我试图弄清楚为什么这不起作用:
#!/bin/bash
sudo sleep 60 &
sudo_pid=$!
sudo kill $sudo_pid
我希望在kill
之后,sudo
命令及其子sleep
进程将被终止,但它们不会被终止,如此所示脚本:
#!/bin/bash
sudo sleep 60 &
sudo_pid=$!
sudo kill $sudo_pid
if ps -p $sudo_pid > /dev/null; then
sudo kill $sudo_pid
else
echo "No sudo process running"
exit 1
fi
if ps -p $sudo_pid > /dev/null; then
echo "sudo (pid $sudo_pid) is still running"
ps -F $sudo_pid
else
echo "sudo successfully killed"
fi
当我运行它时会产生此输出(缓存sudo
个信用卡):
jon@ubuntu:~$ ./so.sh
sudo (pid 46199) is still running
UID PID PPID C SZ RSS PSR STIME TTY STAT TIME CMD
root 46199 46198 0 14764 3984 3 13:37 pts/0 S+ 0:00 sudo sleep 60
脚本完成后(并且sudo sleep 60
仍在运行), 可以使用相同的命令将其终止:
jon@ubuntu:~$ ps -F 46199
UID PID PPID C SZ RSS PSR STIME TTY STAT TIME CMD
root 46199 1 0 14764 3984 3 13:37 pts/0 S 0:00 sudo sleep 60
jon@ubuntu:~$ sudo kill 46199
jon@ubuntu:~$ ps -F 46199
UID PID PPID C SZ RSS PSR STIME TTY STAT TIME CMD
jon@ubuntu:~$
我注意到so.sh
脚本退出后,sudo sleep 60
的父进程ID已从脚本更改为init
进程,我认为这很重要。在sudo sleep 60
脚本仍在运行时,也可以从其他shell成功终止so.sh
进程。
我还注意到在脚本中使用sudo kill -ABRT
(而不是kill
的默认SIGTERM
)会成功终止sudo
进程,所以我假设这与sudo
处理SIGTERM
的方式有关。但是,根据手册页,我认为它不应该做任何特别的事情:
Signal handling
When the command is run as a child of the sudo process, sudo will relay
signals it receives to the command. The SIGINT and SIGQUIT signals are
only relayed when the command is being run in a new pty or when the sig‐
nal was sent by a user process, not the kernel. This prevents the com‐
mand from receiving SIGINT twice each time the user enters control-C.
手册页中提到的SIGTERM
的唯一特殊处理是signals that were sent by the command it is running
;不是这里的情况。此外,我将上面脚本中的ps -F
更改为ps -o blocked,caught,ignored,pending
并输出
sudo (pid 46429) is still running
BLOCKED CAUGHT IGNORED PENDING
0000000000000000 00000001800b7a07 0000000000000000 0000000000000000
这似乎表明SIGTERM没有被阻止或忽略,那么为什么sudo sleep 60
进程没有被终止?
我提出了几个解决方法(setsid
,sudo -b
,杀死了孩子sleep
进程而不是父sudo
进程),所以我&# 39;我不寻找替代方法的答案。我只是想了解这里发生了什么。
如果重要:
jon@ubuntu:~$ uname -a
Linux ubuntu 4.13.0-16-generic #19-Ubuntu SMP Wed Oct 11 18:35:14 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
jon@ubuntu:~$ sudo --version
Sudo version 1.8.20p2
Sudoers policy plugin version 1.8.20p2
Sudoers file grammar version 46
Sudoers I/O plugin version 1.8.20p2
答案 0 :(得分:1)
任何给定信号的信号屏蔽位为:
(1ULL << ((signal_number) - 1))
(无论如何,对于1-32范围内的标准信号;附加信号在“实时”信号集中并且处理方式稍有不同,但适用相同的概念)。所以CAUGHT
蒙版的有趣部分是:
...7a07
是(+对于捕获, - 对于未捕获,在扩展部分中):
xxx7: signals 1, 2, 3, but not 4: +SIGHUP +SIGINT +SIGQUIT -SIGILL
xx0x: not 5-8: -SIGTRAP -SIGABRT -SIGBUS -SIGFPE
xaxx: not 9, 10, not 11, 12: -SIGKILL +SIGUSR1 -SIGSEGV +SIGUSR2
7xxx: 13, 14, 15, not 16: +SIGPIPE +SIGALRM +SIGTERM -SIGSTKFLT
(如果您愿意,可以继续解码其余部分;有关特定于Linux的信号编号,请参阅/usr/include/asm-generic/signal.h
;请注意,OSX和BSD上的数字定义不同但技术相同:捕获或阻止或其他信号在掩码中表示为1位。
因此,这意味着sudo
正在抓住SIGTERM
但却没有抓住SIGABRT
。 SIGTERM
未传递的事实必须与sudo
代码本身有关。源代码(apt-get source sudo
)有一些相当复杂的代码用于执行信号处理,包括一些有趣的调试技巧,你可以在sudo配置文件中打开它们来帮助你追踪正在发生的事情。
答案 1 :(得分:0)
我在sudo的源代码中发现以下注释
/*
* Do not forward signals sent by a process in the command's process
* group, as we don't want the command to indirectly kill itself.
* For example, this can happen with some versions of reboot that
* call kill(-1, SIGTERM) to kill all other processes.
*/