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