]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/killall.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright © 2010 ProFUSION embedded systems
11 #include "alloc-util.h"
13 #include "dirent-util.h"
15 #include "format-util.h"
17 #include "parse-util.h"
18 #include "process-util.h"
20 #include "string-util.h"
21 #include "terminal-util.h"
24 static bool ignore_proc(pid_t pid
, bool warn_rootfs
) {
25 _cleanup_fclose_
FILE *f
= NULL
;
31 /* We are PID 1, let's not commit suicide */
35 /* Ignore kernel threads */
36 r
= is_kernel_thread(pid
);
38 return true; /* also ignore processes where we can't determine this */
40 r
= get_process_uid(pid
, &uid
);
42 return true; /* not really, but better safe than sorry */
44 /* Non-root processes otherwise are always subject to be killed */
48 p
= procfs_file_alloca(pid
, "cmdline");
51 return true; /* not really, but has the desired effect */
53 /* Try to read the first character of the command line. If the cmdline is empty (which might be the case for
54 * kernel threads but potentially also other stuff), this line won't do anything, but we don't care much, as
55 * actual kernel threads are already filtered out above. */
56 (void) fread(&c
, 1, 1, f
);
58 /* Processes with argv[0][0] = '@' we ignore from the killing spree.
60 * https://systemd.io/ROOT_STORAGE_DAEMONS */
65 pid_from_same_root_fs(pid
) == 0) {
67 _cleanup_free_
char *comm
= NULL
;
69 (void) get_process_comm(pid
, &comm
);
71 log_notice("Process " PID_FMT
" (%s) has been marked to be excluded from killing. It is "
72 "running from the root file system, and thus likely to block re-mounting of the "
73 "root file system to read-only. Please consider moving it into an initrd file "
74 "system instead.", pid
, strna(comm
));
80 static void log_children_no_yet_killed(Set
*pids
) {
81 _cleanup_free_
char *lst_child
= NULL
;
85 SET_FOREACH(p
, pids
, i
) {
86 _cleanup_free_
char *s
= NULL
;
88 if (get_process_comm(PTR_TO_PID(p
), &s
) < 0)
89 (void) asprintf(&s
, PID_FMT
, PTR_TO_PID(p
));
91 if (!strextend(&lst_child
, ", ", s
, NULL
)) {
97 if (isempty(lst_child
))
100 log_warning("Waiting for process: %s", lst_child
+ 2);
103 static int wait_for_children(Set
*pids
, sigset_t
*mask
, usec_t timeout
) {
104 usec_t until
, date_log_child
, n
;
108 /* Return the number of children remaining in the pids set: That correspond to the number
109 * of processes still "alive" after the timeout */
111 if (set_isempty(pids
))
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);
126 /* First, let the kernel inform us about killed
127 * children. Most processes will probably be our
128 * children, but some are not (might be our
129 * grandchildren instead...). */
133 pid
= waitpid(-1, NULL
, WNOHANG
);
140 return log_error_errno(errno
, "waitpid() failed: %m");
143 (void) set_remove(pids
, PID_TO_PTR(pid
));
146 /* Now explicitly check who might be remaining, who
147 * might not be our child. */
148 SET_FOREACH(p
, pids
, i
) {
150 /* kill(pid, 0) sends no signal, but it tells
151 * us whether the process still exists. */
152 if (kill(PTR_TO_PID(p
), 0) == 0)
161 if (set_isempty(pids
))
164 n
= now(CLOCK_MONOTONIC
);
165 if (date_log_child
> 0 && n
>= date_log_child
) {
166 log_children_no_yet_killed(pids
);
167 /* Log the children not yet killed only once */
172 return set_size(pids
);
174 if (date_log_child
> 0)
175 timespec_store(&ts
, MIN(until
- n
, date_log_child
- n
));
177 timespec_store(&ts
, until
- n
);
179 k
= sigtimedwait(mask
, NULL
, &ts
);
182 if (k
< 0 && errno
!= EAGAIN
)
183 return log_error_errno(errno
, "sigtimedwait() failed: %m");
186 log_warning("sigtimedwait() returned unexpected signal.");
191 static int killall(int sig
, Set
*pids
, bool send_sighup
) {
192 _cleanup_closedir_
DIR *dir
= NULL
;
196 /* Send the specified signal to all remaining processes, if not excluded by ignore_proc().
197 * Returns the number of processes to which the specified signal was sent */
199 dir
= opendir("/proc");
201 return log_warning_errno(errno
, "opendir(/proc) failed: %m");
203 FOREACH_DIRENT_ALL(d
, dir
, break) {
207 if (!IN_SET(d
->d_type
, DT_DIR
, DT_UNKNOWN
))
210 if (parse_pid(d
->d_name
, &pid
) < 0)
213 if (ignore_proc(pid
, sig
== SIGKILL
&& !in_initrd()))
216 if (sig
== SIGKILL
) {
217 _cleanup_free_
char *s
= NULL
;
219 get_process_comm(pid
, &s
);
220 log_notice("Sending SIGKILL to PID "PID_FMT
" (%s).", pid
, strna(s
));
223 if (kill(pid
, sig
) >= 0) {
226 r
= set_put(pids
, PID_TO_PTR(pid
));
230 } else if (errno
!= ENOENT
)
231 log_warning_errno(errno
, "Could not kill %d: %m", pid
);
234 /* Optionally, also send a SIGHUP signal, but
235 only if the process has a controlling
236 tty. This is useful to allow handling of
237 shells which ignore SIGTERM but react to
238 SIGHUP. We do not send this to processes that
239 have no controlling TTY since we don't want to
240 trigger reloads of daemon processes. Also we
241 make sure to only send this after SIGTERM so
242 that SIGTERM is always first in the queue. */
244 if (get_ctty_devnr(pid
, NULL
) >= 0)
245 /* it's OK if the process is gone, just ignore the result */
246 (void) kill(pid
, SIGHUP
);
253 int broadcast_signal(int sig
, bool wait_for_exit
, bool send_sighup
, usec_t timeout
) {
255 sigset_t mask
, oldmask
;
256 _cleanup_set_free_ Set
*pids
= NULL
;
258 /* Send the specified signal to all remaining processes, if not excluded by ignore_proc().
260 * - The number of processes still "alive" after the timeout (that should have been killed)
261 * if the function needs to wait for the end of the processes (wait_for_exit).
262 * - Otherwise, the number of processes to which the specified signal was sent */
265 pids
= set_new(NULL
);
267 assert_se(sigemptyset(&mask
) == 0);
268 assert_se(sigaddset(&mask
, SIGCHLD
) == 0);
269 assert_se(sigprocmask(SIG_BLOCK
, &mask
, &oldmask
) == 0);
271 if (kill(-1, SIGSTOP
) < 0 && errno
!= ESRCH
)
272 log_warning_errno(errno
, "kill(-1, SIGSTOP) failed: %m");
274 n_children_left
= killall(sig
, pids
, send_sighup
);
276 if (kill(-1, SIGCONT
) < 0 && errno
!= ESRCH
)
277 log_warning_errno(errno
, "kill(-1, SIGCONT) failed: %m");
279 if (wait_for_exit
&& n_children_left
> 0)
280 n_children_left
= wait_for_children(pids
, &mask
, timeout
);
282 assert_se(sigprocmask(SIG_SETMASK
, &oldmask
, NULL
) == 0);
284 return n_children_left
;