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 <troglobit@gmail.com>
This commit is contained in:
Joachim Nilsson
2016-10-23 00:28:41 +02:00
parent 4f8211f6a1
commit 9c9fe51eee
+48 -8
View File
@@ -64,6 +64,7 @@
* Finit currently forwards this to SIGUSR2.
*/
#include <dirent.h>
#include <sched.h>
#include <string.h> /* strerror() */
#include <sys/reboot.h>
@@ -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();