3

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

#!/bin/bash    
#save fd 1 in fd 3 for use later
exec 3<&1
$SERVICESCRIPT | logger

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

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

首先,在启动守护进程的脚本中,我执行了以下操作:

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

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

其次,我尝试了以下方法:

$daemon_process 4<&- 3<&-

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

当脚本交给我时,我可以“CTRL-C”让它回到命令行,但这绝不是一个解决方案。

有任何想法吗?

谢谢!!!!

4

2 回答 2

0

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

$daemon_process >/dev/tty

将解决问题。

于 2013-09-17T11:21:39.600 回答
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. 通过在上述运行时logger签入另一个终端,您可以看到来自孤儿的 STDOUT (fd 1) 的管道(注意其父进程是 1)进入 STDIN (fd 0) :/proc/$pid/fd

$ 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)的必要步骤之一。所以要么 ^C 正在杀死你的守护进程,你需要调用你的代码,或者你的代码已经调用,并且你有一堆流氓守护进程在后台运行:)setsid(2)setsid(2)

于 2013-07-02T20:51:34.247 回答