在带有 busybox 的嵌入式 linux 上使用 system() 时,SIGHUP 信号处理程序重置为默认值

SIGHUP signal handler reset to default when using system() on embedded linux with busybox

我正在使用 busybox 开发嵌入式 linux。作为我的应用程序的一部分,我有一个 rc.init 脚本 E80-startmyprog。该脚本正在调用我的程序 prog.

trap "" HUP
startmyprog >${LOGFILE} 2>&1 </dev/null &

startmyprog() {
  prog
}

在我的程序中,我可以看到信号处理程序设置为忽略 SIGHUP。我正在检查

struct sigaction act;
sigaction(1, NULL, &act);
printf("action %p\n", act.sa_sigaction);  // prints out 1 -> SIG_IGN

现在在我的程序中的某个时间我需要启动另一个进程,给它一些输入并检查它是否在 stdout 上打印 "yes"。我正在使用系统来做到这一点。

const int ret = system("[ `echo input | second_process` == yes ]");

正常行为是 WIFEXITED(ret) 为真,WEXITSTATUS(ret) 为 0 或 1。

但在某些情况下,不幸的是,WIFSIGNALED(ret) 为真,WTERMSIG(ret) 为 1(SIGHUP)。

调试表明,如果我 execl("second_process", "second_process", (char*)NULL) second_process 中的信号处理程序状态被正确设置为 SIGHUP=ignore。但是如果我使用 system,那么 second_process 有 SIGHUP=default.

我的问题是:

那里发生了什么事?谁在启动时重置 SIGHUP 信号处理程序?是 shell 吗?有没有办法防止这种情况发生? (在 sh 手册页中,我还没有看到这样的命令行选项。)

我知道我可以做一个解决方法并设置管道、fork、exec second_process、将输入写入管道、从管道读取输出并解析输出,但与系统相比,这是很多东西一个班轮,我很有可能会错过一些东西并弄错。

我不认为这正是正在发生的事情。当您在 shell 中键入 'trap' 时,您要求它列出为该信号建立的操作。当你调用一个 subshell 时,你没有给它任何动作,所以它不会显示任何(它不知道你给了它的父级什么)但这并不意味着它已经重置SIGHUP 状态。

试试这个证明 SIGHUP 仍然被忽略的小脚本,即使 "trap" 什么也没显示:

trap "" HUP
echo "TRAPs in parent"
trap
sh -c 'echo "TRAPs in child"; trap; sleep 5; echo "Still here. Traps: "; trap' &
child=$!
sleep 1
kill -HUP $child
echo 'Killed child'

深入研究 Linux 上的 运行 busybox 的源代码,我发现 busybox 中的 shell 在初始化期间调用 signal(SIGHUP, SIG_DFL);。这会将 sighup 处理程序重置为默认值。所以 shell 本身和它运行的程序(由 -c ... 提供)是 运行 默认的 SIGHUP 处理程序。

我没有看到绕过重置 SIGHUP 信号处理程序的代码路径,所以我似乎无法通过 system() 实现我想要的。