未接收使用sudo执行的进程的SIGCHLD

未接收使用sudo执行的进程的SIGCHLD,c,shell,exec,sudo,sigchld,C,Shell,Exec,Sudo,Sigchld,我目前正在写一个shell。我执行进程,并利用SIGCHLD信号处理程序在进程完成时进行清理(等待) 一切都在运行——除了我执行使用sudo升级权限的进程。在这些情况下,我从未得到一个SIGCHLD信号——因此我永远不知道进程已经完成执行 当我收到诸如sudo ls之类的命令时,我执行程序sudo,然后将ls作为参数提供。我使用execvp执行此执行 如果我在shell执行了sudo ls之后查看一下ps-aux,我会看到以下内容: root 4795 0.0 0.0 4496

我目前正在写一个shell。我执行进程,并利用
SIGCHLD
信号处理程序在进程完成时进行清理(等待)

一切都在运行——除了我执行使用
sudo
升级权限的进程。在这些情况下,我从未得到一个
SIGCHLD
信号——因此我永远不知道进程已经完成执行

当我收到诸如
sudo ls
之类的命令时,我执行程序
sudo
,然后将
ls
作为参数提供。我使用
execvp
执行此执行

如果我在shell执行了sudo ls之后查看一下ps-aux,我会看到以下内容:

root      4795  0.0  0.0   4496  1160 pts/29   S+   16:51   0:00 sudo ls
root      4796  0.0  0.0      0     0 pts/29   Z+   16:51   0:00 [ls] <defunct>
root 4795 0.0 0.0 4496 1160 pts/29 S+16:51 0:00 sudo ls
根4796 0.0.0 pts/29 Z+16:51 0:00[ls]
因此,
sudo
运行并被分配
pid=4795
,子对象(ls)被分配
4796
。孩子已经完成了任务,现在处于僵尸状态
sudo
似乎不想收获僵尸进程,只是坐在那里

我想知道是什么导致了这种行为——我尝试了不同的技术来清理这些僵尸进程,比如在
sudo
下运行shell,直接等待
sudo
sudo
执行的
PID
(上例中为4796)。这些技术都不起作用


和往常一样,任何建议都是值得赞赏的。

我的第一个想法是错误的信号处理,但您的帖子中没有足够的信息来编写测试代码来复制您的失败。但我可以给你一些地方看看。请原谅,如果我为将来的读者介绍一些你们已经知道的信号基础知识

首先,我不知道您是在使用传统的signal()还是新的POSIX sigaction()信号例程来捕获信号。sigset()是来自GNU的一个有用的中间变量

遗留信号--signal()
如果不是不可能的话,几乎不可能保证在所有环境中使用原始信号处理器的气密信号处理器

  • 在某些UNIX系统上,输入信号处理程序可以将处理程序重置为默认条件。除非处理程序显式重置信号,否则后续信号将保证丢失。
  • signal()处理程序不能假设每个信号调用一次。
    • 处理程序必须执行
      while((pid=waitpid(-1,&signal,WNOHANG))>0)
      循环, 直到没有发现更多信号作为遗留信号,否则将设置布尔条件 表示至少有一个信号未完成。 实际计数未知。
    • 如果处理了先前的while()循环,则处理程序必须允许找不到任何信号 信号。
  • 允许来自未知进程的信号。。。如果你启动的程序也启动了 孙子进程如果您的孩子很快退出,您可能会继承该进程。
建议,保持冷静,避开遗留信号

遗留处理程序中缺少while()循环和多个sigchild,一个来自sudo,一个或多个来自sudo激发的意外孙子。如果在孙子信号首先传入时只处理一个SIGCHILD,则预期程序的信号将不会被捕获

POSIX信号--sigaction()
POSIX信号可以清除遗留信号的所有故障

  • 设置一个处理程序,无需还原(还原不是POSIX信号的一部分,通常是, 至少在我看来,当你可能得到多个信号以同样的方式处理时是邪恶的)。
  • sigaction()信号是粘性的。。。他们一直活着,直到有了明确的改变(太棒了!)。 所有这些都不需要重新设置信号处理程序 在处理程序中。
  • 在处理信号时,设置遮罩以屏蔽当前信号。偏执狂还会掩盖传递给同一处理程序的任何其他信号。
如果在SIGCHILD处理程序中得到SIGCHILD,缺少掩码可能会导致奇怪的事情,比如失去信号的跟踪

GNU--sigset()
GNU提供了一个有用的中间接口,它具有与signal()相同的调用签名,但消除了大多数问题。还提供了一些附加的控制功能。使用sigset()可以轻松解决许多信号问题

提醒
将信号处理程序视为程序中的线程, 即使代码中没有使用线程。 在过去的日子里,您需要在信号处理程序中进行绝对最小的处理。。。不调用库代码, 例如printf,有副作用。
在必须使用旧的信号处理程序时,我仍然遵循这一点,并且在较新的处理程序中始终使用多线程警告。

我建议在由shell运行和由标准系统shell运行时,检查
strace(1)
sudo(8)的输出。由于跟踪会影响可执行文件上的setuid权限,所以需要在
sudo
启动后但在它完成大量工作之前附加
strace
sudo-k
首先将强制
sudo
重新提示输入密码,当它等待时,您可以找到它的pid并运行
strace-o/tmp/out-f-p
。这在其他shell下也会发生吗?@bdonlan,通过其他shell,您的意思是如果我通过bash运行
sudo vi
?它并没有发生在那个里。你们可以试着阅读bash(或其他shell)的源代码,看看它有什么不同的地方/sudo有一些特殊的行为。此外,如果sudo更改了用户id,这是否会阻止您的流程使用sudo“执行工作人员”请求:向我们显示再现问题的最小可编译代码,并告诉我们sudo的版本,因为存在问题。问:当你执行时,你是否阻止了SIGCHLD<代码>sudo并不完全依赖CHLD,IIRC,但这肯定不会有什么帮助