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