X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Fcore%2Fkillall.c;h=c6f1ddfec867fbb80a621e18faf6a7a4faf0cf81;hb=f5b51ea7fcb0b6380c3ceb4d4f3f22f647c6fd32;hp=7f0dbb9edf0823ccd0eb699e5dc44760bff4ac32;hpb=aaf7eb81be912e7bed939f31e3bc4c631b2552b3;p=elogind.git diff --git a/src/core/killall.c b/src/core/killall.c index 7f0dbb9ed..c6f1ddfec 100644 --- a/src/core/killall.c +++ b/src/core/killall.c @@ -25,16 +25,15 @@ #include #include "util.h" -#include "def.h" #include "killall.h" #include "set.h" #define TIMEOUT_USEC (10 * USEC_PER_SEC) static bool ignore_proc(pid_t pid) { - char buf[PATH_MAX]; - FILE *f; + _cleanup_fclose_ FILE *f = NULL; char c; + const char *p; size_t count; uid_t uid; int r; @@ -51,15 +50,12 @@ static bool ignore_proc(pid_t pid) { if (uid != 0) return false; - snprintf(buf, sizeof(buf), "/proc/%lu/cmdline", (unsigned long) pid); - char_array_0(buf); - - f = fopen(buf, "re"); + p = procfs_file_alloca(pid, "cmdline"); + f = fopen(p, "re"); if (!f) return true; /* not really, but has the desired effect */ count = fread(&c, 1, 1, f); - fclose(f); /* Kernel threads have an empty cmdline */ if (count <= 0) @@ -105,7 +101,7 @@ static void wait_for_children(Set *pids, sigset_t *mask) { if (errno == ECHILD) break; - log_error("waitpid() failed: %m"); + log_error_errno(errno, "waitpid() failed: %m"); return; } @@ -139,7 +135,7 @@ static void wait_for_children(Set *pids, sigset_t *mask) { if (k != SIGCHLD) { if (k < 0 && errno != EAGAIN) { - log_error("sigtimedwait() failed: %m"); + log_error_errno(errno, "sigtimedwait() failed: %m"); return; } @@ -149,7 +145,7 @@ static void wait_for_children(Set *pids, sigset_t *mask) { } } -static int killall(int sig, Set *pids) { +static int killall(int sig, Set *pids, bool send_sighup) { _cleanup_closedir_ DIR *dir = NULL; struct dirent *d; @@ -171,45 +167,59 @@ static int killall(int sig, Set *pids) { continue; if (sig == SIGKILL) { - _cleanup_free_ char *s; + _cleanup_free_ char *s = NULL; get_process_comm(pid, &s); - log_notice("Sending SIGKILL to PID %lu (%s).", (unsigned long) pid, strna(s)); + log_notice("Sending SIGKILL to PID "PID_FMT" (%s).", pid, strna(s)); } if (kill(pid, sig) >= 0) { if (pids) - set_put(pids, ULONG_TO_PTR((unsigned long) pid)); + set_put(pids, ULONG_TO_PTR(pid)); } else if (errno != ENOENT) - log_warning("Could not kill %d: %m", pid); + log_warning_errno(errno, "Could not kill %d: %m", pid); + + if (send_sighup) { + /* Optionally, also send a SIGHUP signal, but + only if the process has a controlling + tty. This is useful to allow handling of + shells which ignore SIGTERM but react to + SIGHUP. We do not send this to processes that + have no controlling TTY since we don't want to + trigger reloads of daemon processes. Also we + make sure to only send this after SIGTERM so + that SIGTERM is always first in the queue. */ + + + if (get_ctty_devnr(pid, NULL) >= 0) + kill(pid, SIGHUP); + } } return set_size(pids); } -void broadcast_signal(int sig, bool wait_for_exit) { +void broadcast_signal(int sig, bool wait_for_exit, bool send_sighup) { sigset_t mask, oldmask; - Set *pids; + _cleanup_set_free_ Set *pids = NULL; if (wait_for_exit) - pids = set_new(trivial_hash_func, trivial_compare_func); + pids = set_new(NULL); assert_se(sigemptyset(&mask) == 0); assert_se(sigaddset(&mask, SIGCHLD) == 0); assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) == 0); if (kill(-1, SIGSTOP) < 0 && errno != ESRCH) - log_warning("kill(-1, SIGSTOP) failed: %m"); + log_warning_errno(errno, "kill(-1, SIGSTOP) failed: %m"); - killall(sig, pids); + killall(sig, pids, send_sighup); if (kill(-1, SIGCONT) < 0 && errno != ESRCH) - log_warning("kill(-1, SIGCONT) failed: %m"); + log_warning_errno(errno, "kill(-1, SIGCONT) failed: %m"); if (wait_for_exit) wait_for_children(pids, &mask); assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0); - - set_free(pids); }