执行守护程序进程时的Linux / Bash文件描述符

时间:2013-07-02 18:39:16

标签: linux bash daemon file-descriptor io-redirection

我正在为我正在处理的C项目编写服务脚本,并在启动时执行一些实用程序。我想使用日志记录实用程序捕获所有输出。我在/ etc / rc5 / myscript

中有类似的内容
#!/bin/bash    
#save fd 1 in fd 3 for use later
exec 3<&1
$SERVICESCRIPT | logger

记录器只是从stdin读取,直到它达到EOF。第二个脚本是检查一堆实用程序是否正在运行并触发它自己的一些实用程序的地方。在这些实用程序中,有一个分叉并成为守护进程。现在,因为我从脚本运行它,它继承了所有脚本fds。这会导致脚本在调用后永远不会返回命令行。

我试图通过以下几种方式来解决这个问题:

首先,在我的脚本中,我执行了以下操作:

(
exec 4<&-
exec 3<&-
$daemon_process
)

这应该启动一个下标,关闭3和4(分别用于存储stdout和管道输出)并运行程序。但是当我试图回到命令行时我仍然感到困惑,这让我相信管道没有关闭。经过进一步的调查,如果我在收盘后放回一个回音,并将它们重定向到用管道输送到记录仪的fd,我会在日志中看到它们告诉我fd确实仍然是机智的。如果我在c程序中关闭fds 2-4,我会看到它返回命令行,但这是一个非常混乱和令人不快的修复。

其次我尝试了以下内容:

$daemon_process 4<&- 3<&-

应该在调用程序时关闭fds,但是我看到脚本的相同结果永远不会回到命令行。

当脚本出现时我可以“CTRL-C”将它恢复到命令行,但这绝不是一个解决方案。

有什么想法吗?

感谢!!!!

2 个答案:

答案 0 :(得分:0)

由于/etc/rc5/myscript内的任何内容,您的$SERVICESCRIPT未被屏蔽。它正在阻塞,因为它正在等待logger终止,直到写入其STDIN的所有内容都已终止(在这种情况下,这是你的守护进程)。

您可以使用此简化示例查看此行为。考虑这个简单的C程序,孤立自己,然后永远不做任何事情:

#include <stdlib.h>

int main( int argc, char *argv[] ){
        if( fork() ){
                exit( 0 );
        }
        while( 1 ){
                sleep( 1 );
        }
        return EXIT_SUCCESS;
}

这个简单的“记录器”只是从STDIN读取直到EOF:

#include <stdio.h>

int main( int argc, char *argv[] ){
        char c;
        while( 1 ){
                c = getc( stdin );
                if( c == EOF ){
                        break;
                }
        }
        return 0;
}

如果我一起运行这些,我将不会得到我的命令提示符。

$ ./forktest | ./logger
<hangs>

这是因为我的shell正在等待整个管道完成。 forktest“完成”(它自杀)但logger没有完成,这就是我们正在等待的事情。 forktest的孤儿进程正在打开logger的STDIN。您可以通过在上述运行时检查另一个终端中的logger来查看孤立的STDOUT(fd 1)的管道(通知其父进程为1)到/proc/$pid/fd的STDIN(fd 0):

$ ps -ef | grep forktest
cneylan  25451     1  0 16:27 pts/7    00:00:00 ./forktest
$ ps -ef | grep logger
cneylan  25450 24379  0 16:27 pts/7    00:00:00 ./logger
$ ls -l /proc/25451/fd
total 0
lrwx------ 1 cneylan cneylan 64 Jul  2 16:28 0 -> /dev/pts/7
l-wx------ 1 cneylan cneylan 64 Jul  2 16:28 1 -> pipe:[944400]
lrwx------ 1 cneylan cneylan 64 Jul  2 16:28 2 -> /dev/pts/7
lrwx------ 1 cneylan cneylan 64 Jul  2 16:28 3 -> /dev/pts/7
$ ls -l /proc/25450/fd
total 0
lr-x------ 1 cneylan cneylan 64 Jul  2 16:28 0 -> pipe:[944400]
lrwx------ 1 cneylan cneylan 64 Jul  2 16:28 1 -> /dev/pts/7
lrwx------ 1 cneylan cneylan 64 Jul  2 16:28 2 -> /dev/pts/7
lrwx------ 1 cneylan cneylan 64 Jul  2 16:28 3 -> /dev/pts/7

作为旁注,在发生这种情况时执行^ C只会发出logger进程的信号,因为你的守护进程[应该有]调用setsid(2),这是{{3}中的必要步骤之一}}。所以要么^ C杀了你的守护进程你需要让你的代码调用setsid(2)或你的代码已经调用setsid(2)并且你有一堆在后台运行的恶意守护进程:)

答案 1 :(得分:0)

正如您所正确认识的那样,logger的阻塞是它在读取端和(最终)写入端的$daemon_process之间的管道问题。由于您希望将后者的输出写入屏幕,

$daemon_process >/dev/tty

可以解决问题。