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