]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/signal-util.c
man/systemd-sysext: list ephemeral/ephemeral-import in the list of options
[thirdparty/systemd.git] / src / basic / signal-util.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
24882e06 2
e7537295 3#include <threads.h>
4f18ff2e 4#include <unistd.h>
11c3a366 5
7c248223 6#include "errno-util.h"
128a11ea 7#include "missing_syscall.h"
6bedfcbb
LP
8#include "parse-util.h"
9#include "signal-util.h"
d054f0a4 10#include "stdio-util.h"
8b43440b 11#include "string-table.h"
07630cea 12#include "string-util.h"
07630cea 13
24882e06 14int reset_all_signal_handlers(void) {
f58411a2 15 int ret = 0, r;
24882e06 16
fe96c0f8 17 for (int sig = 1; sig < _NSIG; sig++) {
24882e06
LP
18
19 /* These two cannot be caught... */
3742095b 20 if (IN_SET(sig, SIGKILL, SIGSTOP))
24882e06
LP
21 continue;
22
f58411a2
LP
23 /* On Linux the first two RT signals are reserved by glibc, and sigaction() will return
24 * EINVAL for them. */
0bd72176 25 r = RET_NERRNO(sigaction(sig, &sigaction_default, NULL));
f58411a2
LP
26 if (r != -EINVAL)
27 RET_GATHER(ret, r);
24882e06
LP
28 }
29
f58411a2 30 return ret;
24882e06
LP
31}
32
33int reset_signal_mask(void) {
34 sigset_t ss;
35
36 if (sigemptyset(&ss) < 0)
37 return -errno;
38
7c248223 39 return RET_NERRNO(sigprocmask(SIG_SETMASK, &ss, NULL));
24882e06
LP
40}
41
9c274488
LP
42int sigaction_many_internal(const struct sigaction *sa, ...) {
43 int sig, r = 0;
44 va_list ap;
45
46 va_start(ap, sa);
0c2c2a3a
LP
47
48 /* negative signal ends the list. 0 signal is skipped. */
9c274488 49 while ((sig = va_arg(ap, int)) >= 0) {
0c2c2a3a
LP
50
51 if (sig == 0)
52 continue;
53
f58411a2 54 RET_GATHER(r, RET_NERRNO(sigaction(sig, sa, NULL)));
0c2c2a3a
LP
55 }
56
24882e06
LP
57 va_end(ap);
58
59 return r;
60}
61
0c2c2a3a
LP
62static int sigset_add_many_ap(sigset_t *ss, va_list ap) {
63 int sig, r = 0;
24882e06
LP
64
65 assert(ss);
66
0c2c2a3a
LP
67 while ((sig = va_arg(ap, int)) >= 0) {
68
69 if (sig == 0)
70 continue;
71
72 if (sigaddset(ss, sig) < 0) {
73 if (r >= 0)
74 r = -errno;
75 }
76 }
77
78 return r;
79}
80
db7136ec 81int sigset_add_many_internal(sigset_t *ss, ...) {
0c2c2a3a
LP
82 va_list ap;
83 int r;
84
24882e06 85 va_start(ap, ss);
0c2c2a3a 86 r = sigset_add_many_ap(ss, ap);
24882e06 87 va_end(ap);
0c2c2a3a
LP
88
89 return r;
24882e06
LP
90}
91
db7136ec 92int sigprocmask_many_internal(int how, sigset_t *old, ...) {
24882e06
LP
93 va_list ap;
94 sigset_t ss;
0c2c2a3a 95 int r;
24882e06 96
0c2c2a3a
LP
97 if (sigemptyset(&ss) < 0)
98 return -errno;
24882e06 99
c59d3e8d 100 va_start(ap, old);
0c2c2a3a 101 r = sigset_add_many_ap(&ss, ap);
24882e06
LP
102 va_end(ap);
103
0c2c2a3a
LP
104 if (r < 0)
105 return r;
106
f58411a2 107 return RET_NERRNO(sigprocmask(how, &ss, old));
24882e06
LP
108}
109
f8cc16fd 110static const char *const static_signal_table[] = {
5d889f3a
YW
111 [SIGHUP] = "HUP",
112 [SIGINT] = "INT",
113 [SIGQUIT] = "QUIT",
114 [SIGILL] = "ILL",
115 [SIGTRAP] = "TRAP",
116 [SIGABRT] = "ABRT",
117 [SIGBUS] = "BUS",
118 [SIGFPE] = "FPE",
119 [SIGKILL] = "KILL",
120 [SIGUSR1] = "USR1",
121 [SIGSEGV] = "SEGV",
122 [SIGUSR2] = "USR2",
123 [SIGPIPE] = "PIPE",
124 [SIGALRM] = "ALRM",
125 [SIGTERM] = "TERM",
24882e06
LP
126#ifdef SIGSTKFLT
127 [SIGSTKFLT] = "STKFLT", /* Linux on SPARC doesn't know SIGSTKFLT */
128#endif
5d889f3a
YW
129 [SIGCHLD] = "CHLD",
130 [SIGCONT] = "CONT",
131 [SIGSTOP] = "STOP",
132 [SIGTSTP] = "TSTP",
133 [SIGTTIN] = "TTIN",
134 [SIGTTOU] = "TTOU",
135 [SIGURG] = "URG",
136 [SIGXCPU] = "XCPU",
137 [SIGXFSZ] = "XFSZ",
24882e06 138 [SIGVTALRM] = "VTALRM",
5d889f3a
YW
139 [SIGPROF] = "PROF",
140 [SIGWINCH] = "WINCH",
141 [SIGIO] = "IO",
142 [SIGPWR] = "PWR",
143 [SIGSYS] = "SYS"
24882e06
LP
144};
145
f8cc16fd 146DEFINE_PRIVATE_STRING_TABLE_LOOKUP(static_signal, int);
24882e06 147
bfd5a068 148const char* signal_to_string(int signo) {
923e2122 149 static thread_local char buf[STRLEN("RTMIN+") + DECIMAL_STR_MAX(int)];
24882e06
LP
150 const char *name;
151
f8cc16fd 152 name = static_signal_to_string(signo);
24882e06
LP
153 if (name)
154 return name;
155
156 if (signo >= SIGRTMIN && signo <= SIGRTMAX)
d054f0a4 157 xsprintf(buf, "RTMIN+%d", signo - SIGRTMIN);
24882e06 158 else
d054f0a4 159 xsprintf(buf, "%d", signo);
24882e06
LP
160
161 return buf;
162}
163
164int signal_from_string(const char *s) {
08d3fdc3
YW
165 const char *p;
166 int signo, r;
24882e06 167
29a3db75 168 /* Check that the input is a signal number. */
08d3fdc3 169 if (safe_atoi(s, &signo) >= 0) {
6eb7c172 170 if (SIGNAL_VALID(signo))
24882e06 171 return signo;
08d3fdc3
YW
172 else
173 return -ERANGE;
174 }
175
29a3db75
YW
176 /* Drop "SIG" prefix. */
177 if (startswith(s, "SIG"))
178 s += 3;
179
180 /* Check that the input is a signal name. */
f8cc16fd 181 signo = static_signal_from_string(s);
29a3db75
YW
182 if (signo > 0)
183 return signo;
184
08d3fdc3
YW
185 /* Check that the input is RTMIN or
186 * RTMIN+n (0 <= n <= SIGRTMAX-SIGRTMIN). */
187 p = startswith(s, "RTMIN");
188 if (p) {
189 if (*p == '\0')
190 return SIGRTMIN;
191 if (*p != '+')
192 return -EINVAL;
193
194 r = safe_atoi(p, &signo);
195 if (r < 0)
196 return r;
197
198 if (signo < 0 || signo > SIGRTMAX - SIGRTMIN)
199 return -ERANGE;
200
201 return signo + SIGRTMIN;
24882e06 202 }
08d3fdc3
YW
203
204 /* Check that the input is RTMAX or
205 * RTMAX-n (0 <= n <= SIGRTMAX-SIGRTMIN). */
206 p = startswith(s, "RTMAX");
207 if (p) {
208 if (*p == '\0')
209 return SIGRTMAX;
210 if (*p != '-')
211 return -EINVAL;
212
213 r = safe_atoi(p, &signo);
214 if (r < 0)
215 return r;
216
217 if (signo > 0 || signo < SIGRTMIN - SIGRTMAX)
218 return -ERANGE;
219
220 return signo + SIGRTMAX;
221 }
222
24882e06
LP
223 return -EINVAL;
224}
225
6bedfcbb
LP
226void nop_signal_handler(int sig) {
227 /* nothing here */
228}
90b15e18
LP
229
230int signal_is_blocked(int sig) {
231 sigset_t ss;
232 int r;
233
234 r = pthread_sigmask(SIG_SETMASK, NULL, &ss);
235 if (r != 0)
236 return -r;
237
7c248223 238 return RET_NERRNO(sigismember(&ss, sig));
90b15e18 239}
0178ff29
LP
240
241int pop_pending_signal_internal(int sig, ...) {
242 sigset_t ss;
243 va_list ap;
244 int r;
245
246 if (sig < 0) /* Empty list? */
247 return -EINVAL;
248
249 if (sigemptyset(&ss) < 0)
250 return -errno;
251
e3709627 252 /* Add first signal (if the signal is zero, we'll silently skip it, to make it easier to build
0178ff29
LP
253 * parameter lists where some element are sometimes off, similar to how sigset_add_many_ap() handles
254 * this.) */
255 if (sig > 0 && sigaddset(&ss, sig) < 0)
256 return -errno;
257
258 /* Add all other signals */
259 va_start(ap, sig);
260 r = sigset_add_many_ap(&ss, ap);
261 va_end(ap);
262 if (r < 0)
263 return r;
264
1ca89d32 265 r = sigtimedwait(&ss, NULL, &(const struct timespec) {});
0178ff29
LP
266 if (r < 0) {
267 if (errno == EAGAIN)
268 return 0;
269
270 return -errno;
271 }
272
273 return r; /* Returns the signal popped */
274}
128a11ea
LP
275
276void propagate_signal(int sig, siginfo_t *siginfo) {
277 pid_t p;
278
279 /* To be called from a signal handler. Will raise the same signal again, in our process + in our threads.
280 *
33db9f21 281 * Note that we use getpid() instead of getpid_cached(). We might have forked with raw_clone()
128a11ea
LP
282 * earlier (see PID 1), and hence let's go to the raw syscall here. In particular as this is not
283 * performance sensitive code.
284 *
285 * Note that we use kill() rather than raise() as fallback, for similar reasons. */
286
33db9f21 287 p = getpid();
128a11ea
LP
288
289 if (rt_tgsigqueueinfo(p, gettid(), sig, siginfo) < 0)
290 assert_se(kill(p, sig) >= 0);
291}
0bd72176
LP
292
293const struct sigaction sigaction_ignore = {
294 .sa_handler = SIG_IGN,
295 .sa_flags = SA_RESTART,
296};
297
298const struct sigaction sigaction_default = {
299 .sa_handler = SIG_DFL,
300 .sa_flags = SA_RESTART,
301};
960b0458 302
bed4386e
MY
303const struct sigaction sigaction_nop_nocldstop = {
304 .sa_handler = nop_signal_handler,
305 .sa_flags = SA_NOCLDSTOP|SA_RESTART,
306};
307
960b0458
LP
308int parse_signo(const char *s, int *ret) {
309 int sig, r;
310
311 r = safe_atoi(s, &sig);
312 if (r < 0)
313 return r;
314
315 if (!SIGNAL_VALID(sig))
316 return -EINVAL;
317
318 if (ret)
319 *ret = sig;
320
321 return 0;
322}