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