Почему это убийство не работает в этом скрипте Bash, а только вне скрипта? - PullRequest
0 голосов
/ 03 июля 2018

Ниже приведен надуманный пример, который демонстрирует эффект и должен запускаться с правами root. Он выполняет процесс ping в фоновом режиме и пытается убить его.

#!/bin/bash

# Ensure that there is no ping process before we begin.
killall ping

sudo ping google.com > /dev/null &
PID=$!

sleep 0.5

kill $PID
echo "Exit code of kill $PID: $?"

# Check the running ping processes. There should be no ping
# process if the above `kill $PID` worked correctly.
ps aux | grep -v grep | grep ping

Однако сценарий не может завершить процесс, даже если код возврата kill равен 0. Ниже приведен пример вывода.

$ bash test.sh
Exit code of kill 16516: 0
root     16516  0.0  0.0  14956  2212 pts/2    S    13:22   0:00 sudo ping google.com
root     16518  1.0  0.0  13112  1292 pts/2    S    13:22   0:00 ping google.com

Я заметил, что если я достану sudo, то это правильно убивает его. Почему это происходит? Я подозреваю, что дочерний процесс sudo как-то все портит.

Обновление 1:

Еще более странно. Если я выполню ту же команду kill после сценария, она будет работать.

$ bash test.sh
Exit code of kill 16631: 0
root     16631  3.0  0.0  14956  2212 pts/2    S    13:29   0:00 sudo ping google.com
root     16633  0.0  0.0  13112  1292 pts/2    S    13:29   0:00 ping google.com
$ ps aux | grep -v grep | grep ping
root     16631  0.5  0.0  14956  2212 pts/2    S    13:29   0:00 sudo ping google.com
root     16633  0.0  0.0  13112  1292 pts/2    S    13:29   0:00 ping google.com
$ kill 16631
$ ps aux | grep -v grep | grep ping
$
$ kill 16631
-bash: kill: (16631) - No such process
$

1 Ответ

0 голосов
/ 04 июля 2018

Это происходит потому, что управляющий процесс sudo не передает сигналы, поступающие из его собственной группы процессов ( source ):

/*
 * 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.
 */
if (USER_SIGNALED(sc->siginfo) && sc->siginfo->si_pid != 0) {
    pid_t si_pgrp = getpgid(sc->siginfo->si_pid);
    if (si_pgrp != -1) {
    if (si_pgrp == ec->ppgrp || si_pgrp == ec->cmnd_pid)
        debug_return;
    } else if (sc->siginfo->si_pid == ec->cmnd_pid) {
        debug_return;
    }
}

Когда вы выполняете команду вне сценария, вы запускаете ее в отдельной группе процессов, поэтому сигнал передается.

...