Daemonize /后台通过另一个程序的脚本启动的过程

时间:2012-07-26 20:22:01

标签: c perl bash daemon background-process

我对发布这个问题犹豫不决,因为我假设某个人已经问过这个问题,但经过多次淘汰后,我已经空了,所以就在这里。

背景:我正在运行本地代理(用C语言编写,通过TCP监听),允许远程执行少量脚本/命令。 (通过Web界面,具体而言。)脚本本身是二进制文件,bash或perl脚本的混合体,只要代理本身在列表中被允许,代理本身并不在意。

(这是在公司内部网络,这是在很早的阶段,所以请不要在此时讨论安全的优点。)

启动流程的C代理代码如下:

sprintf(mrun, "%s %s 2>&1", file, args);
mexec = popen(mrun, "r");
[read some returned buffer]
pclose(mexec);

这种方法适用于外部bash和perl脚本,前提是脚本只执行命令(或在前台执行操作)。但是,我最近需要扩展一个脚本以包含一个守护进程的重启,在这种情况下命名为。

脚本本身(bash)很简单:

#!/bin/bash
pkill -9 named
/local/mnt/named/sbin/named -c /local/mnt/named/var/named.conf &
echo "restarted"

我遇到的问题是,当通过C代理程序运行时,脚本永远不会完成(即重新启动永远不会回显),因此永远不会返回控件,并且TCP套接字永远不会被释放。就代理而言,该过程仍在运行。如果我从终端运行脚本,它工作正常,控制权返回给我。

我是否遗漏了一些允许脚本在从C守护程序分离而不是从bash终端调用时正常执行的内容?

我知道nohup,如果其他所有方法都失败了,我想可以使用它,但我很好奇是否还有其他类型的解决方法。

1 个答案:

答案 0 :(得分:0)

根据上述评论的反馈,我可以在启动守护程序进程后让脚本继续工作,这要归功于一些额外的重定向:

/local/mnt/named/sbin/named -c /local/mnt/named/var/named.conf </dev/null &> /dev/null &

所以,感谢fork0获得了一点知识。

之后,我注意到即使脚本完成了工作,TCP套接字连接也无法正常关闭。在下面的一些更多信息并进行大量研究之后,事实证明子进程将从父进程(包括套接字)继承(并保持打开)文件描述符。

我全神贯注地查看了拒绝子进程的方法,但没有找到任何对我有用的方法(或者不构成对代理的全部重写)。

最后,我偶然发现了这个问题,这个问题与我使用的编程语言有关但不相关:

os.execute without inheriting parent's fds

这基本上涉及子进程关闭代码中的任何打开的文件描述符,从而释放它们被父进程关闭。 (我想?)

我在bash脚本中添加了几行来执行此操作,然后才开始命名,它确实有效。

for i in `nawk 'BEGIN{ for(i=1;i<=255;i++) print i}'`
do
eval exec `echo $i | sed -e 's/.*/&<\&-/'`
done

(我希望使用nawk而不是seq,因为我需要它在Solaris和Linux上运行。)

一些基本的测试表明,这已经解决了套接字无法关闭的主要问题,但我需要做更多的研究,看看这是否会产生任何其他我不知道的后果。可能还有一种更好,更安全的方法来实现这一目标,但至少我走在正确的轨道上。