]>
Commit | Line | Data |
---|---|---|
a032b68d | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
663996b3 | 2 | /*** |
b012e921 | 3 | Copyright © 2010 ProFUSION embedded systems |
663996b3 MS |
4 | ***/ |
5 | ||
663996b3 | 6 | #include <errno.h> |
db2df898 MP |
7 | #include <signal.h> |
8 | #include <sys/wait.h> | |
663996b3 MS |
9 | #include <unistd.h> |
10 | ||
db2df898 | 11 | #include "alloc-util.h" |
5a920b42 | 12 | #include "def.h" |
2897b343 | 13 | #include "dirent-util.h" |
db2df898 | 14 | #include "fd-util.h" |
2897b343 | 15 | #include "format-util.h" |
db2df898 MP |
16 | #include "killall.h" |
17 | #include "parse-util.h" | |
e3bff60a | 18 | #include "process-util.h" |
db2df898 | 19 | #include "set.h" |
ea0999c9 | 20 | #include "stdio-util.h" |
db2df898 | 21 | #include "string-util.h" |
e3bff60a | 22 | #include "terminal-util.h" |
db2df898 | 23 | #include "util.h" |
663996b3 | 24 | |
4c89c718 | 25 | static bool ignore_proc(pid_t pid, bool warn_rootfs) { |
663996b3 | 26 | _cleanup_fclose_ FILE *f = NULL; |
60f067b4 | 27 | const char *p; |
6e866b33 | 28 | char c = 0; |
663996b3 MS |
29 | uid_t uid; |
30 | int r; | |
31 | ||
32 | /* We are PID 1, let's not commit suicide */ | |
6e866b33 | 33 | if (pid <= 1) |
663996b3 MS |
34 | return true; |
35 | ||
6e866b33 MB |
36 | /* Ignore kernel threads */ |
37 | r = is_kernel_thread(pid); | |
38 | if (r != 0) | |
39 | return true; /* also ignore processes where we can't determine this */ | |
40 | ||
663996b3 MS |
41 | r = get_process_uid(pid, &uid); |
42 | if (r < 0) | |
43 | return true; /* not really, but better safe than sorry */ | |
44 | ||
45 | /* Non-root processes otherwise are always subject to be killed */ | |
46 | if (uid != 0) | |
47 | return false; | |
48 | ||
14228c0d MB |
49 | p = procfs_file_alloca(pid, "cmdline"); |
50 | f = fopen(p, "re"); | |
663996b3 MS |
51 | if (!f) |
52 | return true; /* not really, but has the desired effect */ | |
53 | ||
6e866b33 MB |
54 | /* Try to read the first character of the command line. If the cmdline is empty (which might be the case for |
55 | * kernel threads but potentially also other stuff), this line won't do anything, but we don't care much, as | |
56 | * actual kernel threads are already filtered out above. */ | |
57 | (void) fread(&c, 1, 1, f); | |
663996b3 | 58 | |
2897b343 | 59 | /* Processes with argv[0][0] = '@' we ignore from the killing spree. |
663996b3 | 60 | * |
46cdbd49 | 61 | * https://systemd.io/ROOT_STORAGE_DAEMONS */ |
2897b343 MP |
62 | if (c != '@') |
63 | return false; | |
4c89c718 | 64 | |
2897b343 MP |
65 | if (warn_rootfs && |
66 | pid_from_same_root_fs(pid) == 0) { | |
67 | ||
68 | _cleanup_free_ char *comm = NULL; | |
4c89c718 | 69 | |
6e866b33 | 70 | (void) get_process_comm(pid, &comm); |
4c89c718 | 71 | |
2897b343 MP |
72 | log_notice("Process " PID_FMT " (%s) has been marked to be excluded from killing. It is " |
73 | "running from the root file system, and thus likely to block re-mounting of the " | |
74 | "root file system to read-only. Please consider moving it into an initrd file " | |
75 | "system instead.", pid, strna(comm)); | |
76 | } | |
663996b3 | 77 | |
2897b343 | 78 | return true; |
663996b3 MS |
79 | } |
80 | ||
f2dec872 BR |
81 | static void log_children_no_yet_killed(Set *pids) { |
82 | _cleanup_free_ char *lst_child = NULL; | |
f2dec872 | 83 | void *p; |
9cde670f | 84 | int r; |
f2dec872 | 85 | |
a032b68d | 86 | SET_FOREACH(p, pids) { |
f2dec872 | 87 | _cleanup_free_ char *s = NULL; |
f2dec872 | 88 | |
9cde670f LB |
89 | if (get_process_comm(PTR_TO_PID(p), &s) >= 0) |
90 | r = strextendf(&lst_child, ", " PID_FMT " (%s)", PTR_TO_PID(p), s); | |
91 | else | |
92 | r = strextendf(&lst_child, ", " PID_FMT, PTR_TO_PID(p)); | |
93 | if (r < 0) | |
ea0999c9 | 94 | return (void) log_oom(); |
f2dec872 BR |
95 | } |
96 | ||
97 | if (isempty(lst_child)) | |
98 | return; | |
99 | ||
100 | log_warning("Waiting for process: %s", lst_child + 2); | |
101 | } | |
102 | ||
103 | static int wait_for_children(Set *pids, sigset_t *mask, usec_t timeout) { | |
104 | usec_t until, date_log_child, n; | |
663996b3 MS |
105 | |
106 | assert(mask); | |
107 | ||
f2dec872 BR |
108 | /* Return the number of children remaining in the pids set: That correspond to the number |
109 | * of processes still "alive" after the timeout */ | |
110 | ||
663996b3 | 111 | if (set_isempty(pids)) |
f2dec872 BR |
112 | return 0; |
113 | ||
114 | n = now(CLOCK_MONOTONIC); | |
115 | until = usec_add(n, timeout); | |
116 | date_log_child = usec_add(n, 10u * USEC_PER_SEC); | |
117 | if (date_log_child > until) | |
118 | date_log_child = usec_add(n, timeout / 2u); | |
663996b3 | 119 | |
663996b3 MS |
120 | for (;;) { |
121 | struct timespec ts; | |
122 | int k; | |
663996b3 | 123 | void *p; |
663996b3 MS |
124 | |
125 | /* First, let the kernel inform us about killed | |
126 | * children. Most processes will probably be our | |
127 | * children, but some are not (might be our | |
128 | * grandchildren instead...). */ | |
129 | for (;;) { | |
130 | pid_t pid; | |
131 | ||
132 | pid = waitpid(-1, NULL, WNOHANG); | |
133 | if (pid == 0) | |
134 | break; | |
135 | if (pid < 0) { | |
136 | if (errno == ECHILD) | |
137 | break; | |
138 | ||
f2dec872 | 139 | return log_error_errno(errno, "waitpid() failed: %m"); |
663996b3 MS |
140 | } |
141 | ||
d9dfd233 | 142 | (void) set_remove(pids, PID_TO_PTR(pid)); |
663996b3 MS |
143 | } |
144 | ||
145 | /* Now explicitly check who might be remaining, who | |
146 | * might not be our child. */ | |
a032b68d | 147 | SET_FOREACH(p, pids) { |
663996b3 | 148 | |
52ad194e MB |
149 | /* kill(pid, 0) sends no signal, but it tells |
150 | * us whether the process still exists. */ | |
151 | if (kill(PTR_TO_PID(p), 0) == 0) | |
663996b3 MS |
152 | continue; |
153 | ||
154 | if (errno != ESRCH) | |
155 | continue; | |
156 | ||
157 | set_remove(pids, p); | |
158 | } | |
159 | ||
160 | if (set_isempty(pids)) | |
f2dec872 | 161 | return 0; |
663996b3 MS |
162 | |
163 | n = now(CLOCK_MONOTONIC); | |
f2dec872 BR |
164 | if (date_log_child > 0 && n >= date_log_child) { |
165 | log_children_no_yet_killed(pids); | |
166 | /* Log the children not yet killed only once */ | |
167 | date_log_child = 0; | |
168 | } | |
169 | ||
663996b3 | 170 | if (n >= until) |
f2dec872 BR |
171 | return set_size(pids); |
172 | ||
173 | if (date_log_child > 0) | |
174 | timespec_store(&ts, MIN(until - n, date_log_child - n)); | |
175 | else | |
176 | timespec_store(&ts, until - n); | |
663996b3 | 177 | |
663996b3 MS |
178 | k = sigtimedwait(mask, NULL, &ts); |
179 | if (k != SIGCHLD) { | |
180 | ||
f2dec872 BR |
181 | if (k < 0 && errno != EAGAIN) |
182 | return log_error_errno(errno, "sigtimedwait() failed: %m"); | |
663996b3 MS |
183 | |
184 | if (k >= 0) | |
185 | log_warning("sigtimedwait() returned unexpected signal."); | |
186 | } | |
187 | } | |
188 | } | |
189 | ||
60f067b4 | 190 | static int killall(int sig, Set *pids, bool send_sighup) { |
663996b3 | 191 | _cleanup_closedir_ DIR *dir = NULL; |
f2dec872 BR |
192 | int n_killed = 0; |
193 | ||
194 | /* Send the specified signal to all remaining processes, if not excluded by ignore_proc(). | |
195 | * Returns the number of processes to which the specified signal was sent */ | |
663996b3 MS |
196 | |
197 | dir = opendir("/proc"); | |
198 | if (!dir) | |
f2dec872 | 199 | return log_warning_errno(errno, "opendir(/proc) failed: %m"); |
663996b3 | 200 | |
ea0999c9 | 201 | FOREACH_DIRENT_ALL(de, dir, break) { |
663996b3 | 202 | pid_t pid; |
86f210e9 | 203 | int r; |
663996b3 | 204 | |
ea0999c9 | 205 | if (!IN_SET(de->d_type, DT_DIR, DT_UNKNOWN)) |
663996b3 MS |
206 | continue; |
207 | ||
ea0999c9 | 208 | if (parse_pid(de->d_name, &pid) < 0) |
663996b3 MS |
209 | continue; |
210 | ||
4c89c718 | 211 | if (ignore_proc(pid, sig == SIGKILL && !in_initrd())) |
663996b3 MS |
212 | continue; |
213 | ||
214 | if (sig == SIGKILL) { | |
e842803a | 215 | _cleanup_free_ char *s = NULL; |
663996b3 | 216 | |
a032b68d | 217 | (void) get_process_comm(pid, &s); |
60f067b4 | 218 | log_notice("Sending SIGKILL to PID "PID_FMT" (%s).", pid, strna(s)); |
663996b3 MS |
219 | } |
220 | ||
221 | if (kill(pid, sig) >= 0) { | |
f2dec872 | 222 | n_killed++; |
86f210e9 | 223 | if (pids) { |
d9dfd233 | 224 | r = set_put(pids, PID_TO_PTR(pid)); |
86f210e9 MP |
225 | if (r < 0) |
226 | log_oom(); | |
227 | } | |
663996b3 | 228 | } else if (errno != ENOENT) |
f47781d8 | 229 | log_warning_errno(errno, "Could not kill %d: %m", pid); |
60f067b4 JS |
230 | |
231 | if (send_sighup) { | |
232 | /* Optionally, also send a SIGHUP signal, but | |
233 | only if the process has a controlling | |
234 | tty. This is useful to allow handling of | |
235 | shells which ignore SIGTERM but react to | |
236 | SIGHUP. We do not send this to processes that | |
237 | have no controlling TTY since we don't want to | |
238 | trigger reloads of daemon processes. Also we | |
239 | make sure to only send this after SIGTERM so | |
240 | that SIGTERM is always first in the queue. */ | |
241 | ||
60f067b4 | 242 | if (get_ctty_devnr(pid, NULL) >= 0) |
2897b343 MP |
243 | /* it's OK if the process is gone, just ignore the result */ |
244 | (void) kill(pid, SIGHUP); | |
60f067b4 | 245 | } |
663996b3 MS |
246 | } |
247 | ||
f2dec872 | 248 | return n_killed; |
663996b3 MS |
249 | } |
250 | ||
f2dec872 BR |
251 | int broadcast_signal(int sig, bool wait_for_exit, bool send_sighup, usec_t timeout) { |
252 | int n_children_left; | |
663996b3 | 253 | sigset_t mask, oldmask; |
e842803a | 254 | _cleanup_set_free_ Set *pids = NULL; |
663996b3 | 255 | |
f2dec872 BR |
256 | /* Send the specified signal to all remaining processes, if not excluded by ignore_proc(). |
257 | * Return: | |
258 | * - The number of processes still "alive" after the timeout (that should have been killed) | |
259 | * if the function needs to wait for the end of the processes (wait_for_exit). | |
260 | * - Otherwise, the number of processes to which the specified signal was sent */ | |
261 | ||
663996b3 | 262 | if (wait_for_exit) |
5eef597e | 263 | pids = set_new(NULL); |
663996b3 MS |
264 | |
265 | assert_se(sigemptyset(&mask) == 0); | |
266 | assert_se(sigaddset(&mask, SIGCHLD) == 0); | |
267 | assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) == 0); | |
268 | ||
269 | if (kill(-1, SIGSTOP) < 0 && errno != ESRCH) | |
f47781d8 | 270 | log_warning_errno(errno, "kill(-1, SIGSTOP) failed: %m"); |
663996b3 | 271 | |
f2dec872 | 272 | n_children_left = killall(sig, pids, send_sighup); |
663996b3 MS |
273 | |
274 | if (kill(-1, SIGCONT) < 0 && errno != ESRCH) | |
f47781d8 | 275 | log_warning_errno(errno, "kill(-1, SIGCONT) failed: %m"); |
663996b3 | 276 | |
f2dec872 BR |
277 | if (wait_for_exit && n_children_left > 0) |
278 | n_children_left = wait_for_children(pids, &mask, timeout); | |
663996b3 MS |
279 | |
280 | assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0); | |
f2dec872 BR |
281 | |
282 | return n_children_left; | |
663996b3 | 283 | } |