1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 ProFUSION embedded systems
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
32 #define TIMEOUT_USEC (10 * USEC_PER_SEC)
34 static bool ignore_proc(pid_t pid) {
35 _cleanup_fclose_ FILE *f = NULL;
41 /* We are PID 1, let's not commit suicide */
45 r = get_process_uid(pid, &uid);
47 return true; /* not really, but better safe than sorry */
49 /* Non-root processes otherwise are always subject to be killed */
53 f = fopen(procfs_file_alloca(pid, "cmdline"), "re");
55 return true; /* not really, but has the desired effect */
57 count = fread(&c, 1, 1, f);
59 /* Kernel threads have an empty cmdline */
63 /* Processes with argv[0][0] = '@' we ignore from the killing
66 * http://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons */
67 if (count == 1 && c == '@')
73 static void wait_for_children(Set *pids, sigset_t *mask) {
78 if (set_isempty(pids))
81 until = now(CLOCK_MONOTONIC) + TIMEOUT_USEC;
89 /* First, let the kernel inform us about killed
90 * children. Most processes will probably be our
91 * children, but some are not (might be our
92 * grandchildren instead...). */
96 pid = waitpid(-1, NULL, WNOHANG);
103 log_error("waitpid() failed: %m");
107 set_remove(pids, ULONG_TO_PTR(pid));
110 /* Now explicitly check who might be remaining, who
111 * might not be our child. */
112 SET_FOREACH(p, pids, i) {
114 /* We misuse getpgid as a check whether a
115 * process still exists. */
116 if (getpgid((pid_t) PTR_TO_ULONG(p)) >= 0)
125 if (set_isempty(pids))
128 n = now(CLOCK_MONOTONIC);
132 timespec_store(&ts, until - n);
133 k = sigtimedwait(mask, NULL, &ts);
136 if (k < 0 && errno != EAGAIN) {
137 log_error("sigtimedwait() failed: %m");
142 log_warning("sigtimedwait() returned unexpected signal.");
147 static int killall(int sig, Set *pids) {
148 _cleanup_closedir_ DIR *dir = NULL;
151 dir = opendir("/proc");
155 while ((d = readdir(dir))) {
158 if (d->d_type != DT_DIR &&
159 d->d_type != DT_UNKNOWN)
162 if (parse_pid(d->d_name, &pid) < 0)
165 if (ignore_proc(pid))
168 if (sig == SIGKILL) {
169 _cleanup_free_ char *s;
171 get_process_comm(pid, &s);
172 log_notice("Sending SIGKILL to PID %lu (%s).", (unsigned long) pid, strna(s));
175 if (kill(pid, sig) >= 0) {
177 set_put(pids, ULONG_TO_PTR((unsigned long) pid));
178 } else if (errno != ENOENT)
179 log_warning("Could not kill %d: %m", pid);
182 return set_size(pids);
185 void broadcast_signal(int sig, bool wait_for_exit) {
186 sigset_t mask, oldmask;
190 pids = set_new(trivial_hash_func, trivial_compare_func);
192 assert_se(sigemptyset(&mask) == 0);
193 assert_se(sigaddset(&mask, SIGCHLD) == 0);
194 assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) == 0);
196 if (kill(-1, SIGSTOP) < 0 && errno != ESRCH)
197 log_warning("kill(-1, SIGSTOP) failed: %m");
201 if (kill(-1, SIGCONT) < 0 && errno != ESRCH)
202 log_warning("kill(-1, SIGCONT) failed: %m");
205 wait_for_children(pids, &mask);
207 assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0);