繁体   English   中英

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

[英]Linux/Bash file descriptors when executing a daemon process

我正在为我正在处理的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”将它恢复到命令行,但这绝不是一个解决方案。

有任何想法吗?

谢谢!!!!

你的/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 “完成”(它forktest )但logger器没有完成,这就是我们正在等待的东西。 forktest的孤儿进程持有打开logger的STDIN。 您可以通过在上述运行时检查另一个终端中的/proc/$pid/fd来查看孤儿的STDOUT(fd 1)中的管道(通知其父进程为1)进入logger的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) ,这是守护进程本身的必要步骤之一。 所以^ C正在杀死你的守护进程你需要让你的代码调用setsid(2)或你的代码已经调用setsid(2)并且你有一堆在后台运行的流氓守护进程:)

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

$daemon_process >/dev/tty

会解决问题。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM