]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/killall.c
0272fdb0da5def7c35c003f357dad2748072d6e3
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
;
84 SET_FOREACH(p
, pids
) {
85 _cleanup_free_
char *s
= NULL
;
87 if (get_process_comm(PTR_TO_PID(p
), &s
) < 0)
88 (void) asprintf(&s
, PID_FMT
, PTR_TO_PID(p
));
90 if (!strextend(&lst_child
, ", ", s
, NULL
)) {
96 if (isempty(lst_child
))
99 log_warning("Waiting for process: %s", lst_child
+ 2);
102 static int wait_for_children(Set
*pids
, sigset_t
*mask
, usec_t timeout
) {
103 usec_t until
, date_log_child
, n
;
107 /* Return the number of children remaining in the pids set: That correspond to the number
108 * of processes still "alive" after the timeout */
110 if (set_isempty(pids
))
113 n
= now(CLOCK_MONOTONIC
);
114 until
= usec_add(n
, timeout
);
115 date_log_child
= usec_add(n
, 10u * USEC_PER_SEC
);
116 if (date_log_child
> until
)
117 date_log_child
= usec_add(n
, timeout
/ 2u);
124 /* First, let the kernel inform us about killed
125 * children. Most processes will probably be our
126 * children, but some are not (might be our
127 * grandchildren instead...). */
131 pid
= waitpid(-1, NULL
, WNOHANG
);
138 return log_error_errno(errno
, "waitpid() failed: %m");
141 (void) set_remove(pids
, PID_TO_PTR(pid
));
144 /* Now explicitly check who might be remaining, who
145 * might not be our child. */
146 SET_FOREACH(p
, pids
) {
148 /* kill(pid, 0) sends no signal, but it tells
149 * us whether the process still exists. */
150 if (kill(PTR_TO_PID(p
), 0) == 0)
159 if (set_isempty(pids
))
162 n
= now(CLOCK_MONOTONIC
);
163 if (date_log_child
> 0 && n
>= date_log_child
) {
164 log_children_no_yet_killed(pids
);
165 /* Log the children not yet killed only once */
170 return set_size(pids
);
172 if (date_log_child
> 0)
173 timespec_store(&ts
, MIN(until
- n
, date_log_child
- n
));
175 timespec_store(&ts
, until
- n
);
177 k
= sigtimedwait(mask
, NULL
, &ts
);
180 if (k
< 0 && errno
!= EAGAIN
)
181 return log_error_errno(errno
, "sigtimedwait() failed: %m");
184 log_warning("sigtimedwait() returned unexpected signal.");
189 static int killall(int sig
, Set
*pids
, bool send_sighup
) {
190 _cleanup_closedir_
DIR *dir
= NULL
;
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 */
197 dir
= opendir("/proc");
199 return log_warning_errno(errno
, "opendir(/proc) failed: %m");
201 FOREACH_DIRENT_ALL(d
, dir
, break) {
205 if (!IN_SET(d
->d_type
, DT_DIR
, DT_UNKNOWN
))
208 if (parse_pid(d
->d_name
, &pid
) < 0)
211 if (ignore_proc(pid
, sig
== SIGKILL
&& !in_initrd()))
214 if (sig
== SIGKILL
) {
215 _cleanup_free_
char *s
= NULL
;
217 get_process_comm(pid
, &s
);
218 log_notice("Sending SIGKILL to PID "PID_FMT
" (%s).", pid
, strna(s
));
221 if (kill(pid
, sig
) >= 0) {
224 r
= set_put(pids
, PID_TO_PTR(pid
));
228 } else if (errno
!= ENOENT
)
229 log_warning_errno(errno
, "Could not kill %d: %m", pid
);
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. */
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
);
251 int broadcast_signal(int sig
, bool wait_for_exit
, bool send_sighup
, usec_t timeout
) {
253 sigset_t mask
, oldmask
;
254 _cleanup_set_free_ Set
*pids
= NULL
;
256 /* Send the specified signal to all remaining processes, if not excluded by ignore_proc().
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 */
263 pids
= set_new(NULL
);
265 assert_se(sigemptyset(&mask
) == 0);
266 assert_se(sigaddset(&mask
, SIGCHLD
) == 0);
267 assert_se(sigprocmask(SIG_BLOCK
, &mask
, &oldmask
) == 0);
269 if (kill(-1, SIGSTOP
) < 0 && errno
!= ESRCH
)
270 log_warning_errno(errno
, "kill(-1, SIGSTOP) failed: %m");
272 n_children_left
= killall(sig
, pids
, send_sighup
);
274 if (kill(-1, SIGCONT
) < 0 && errno
!= ESRCH
)
275 log_warning_errno(errno
, "kill(-1, SIGCONT) failed: %m");
277 if (wait_for_exit
&& n_children_left
> 0)
278 n_children_left
= wait_for_children(pids
, &mask
, timeout
);
280 assert_se(sigprocmask(SIG_SETMASK
, &oldmask
, NULL
) == 0);
282 return n_children_left
;