1

我很犹豫要不要发布这个问题,因为我认为某个地方已经有人问过了,但是经过大量的搜索,我发现它是空的,所以就在这里。

背景:我正在运行一个本地代理(用 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 并且我想如果所有其他方法都失败了可以使用它,但我很好奇是否有其他类型的解决方法可以做到这一点。

4

1 回答 1

0

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

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

所以,感谢 fork0 提供的那一点知识。

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

我到处寻找与子进程断绝关系的方法,但并没有真正找到任何对我有用的方法(或者不构成对代理的整个重写)。

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

os.execute 不继承父级的 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 上运行。)

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

于 2012-07-27T22:52:21.663 回答