]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/killall.c
shared: add process-util.[ch]
[thirdparty/systemd.git] / src / core / killall.c
CommitLineData
bd3fa1d2
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 ProFUSION embedded systems
7
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.
12
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.
17
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/>.
20***/
21
22#include <sys/wait.h>
23#include <signal.h>
24#include <errno.h>
aaf7eb81 25#include <unistd.h>
bd3fa1d2
LP
26
27#include "util.h"
bd3fa1d2 28#include "killall.h"
aaf7eb81 29#include "set.h"
6482f626 30#include "formats-util.h"
0b452006 31#include "process-util.h"
bd3fa1d2 32
aaf7eb81 33#define TIMEOUT_USEC (10 * USEC_PER_SEC)
bd3fa1d2
LP
34
35static bool ignore_proc(pid_t pid) {
31885cd5 36 _cleanup_fclose_ FILE *f = NULL;
b68fa010
SP
37 char c;
38 const char *p;
bd3fa1d2
LP
39 size_t count;
40 uid_t uid;
41 int r;
42
43 /* We are PID 1, let's not commit suicide */
44 if (pid == 1)
45 return true;
46
47 r = get_process_uid(pid, &uid);
48 if (r < 0)
49 return true; /* not really, but better safe than sorry */
50
51 /* Non-root processes otherwise are always subject to be killed */
52 if (uid != 0)
53 return false;
54
5841bd80
ZJS
55 p = procfs_file_alloca(pid, "cmdline");
56 f = fopen(p, "re");
bd3fa1d2
LP
57 if (!f)
58 return true; /* not really, but has the desired effect */
59
60 count = fread(&c, 1, 1, f);
bd3fa1d2
LP
61
62 /* Kernel threads have an empty cmdline */
63 if (count <= 0)
64 return true;
65
66 /* Processes with argv[0][0] = '@' we ignore from the killing
67 * spree.
68 *
69 * http://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons */
70 if (count == 1 && c == '@')
71 return true;
72
73 return false;
74}
75
aaf7eb81 76static void wait_for_children(Set *pids, sigset_t *mask) {
bd3fa1d2
LP
77 usec_t until;
78
79 assert(mask);
80
aaf7eb81
LP
81 if (set_isempty(pids))
82 return;
83
bd3fa1d2
LP
84 until = now(CLOCK_MONOTONIC) + TIMEOUT_USEC;
85 for (;;) {
86 struct timespec ts;
87 int k;
88 usec_t n;
aaf7eb81
LP
89 void *p;
90 Iterator i;
bd3fa1d2 91
aaf7eb81
LP
92 /* First, let the kernel inform us about killed
93 * children. Most processes will probably be our
94 * children, but some are not (might be our
95 * grandchildren instead...). */
bd3fa1d2 96 for (;;) {
aaf7eb81 97 pid_t pid;
bd3fa1d2 98
aaf7eb81 99 pid = waitpid(-1, NULL, WNOHANG);
bd3fa1d2
LP
100 if (pid == 0)
101 break;
aaf7eb81
LP
102 if (pid < 0) {
103 if (errno == ECHILD)
104 break;
bd3fa1d2 105
56f64d95 106 log_error_errno(errno, "waitpid() failed: %m");
bd3fa1d2 107 return;
aaf7eb81
LP
108 }
109
110 set_remove(pids, ULONG_TO_PTR(pid));
111 }
bd3fa1d2 112
aaf7eb81
LP
113 /* Now explicitly check who might be remaining, who
114 * might not be our child. */
115 SET_FOREACH(p, pids, i) {
116
117 /* We misuse getpgid as a check whether a
118 * process still exists. */
119 if (getpgid((pid_t) PTR_TO_ULONG(p)) >= 0)
120 continue;
121
122 if (errno != ESRCH)
123 continue;
124
125 set_remove(pids, p);
bd3fa1d2
LP
126 }
127
aaf7eb81
LP
128 if (set_isempty(pids))
129 return;
130
bd3fa1d2
LP
131 n = now(CLOCK_MONOTONIC);
132 if (n >= until)
133 return;
134
135 timespec_store(&ts, until - n);
aaf7eb81
LP
136 k = sigtimedwait(mask, NULL, &ts);
137 if (k != SIGCHLD) {
bd3fa1d2
LP
138
139 if (k < 0 && errno != EAGAIN) {
56f64d95 140 log_error_errno(errno, "sigtimedwait() failed: %m");
bd3fa1d2
LP
141 return;
142 }
143
144 if (k >= 0)
145 log_warning("sigtimedwait() returned unexpected signal.");
146 }
147 }
148}
149
0bee65f0 150static int killall(int sig, Set *pids, bool send_sighup) {
aaf7eb81 151 _cleanup_closedir_ DIR *dir = NULL;
bd3fa1d2 152 struct dirent *d;
bd3fa1d2
LP
153
154 dir = opendir("/proc");
155 if (!dir)
156 return -errno;
157
158 while ((d = readdir(dir))) {
159 pid_t pid;
160
161 if (d->d_type != DT_DIR &&
162 d->d_type != DT_UNKNOWN)
163 continue;
164
165 if (parse_pid(d->d_name, &pid) < 0)
166 continue;
167
168 if (ignore_proc(pid))
169 continue;
170
df758e98 171 if (sig == SIGKILL) {
3e09eb5c 172 _cleanup_free_ char *s = NULL;
df758e98
KS
173
174 get_process_comm(pid, &s);
ccd06097 175 log_notice("Sending SIGKILL to PID "PID_FMT" (%s).", pid, strna(s));
df758e98
KS
176 }
177
aaf7eb81
LP
178 if (kill(pid, sig) >= 0) {
179 if (pids)
ccd06097 180 set_put(pids, ULONG_TO_PTR(pid));
aaf7eb81 181 } else if (errno != ENOENT)
56f64d95 182 log_warning_errno(errno, "Could not kill %d: %m", pid);
0bee65f0
LP
183
184 if (send_sighup) {
185 /* Optionally, also send a SIGHUP signal, but
186 only if the process has a controlling
187 tty. This is useful to allow handling of
188 shells which ignore SIGTERM but react to
189 SIGHUP. We do not send this to processes that
190 have no controlling TTY since we don't want to
191 trigger reloads of daemon processes. Also we
192 make sure to only send this after SIGTERM so
193 that SIGTERM is always first in the queue. */
194
195
196 if (get_ctty_devnr(pid, NULL) >= 0)
197 kill(pid, SIGHUP);
198 }
bd3fa1d2
LP
199 }
200
aaf7eb81 201 return set_size(pids);
bd3fa1d2
LP
202}
203
6301a98c 204void broadcast_signal(int sig, bool wait_for_exit, bool send_sighup) {
bd3fa1d2 205 sigset_t mask, oldmask;
e1d75803 206 _cleanup_set_free_ Set *pids = NULL;
aaf7eb81
LP
207
208 if (wait_for_exit)
d5099efc 209 pids = set_new(NULL);
bd3fa1d2
LP
210
211 assert_se(sigemptyset(&mask) == 0);
212 assert_se(sigaddset(&mask, SIGCHLD) == 0);
213 assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) == 0);
214
215 if (kill(-1, SIGSTOP) < 0 && errno != ESRCH)
56f64d95 216 log_warning_errno(errno, "kill(-1, SIGSTOP) failed: %m");
bd3fa1d2 217
0bee65f0 218 killall(sig, pids, send_sighup);
bd3fa1d2
LP
219
220 if (kill(-1, SIGCONT) < 0 && errno != ESRCH)
56f64d95 221 log_warning_errno(errno, "kill(-1, SIGCONT) failed: %m");
bd3fa1d2 222
3d141780 223 if (wait_for_exit)
aaf7eb81
LP
224 wait_for_children(pids, &mask);
225
226 assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0);
bd3fa1d2 227}