]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/basic/signal-util.c
license: LGPL-2.1+ -> LGPL-2.1-or-later
[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
93cc7779 6#include "macro.h"
6bedfcbb
LP
7#include "parse-util.h"
8#include "signal-util.h"
d054f0a4 9#include "stdio-util.h"
8b43440b 10#include "string-table.h"
07630cea 11#include "string-util.h"
07630cea 12
24882e06 13int reset_all_signal_handlers(void) {
0c2c2a3a
LP
14 static const struct sigaction sa = {
15 .sa_handler = SIG_DFL,
16 .sa_flags = SA_RESTART,
17 };
24882e06
LP
18 int sig, r = 0;
19
20 for (sig = 1; sig < _NSIG; sig++) {
24882e06
LP
21
22 /* These two cannot be caught... */
3742095b 23 if (IN_SET(sig, SIGKILL, SIGSTOP))
24882e06
LP
24 continue;
25
26 /* On Linux the first two RT signals are reserved by
27 * glibc, and sigaction() will return EINVAL for them. */
08e82b84 28 if (sigaction(sig, &sa, NULL) < 0)
0c2c2a3a 29 if (errno != EINVAL && r >= 0)
24882e06
LP
30 r = -errno;
31 }
32
33 return r;
34}
35
36int reset_signal_mask(void) {
37 sigset_t ss;
38
39 if (sigemptyset(&ss) < 0)
40 return -errno;
41
42 if (sigprocmask(SIG_SETMASK, &ss, NULL) < 0)
43 return -errno;
44
45 return 0;
46}
47
0c2c2a3a
LP
48static int sigaction_many_ap(const struct sigaction *sa, int sig, va_list ap) {
49 int r = 0;
50
51 /* negative signal ends the list. 0 signal is skipped. */
bd8e699c 52 for (; sig >= 0; sig = va_arg(ap, int)) {
0c2c2a3a
LP
53
54 if (sig == 0)
55 continue;
56
57 if (sigaction(sig, sa, NULL) < 0) {
58 if (r >= 0)
59 r = -errno;
60 }
61 }
62
63 return r;
64}
65
24882e06
LP
66int sigaction_many(const struct sigaction *sa, ...) {
67 va_list ap;
0c2c2a3a 68 int r;
24882e06
LP
69
70 va_start(ap, sa);
0c2c2a3a 71 r = sigaction_many_ap(sa, 0, ap);
24882e06
LP
72 va_end(ap);
73
74 return r;
75}
76
77int ignore_signals(int sig, ...) {
0c2c2a3a 78
24882e06
LP
79 static const struct sigaction sa = {
80 .sa_handler = SIG_IGN,
81 .sa_flags = SA_RESTART,
82 };
24882e06 83
0c2c2a3a
LP
84 va_list ap;
85 int r;
24882e06
LP
86
87 va_start(ap, sig);
0c2c2a3a 88 r = sigaction_many_ap(&sa, sig, ap);
24882e06
LP
89 va_end(ap);
90
91 return r;
92}
93
94int default_signals(int sig, ...) {
0c2c2a3a 95
24882e06
LP
96 static const struct sigaction sa = {
97 .sa_handler = SIG_DFL,
98 .sa_flags = SA_RESTART,
99 };
24882e06 100
0c2c2a3a
LP
101 va_list ap;
102 int r;
24882e06
LP
103
104 va_start(ap, sig);
0c2c2a3a 105 r = sigaction_many_ap(&sa, sig, ap);
24882e06
LP
106 va_end(ap);
107
108 return r;
109}
110
0c2c2a3a
LP
111static int sigset_add_many_ap(sigset_t *ss, va_list ap) {
112 int sig, r = 0;
24882e06
LP
113
114 assert(ss);
115
0c2c2a3a
LP
116 while ((sig = va_arg(ap, int)) >= 0) {
117
118 if (sig == 0)
119 continue;
120
121 if (sigaddset(ss, sig) < 0) {
122 if (r >= 0)
123 r = -errno;
124 }
125 }
126
127 return r;
128}
129
130int sigset_add_many(sigset_t *ss, ...) {
131 va_list ap;
132 int r;
133
24882e06 134 va_start(ap, ss);
0c2c2a3a 135 r = sigset_add_many_ap(ss, ap);
24882e06 136 va_end(ap);
0c2c2a3a
LP
137
138 return r;
24882e06
LP
139}
140
72c0a2c2 141int sigprocmask_many(int how, sigset_t *old, ...) {
24882e06
LP
142 va_list ap;
143 sigset_t ss;
0c2c2a3a 144 int r;
24882e06 145
0c2c2a3a
LP
146 if (sigemptyset(&ss) < 0)
147 return -errno;
24882e06 148
c59d3e8d 149 va_start(ap, old);
0c2c2a3a 150 r = sigset_add_many_ap(&ss, ap);
24882e06
LP
151 va_end(ap);
152
0c2c2a3a
LP
153 if (r < 0)
154 return r;
155
72c0a2c2 156 if (sigprocmask(how, &ss, old) < 0)
24882e06
LP
157 return -errno;
158
159 return 0;
160}
161
162static const char *const __signal_table[] = {
163 [SIGHUP] = "HUP",
164 [SIGINT] = "INT",
165 [SIGQUIT] = "QUIT",
166 [SIGILL] = "ILL",
167 [SIGTRAP] = "TRAP",
168 [SIGABRT] = "ABRT",
169 [SIGBUS] = "BUS",
170 [SIGFPE] = "FPE",
171 [SIGKILL] = "KILL",
172 [SIGUSR1] = "USR1",
173 [SIGSEGV] = "SEGV",
174 [SIGUSR2] = "USR2",
175 [SIGPIPE] = "PIPE",
176 [SIGALRM] = "ALRM",
177 [SIGTERM] = "TERM",
178#ifdef SIGSTKFLT
179 [SIGSTKFLT] = "STKFLT", /* Linux on SPARC doesn't know SIGSTKFLT */
180#endif
181 [SIGCHLD] = "CHLD",
182 [SIGCONT] = "CONT",
183 [SIGSTOP] = "STOP",
184 [SIGTSTP] = "TSTP",
185 [SIGTTIN] = "TTIN",
186 [SIGTTOU] = "TTOU",
187 [SIGURG] = "URG",
188 [SIGXCPU] = "XCPU",
189 [SIGXFSZ] = "XFSZ",
190 [SIGVTALRM] = "VTALRM",
191 [SIGPROF] = "PROF",
192 [SIGWINCH] = "WINCH",
193 [SIGIO] = "IO",
194 [SIGPWR] = "PWR",
195 [SIGSYS] = "SYS"
196};
197
198DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int);
199
200const char *signal_to_string(int signo) {
fbd0b64f 201 static thread_local char buf[STRLEN("RTMIN+") + DECIMAL_STR_MAX(int) + 1];
24882e06
LP
202 const char *name;
203
204 name = __signal_to_string(signo);
205 if (name)
206 return name;
207
208 if (signo >= SIGRTMIN && signo <= SIGRTMAX)
d054f0a4 209 xsprintf(buf, "RTMIN+%d", signo - SIGRTMIN);
24882e06 210 else
d054f0a4 211 xsprintf(buf, "%d", signo);
24882e06
LP
212
213 return buf;
214}
215
216int signal_from_string(const char *s) {
08d3fdc3
YW
217 const char *p;
218 int signo, r;
24882e06 219
29a3db75 220 /* Check that the input is a signal number. */
08d3fdc3 221 if (safe_atoi(s, &signo) >= 0) {
6eb7c172 222 if (SIGNAL_VALID(signo))
24882e06 223 return signo;
08d3fdc3
YW
224 else
225 return -ERANGE;
226 }
227
29a3db75
YW
228 /* Drop "SIG" prefix. */
229 if (startswith(s, "SIG"))
230 s += 3;
231
232 /* Check that the input is a signal name. */
233 signo = __signal_from_string(s);
234 if (signo > 0)
235 return signo;
236
08d3fdc3
YW
237 /* Check that the input is RTMIN or
238 * RTMIN+n (0 <= n <= SIGRTMAX-SIGRTMIN). */
239 p = startswith(s, "RTMIN");
240 if (p) {
241 if (*p == '\0')
242 return SIGRTMIN;
243 if (*p != '+')
244 return -EINVAL;
245
246 r = safe_atoi(p, &signo);
247 if (r < 0)
248 return r;
249
250 if (signo < 0 || signo > SIGRTMAX - SIGRTMIN)
251 return -ERANGE;
252
253 return signo + SIGRTMIN;
24882e06 254 }
08d3fdc3
YW
255
256 /* Check that the input is RTMAX or
257 * RTMAX-n (0 <= n <= SIGRTMAX-SIGRTMIN). */
258 p = startswith(s, "RTMAX");
259 if (p) {
260 if (*p == '\0')
261 return SIGRTMAX;
262 if (*p != '-')
263 return -EINVAL;
264
265 r = safe_atoi(p, &signo);
266 if (r < 0)
267 return r;
268
269 if (signo > 0 || signo < SIGRTMIN - SIGRTMAX)
270 return -ERANGE;
271
272 return signo + SIGRTMAX;
273 }
274
24882e06
LP
275 return -EINVAL;
276}
277
6bedfcbb
LP
278void nop_signal_handler(int sig) {
279 /* nothing here */
280}
90b15e18
LP
281
282int signal_is_blocked(int sig) {
283 sigset_t ss;
284 int r;
285
286 r = pthread_sigmask(SIG_SETMASK, NULL, &ss);
287 if (r != 0)
288 return -r;
289
290 r = sigismember(&ss, sig);
291 if (r < 0)
292 return -errno;
293
294 return r;
295}