在测试OpenSUSE中遗留程序更新的兼容性时,我将问题追溯到一个奇怪的版本差异。下面的C程序在sudo中创建一个子进程,然后在sudo中杀死这个进程:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main (int argc, char *argv[])
{
char execName[80] = "/usr/bin/sudo";
char cmd[128];
int pid = 0;
int SIG = 15;
if (argc > 1) SIG = atoi(argv[1]);
printf("Sudo sleeping for 30 seconds.\n");
printf("Sudo killing with signal %d.\n", SIG);
printf("Use `ps aux | grep sleep` within 30 seconds to verify it was killed. Only this grep should show.\n");
if ((pid = vfork()) == 0) {
execl (execName, execName, "/bin/sleep", "30", (char *)NULL);
perror(execName);
exit (-1);
} else {
if (pid == -1) perror("Bad PID for sleeper");
fprintf( stderr, "sleeper process PID = %d\n", pid );
}
sprintf(cmd, "/usr/bin/sudo kill -%d %d", SIG, pid);
system(cmd);
}
为了执行这段代码,用户需要访问sudo
,sudoers
需要访问kill
。这准确地表示了遗留程序是如何工作的,除了睡眠程序是一个连续运行的过程,并且中间有更多的步骤。不幸的是,完全放弃这个计划是不现实的。
在OpenSUSE 13.2中,这个程序成功地杀死了睡眠者。但是,在OpenSUSE 42.3中,仍然保留了睡眠者。为什么?我如何重写它,以便我可以给予我自己的OpenSUSE 42. 3中的sudo子级一个kill信号?
作为实验,我将最后一个系统调用更改为/usr/bin/sudo pkill -15 -P %d
,其中%d
是进程ID。出于某种原因,这在不同版本中都有效,尽管并不可靠。我所拥有的关于为什么这些不同的理论都不能充分解释为什么 * 这 * 有效。
1条答案
按热度按时间gfttwv5a1#
睡眠进程是
sudo
的子进程。您只会终止sudo
进程,而不会终止其子进程。您可以通过取消进程组前导的PID来终止整个进程组。只要
sudo
不为子进程创建新的进程组(这似乎不太可能),这就可以工作。此外,如果
fork()
返回-1
,则应在打印错误消息后退出。通常的结构看起来像这样: