]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/killall.c
Merge pull request #10088 from keszybz/man-systemctl-return
[thirdparty/systemd.git] / src / core / killall.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
bd3fa1d2 2/***
96b2fb93 3 Copyright © 2010 ProFUSION embedded systems
bd3fa1d2
LP
4***/
5
bd3fa1d2 6#include <errno.h>
07630cea
LP
7#include <signal.h>
8#include <sys/wait.h>
aaf7eb81 9#include <unistd.h>
bd3fa1d2 10
b5efdb8a 11#include "alloc-util.h"
d4506129 12#include "def.h"
8fb3f009 13#include "dirent-util.h"
3ffd4af2 14#include "fd-util.h"
f97b34a6 15#include "format-util.h"
3ffd4af2 16#include "killall.h"
6bedfcbb 17#include "parse-util.h"
0b452006 18#include "process-util.h"
07630cea
LP
19#include "set.h"
20#include "string-util.h"
288a74cc 21#include "terminal-util.h"
07630cea 22#include "util.h"
bd3fa1d2 23
1359fffa 24static bool ignore_proc(pid_t pid, bool warn_rootfs) {
31885cd5 25 _cleanup_fclose_ FILE *f = NULL;
b68fa010
SP
26 char c;
27 const char *p;
bd3fa1d2
LP
28 size_t count;
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 r = get_process_uid(pid, &uid);
37 if (r < 0)
38 return true; /* not really, but better safe than sorry */
39
40 /* Non-root processes otherwise are always subject to be killed */
41 if (uid != 0)
42 return false;
43
5841bd80
ZJS
44 p = procfs_file_alloca(pid, "cmdline");
45 f = fopen(p, "re");
bd3fa1d2
LP
46 if (!f)
47 return true; /* not really, but has the desired effect */
48
49 count = fread(&c, 1, 1, f);
bd3fa1d2
LP
50
51 /* Kernel threads have an empty cmdline */
52 if (count <= 0)
53 return true;
54
9e615117 55 /* Processes with argv[0][0] = '@' we ignore from the killing spree.
bd3fa1d2
LP
56 *
57 * http://www.freedesktop.org/wiki/Software/systemd/RootStorageDaemons */
9e615117
ZJS
58 if (c != '@')
59 return false;
60
61 if (warn_rootfs &&
62 pid_from_same_root_fs(pid) == 0) {
1359fffa 63
9e615117 64 _cleanup_free_ char *comm = NULL;
1359fffa
MS
65
66 get_process_comm(pid, &comm);
67
9e615117
ZJS
68 log_notice("Process " PID_FMT " (%s) has been marked to be excluded from killing. It is "
69 "running from the root file system, and thus likely to block re-mounting of the "
70 "root file system to read-only. Please consider moving it into an initrd file "
71 "system instead.", pid, strna(comm));
72 }
bd3fa1d2 73
9e615117 74 return true;
bd3fa1d2
LP
75}
76
e73c54b8 77static void wait_for_children(Set *pids, sigset_t *mask, usec_t timeout) {
bd3fa1d2
LP
78 usec_t until;
79
80 assert(mask);
81
aaf7eb81
LP
82 if (set_isempty(pids))
83 return;
84
e73c54b8 85 until = now(CLOCK_MONOTONIC) + timeout;
bd3fa1d2
LP
86 for (;;) {
87 struct timespec ts;
88 int k;
89 usec_t n;
aaf7eb81
LP
90 void *p;
91 Iterator i;
bd3fa1d2 92
aaf7eb81
LP
93 /* First, let the kernel inform us about killed
94 * children. Most processes will probably be our
95 * children, but some are not (might be our
96 * grandchildren instead...). */
bd3fa1d2 97 for (;;) {
aaf7eb81 98 pid_t pid;
bd3fa1d2 99
aaf7eb81 100 pid = waitpid(-1, NULL, WNOHANG);
bd3fa1d2
LP
101 if (pid == 0)
102 break;
aaf7eb81
LP
103 if (pid < 0) {
104 if (errno == ECHILD)
105 break;
bd3fa1d2 106
56f64d95 107 log_error_errno(errno, "waitpid() failed: %m");
bd3fa1d2 108 return;
aaf7eb81
LP
109 }
110
fea72cc0 111 (void) set_remove(pids, PID_TO_PTR(pid));
aaf7eb81 112 }
bd3fa1d2 113
aaf7eb81
LP
114 /* Now explicitly check who might be remaining, who
115 * might not be our child. */
116 SET_FOREACH(p, pids, i) {
117
3448a969
AJ
118 /* kill(pid, 0) sends no signal, but it tells
119 * us whether the process still exists. */
120 if (kill(PTR_TO_PID(p), 0) == 0)
aaf7eb81
LP
121 continue;
122
123 if (errno != ESRCH)
124 continue;
125
126 set_remove(pids, p);
bd3fa1d2
LP
127 }
128
aaf7eb81
LP
129 if (set_isempty(pids))
130 return;
131
bd3fa1d2
LP
132 n = now(CLOCK_MONOTONIC);
133 if (n >= until)
134 return;
135
136 timespec_store(&ts, until - n);
aaf7eb81
LP
137 k = sigtimedwait(mask, NULL, &ts);
138 if (k != SIGCHLD) {
bd3fa1d2
LP
139
140 if (k < 0 && errno != EAGAIN) {
56f64d95 141 log_error_errno(errno, "sigtimedwait() failed: %m");
bd3fa1d2
LP
142 return;
143 }
144
145 if (k >= 0)
146 log_warning("sigtimedwait() returned unexpected signal.");
147 }
148 }
149}
150
0bee65f0 151static int killall(int sig, Set *pids, bool send_sighup) {
aaf7eb81 152 _cleanup_closedir_ DIR *dir = NULL;
bd3fa1d2 153 struct dirent *d;
bd3fa1d2
LP
154
155 dir = opendir("/proc");
156 if (!dir)
157 return -errno;
158
8fb3f009 159 FOREACH_DIRENT_ALL(d, dir, break) {
bd3fa1d2 160 pid_t pid;
60053efb 161 int r;
bd3fa1d2 162
ec2ce0c5 163 if (!IN_SET(d->d_type, DT_DIR, DT_UNKNOWN))
bd3fa1d2
LP
164 continue;
165
166 if (parse_pid(d->d_name, &pid) < 0)
167 continue;
168
1359fffa 169 if (ignore_proc(pid, sig == SIGKILL && !in_initrd()))
bd3fa1d2
LP
170 continue;
171
df758e98 172 if (sig == SIGKILL) {
3e09eb5c 173 _cleanup_free_ char *s = NULL;
df758e98
KS
174
175 get_process_comm(pid, &s);
ccd06097 176 log_notice("Sending SIGKILL to PID "PID_FMT" (%s).", pid, strna(s));
df758e98
KS
177 }
178
aaf7eb81 179 if (kill(pid, sig) >= 0) {
60053efb 180 if (pids) {
fea72cc0 181 r = set_put(pids, PID_TO_PTR(pid));
60053efb
TA
182 if (r < 0)
183 log_oom();
184 }
aaf7eb81 185 } else if (errno != ENOENT)
56f64d95 186 log_warning_errno(errno, "Could not kill %d: %m", pid);
0bee65f0
LP
187
188 if (send_sighup) {
189 /* Optionally, also send a SIGHUP signal, but
190 only if the process has a controlling
191 tty. This is useful to allow handling of
192 shells which ignore SIGTERM but react to
193 SIGHUP. We do not send this to processes that
194 have no controlling TTY since we don't want to
195 trigger reloads of daemon processes. Also we
196 make sure to only send this after SIGTERM so
197 that SIGTERM is always first in the queue. */
198
0bee65f0 199 if (get_ctty_devnr(pid, NULL) >= 0)
5c5d9f26
ZJS
200 /* it's OK if the process is gone, just ignore the result */
201 (void) kill(pid, SIGHUP);
0bee65f0 202 }
bd3fa1d2
LP
203 }
204
aaf7eb81 205 return set_size(pids);
bd3fa1d2
LP
206}
207
e73c54b8 208void broadcast_signal(int sig, bool wait_for_exit, bool send_sighup, usec_t timeout) {
bd3fa1d2 209 sigset_t mask, oldmask;
e1d75803 210 _cleanup_set_free_ Set *pids = NULL;
aaf7eb81
LP
211
212 if (wait_for_exit)
d5099efc 213 pids = set_new(NULL);
bd3fa1d2
LP
214
215 assert_se(sigemptyset(&mask) == 0);
216 assert_se(sigaddset(&mask, SIGCHLD) == 0);
217 assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) == 0);
218
219 if (kill(-1, SIGSTOP) < 0 && errno != ESRCH)
56f64d95 220 log_warning_errno(errno, "kill(-1, SIGSTOP) failed: %m");
bd3fa1d2 221
0bee65f0 222 killall(sig, pids, send_sighup);
bd3fa1d2
LP
223
224 if (kill(-1, SIGCONT) < 0 && errno != ESRCH)
56f64d95 225 log_warning_errno(errno, "kill(-1, SIGCONT) failed: %m");
bd3fa1d2 226
3d141780 227 if (wait_for_exit)
e73c54b8 228 wait_for_children(pids, &mask, timeout);
aaf7eb81
LP
229
230 assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0);
bd3fa1d2 231}