From 9c9fe51eeec96941a487f6f34e8478d380e43b39 Mon Sep 17 00:00:00 2001 From: Joachim Nilsson Date: Sun, 23 Oct 2016 00:28:41 +0200 Subject: [PATCH] Fine grained signaling of processes at shutdown This patch replaces kill(-1, signo) with a more fine grained do_kill(signo) that traverses each /proc/PID, skipping kernel threads and special [0][0] == '@' processes. The reason for this patch is not only future compliance with freedesktop.org standards, but also a way of not killing any critical processes at shutdown, e.g. mdadm or watchdogd. Signed-off-by: Joachim Nilsson --- sig.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 48 insertions(+), 8 deletions(-) diff --git a/sig.c b/sig.c index 65fce4c6..0fab0e97 100644 --- a/sig.c +++ b/sig.c @@ -64,6 +64,7 @@ * Finit currently forwards this to SIGUSR2. */ +#include #include #include /* strerror() */ #include @@ -97,6 +98,47 @@ void mdadm_wait(void); void unmount_tmpfs(void); void unmount_regular(void); +/* + * Kernel threads have no cmdline so fgets() returns NULL for them. We + * also skip "special" processes, e.g. mdadm/mdmon or watchdogd that must + * not be stopped here, for various reasons. + * + * https://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons/ + */ +void do_kill(int signo) +{ + DIR *dirp; + + dirp = opendir("/proc"); + if (dirp) { + struct dirent *d; + + while ((d = readdir(dirp))) { + int pid; + FILE *fp; + char file[80] = ""; + + if (d->d_type != DT_DIR) + continue; + + pid = atoi(d->d_name); + if (!pid) + continue; + + snprintf(file, sizeof(file), "/proc/%s/cmdline", d->d_name); + fp = fopen(file, "r"); + if (!fp) + continue; + + if (fgets(file, sizeof(file), fp)) { + if (file[0] != '@') + kill(pid, signo); + } + fclose(fp); + } + closedir(dirp); + } +} void do_shutdown(shutop_t op) { @@ -117,15 +159,13 @@ void do_shutdown(shutop_t op) /* Update UTMP db */ utmp_set_halt(); - /* Here is where we signal watchdogd to do a forced reset for us */ - _d("Sending SIGTERM to all processes"); - kill(-1, SIGTERM); - - /* Wait for WDT to timeout, should be no more than ~1 sec. */ + /* + * Tell all remaining non-monitored processes to exit, give them + * some time to exit gracefully, 2 sec is customary. + */ + do_kill(SIGTERM); do_sleep(2); - - _d("Sending SIGKILL to remaining processes"); - kill(-1, SIGKILL); + do_kill(SIGKILL); /* Exit plugins and API gracefully */ plugin_exit();