1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 /***
3 Copyright © 2010 ProFUSION embedded systems
4 ***/
5
6 #include <errno.h>
7 #include <signal.h>
8 #include <sys/wait.h>
9 #include <unistd.h>
10
11 #include "alloc-util.h"
12 #include "def.h"
13 #include "dirent-util.h"
14 #include "fd-util.h"
15 #include "format-util.h"
16 #include "killall.h"
17 #include "parse-util.h"
18 #include "process-util.h"
19 #include "set.h"
20 #include "stdio-util.h"
21 #include "string-util.h"
22 #include "terminal-util.h"
23 #include "util.h"
24
ignore_proc(pid_t pid,bool warn_rootfs)25 static bool ignore_proc(pid_t pid, bool warn_rootfs) {
26 _cleanup_fclose_ FILE *f = NULL;
27 const char *p;
28 char c = 0;
29 uid_t uid;
30 int r;
31
32 /* We are PID 1, let's not commit suicide */
33 if (pid <= 1)
34 return true;
35
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
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
49 p = procfs_file_alloca(pid, "cmdline");
50 f = fopen(p, "re");
51 if (!f)
52 return true; /* not really, but has the desired effect */
53
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);
58
59 /* Processes with argv[0][0] = '@' we ignore from the killing spree.
60 *
61 * https://systemd.io/ROOT_STORAGE_DAEMONS */
62 if (c != '@')
63 return false;
64
65 if (warn_rootfs &&
66 pid_from_same_root_fs(pid) == 0) {
67
68 _cleanup_free_ char *comm = NULL;
69
70 (void) get_process_comm(pid, &comm);
71
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 }
77
78 return true;
79 }
80
log_children_no_yet_killed(Set * pids)81 static void log_children_no_yet_killed(Set *pids) {
82 _cleanup_free_ char *lst_child = NULL;
83 void *p;
84 int r;
85
86 SET_FOREACH(p, pids) {
87 _cleanup_free_ char *s = NULL;
88
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)
94 return (void) log_oom();
95 }
96
97 if (isempty(lst_child))
98 return;
99
100 log_warning("Waiting for process: %s", lst_child + 2);
101 }
102
wait_for_children(Set * pids,sigset_t * mask,usec_t timeout)103 static int wait_for_children(Set *pids, sigset_t *mask, usec_t timeout) {
104 usec_t until, date_log_child, n;
105
106 assert(mask);
107
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
111 if (set_isempty(pids))
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);
119
120 for (;;) {
121 struct timespec ts;
122 int k;
123 void *p;
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
139 return log_error_errno(errno, "waitpid() failed: %m");
140 }
141
142 (void) set_remove(pids, PID_TO_PTR(pid));
143 }
144
145 /* Now explicitly check who might be remaining, who
146 * might not be our child. */
147 SET_FOREACH(p, pids) {
148
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)
152 continue;
153
154 if (errno != ESRCH)
155 continue;
156
157 set_remove(pids, p);
158 }
159
160 if (set_isempty(pids))
161 return 0;
162
163 n = now(CLOCK_MONOTONIC);
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
170 if (n >= until)
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);
177
178 k = sigtimedwait(mask, NULL, &ts);
179 if (k != SIGCHLD) {
180
181 if (k < 0 && errno != EAGAIN)
182 return log_error_errno(errno, "sigtimedwait() failed: %m");
183
184 if (k >= 0)
185 log_warning("sigtimedwait() returned unexpected signal.");
186 }
187 }
188 }
189
killall(int sig,Set * pids,bool send_sighup)190 static int killall(int sig, Set *pids, bool send_sighup) {
191 _cleanup_closedir_ DIR *dir = NULL;
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 */
196
197 dir = opendir("/proc");
198 if (!dir)
199 return log_warning_errno(errno, "opendir(/proc) failed: %m");
200
201 FOREACH_DIRENT_ALL(de, dir, break) {
202 pid_t pid;
203 int r;
204
205 if (!IN_SET(de->d_type, DT_DIR, DT_UNKNOWN))
206 continue;
207
208 if (parse_pid(de->d_name, &pid) < 0)
209 continue;
210
211 if (ignore_proc(pid, sig == SIGKILL && !in_initrd()))
212 continue;
213
214 if (sig == SIGKILL) {
215 _cleanup_free_ char *s = NULL;
216
217 (void) get_process_comm(pid, &s);
218 log_notice("Sending SIGKILL to PID "PID_FMT" (%s).", pid, strna(s));
219 }
220
221 if (kill(pid, sig) >= 0) {
222 n_killed++;
223 if (pids) {
224 r = set_put(pids, PID_TO_PTR(pid));
225 if (r < 0)
226 log_oom();
227 }
228 } else if (errno != ENOENT)
229 log_warning_errno(errno, "Could not kill %d: %m", pid);
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
242 if (get_ctty_devnr(pid, NULL) >= 0)
243 /* it's OK if the process is gone, just ignore the result */
244 (void) kill(pid, SIGHUP);
245 }
246 }
247
248 return n_killed;
249 }
250
broadcast_signal(int sig,bool wait_for_exit,bool send_sighup,usec_t timeout)251 int broadcast_signal(int sig, bool wait_for_exit, bool send_sighup, usec_t timeout) {
252 int n_children_left;
253 sigset_t mask, oldmask;
254 _cleanup_set_free_ Set *pids = NULL;
255
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
262 if (wait_for_exit)
263 pids = set_new(NULL);
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)
270 log_warning_errno(errno, "kill(-1, SIGSTOP) failed: %m");
271
272 n_children_left = killall(sig, pids, send_sighup);
273
274 if (kill(-1, SIGCONT) < 0 && errno != ESRCH)
275 log_warning_errno(errno, "kill(-1, SIGCONT) failed: %m");
276
277 if (wait_for_exit && n_children_left > 0)
278 n_children_left = wait_for_children(pids, &mask, timeout);
279
280 assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0);
281
282 return n_children_left;
283 }
284