chiark / gitweb /
tree-wide: remove Lennart's copyright lines
[elogind.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 #if 0 /// UNNEEDED by elogind
77 int sigaction_many(const struct sigaction *sa, ...) {
78         va_list ap;
79         int r;
80
81         va_start(ap, sa);
82         r = sigaction_many_ap(sa, 0, ap);
83         va_end(ap);
84
85         return r;
86 }
87 #endif // 0
88
89 int ignore_signals(int sig, ...) {
90
91         static const struct sigaction sa = {
92                 .sa_handler = SIG_IGN,
93                 .sa_flags = SA_RESTART,
94         };
95
96         va_list ap;
97         int r;
98
99         va_start(ap, sig);
100         r = sigaction_many_ap(&sa, sig, ap);
101         va_end(ap);
102
103         return r;
104 }
105
106 int default_signals(int sig, ...) {
107
108         static const struct sigaction sa = {
109                 .sa_handler = SIG_DFL,
110                 .sa_flags = SA_RESTART,
111         };
112
113         va_list ap;
114         int r;
115
116         va_start(ap, sig);
117         r = sigaction_many_ap(&sa, sig, ap);
118         va_end(ap);
119
120         return r;
121 }
122
123 static int sigset_add_many_ap(sigset_t *ss, va_list ap) {
124         int sig, r = 0;
125
126         assert(ss);
127
128         while ((sig = va_arg(ap, int)) >= 0) {
129
130                 if (sig == 0)
131                         continue;
132
133                 if (sigaddset(ss, sig) < 0) {
134                         if (r >= 0)
135                                 r = -errno;
136                 }
137         }
138
139         return r;
140 }
141
142 int sigset_add_many(sigset_t *ss, ...) {
143         va_list ap;
144         int r;
145
146         va_start(ap, ss);
147         r = sigset_add_many_ap(ss, ap);
148         va_end(ap);
149
150         return r;
151 }
152
153 int sigprocmask_many(int how, sigset_t *old, ...) {
154         va_list ap;
155         sigset_t ss;
156         int r;
157
158         if (sigemptyset(&ss) < 0)
159                 return -errno;
160
161         va_start(ap, old);
162         r = sigset_add_many_ap(&ss, ap);
163         va_end(ap);
164
165         if (r < 0)
166                 return r;
167
168         if (sigprocmask(how, &ss, old) < 0)
169                 return -errno;
170
171         return 0;
172 }
173
174 static const char *const __signal_table[] = {
175         [SIGHUP] = "HUP",
176         [SIGINT] = "INT",
177         [SIGQUIT] = "QUIT",
178         [SIGILL] = "ILL",
179         [SIGTRAP] = "TRAP",
180         [SIGABRT] = "ABRT",
181         [SIGBUS] = "BUS",
182         [SIGFPE] = "FPE",
183         [SIGKILL] = "KILL",
184         [SIGUSR1] = "USR1",
185         [SIGSEGV] = "SEGV",
186         [SIGUSR2] = "USR2",
187         [SIGPIPE] = "PIPE",
188         [SIGALRM] = "ALRM",
189         [SIGTERM] = "TERM",
190 #ifdef SIGSTKFLT
191         [SIGSTKFLT] = "STKFLT",  /* Linux on SPARC doesn't know SIGSTKFLT */
192 #endif
193         [SIGCHLD] = "CHLD",
194         [SIGCONT] = "CONT",
195         [SIGSTOP] = "STOP",
196         [SIGTSTP] = "TSTP",
197         [SIGTTIN] = "TTIN",
198         [SIGTTOU] = "TTOU",
199         [SIGURG] = "URG",
200         [SIGXCPU] = "XCPU",
201         [SIGXFSZ] = "XFSZ",
202         [SIGVTALRM] = "VTALRM",
203         [SIGPROF] = "PROF",
204         [SIGWINCH] = "WINCH",
205         [SIGIO] = "IO",
206         [SIGPWR] = "PWR",
207         [SIGSYS] = "SYS"
208 };
209
210 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int);
211
212 const char *signal_to_string(int signo) {
213         static thread_local char buf[STRLEN("RTMIN+") + DECIMAL_STR_MAX(int) + 1];
214         const char *name;
215
216         name = __signal_to_string(signo);
217         if (name)
218                 return name;
219
220         if (signo >= SIGRTMIN && signo <= SIGRTMAX)
221                 xsprintf(buf, "RTMIN+%d", signo - SIGRTMIN);
222         else
223                 xsprintf(buf, "%d", signo);
224
225         return buf;
226 }
227
228 int signal_from_string(const char *s) {
229         const char *p;
230         int signo, r;
231
232         /* Check that the input is a signal number. */
233         if (safe_atoi(s, &signo) >= 0) {
234                 if (SIGNAL_VALID(signo))
235                         return signo;
236                 else
237                         return -ERANGE;
238         }
239
240         /* Drop "SIG" prefix. */
241         if (startswith(s, "SIG"))
242                 s += 3;
243
244         /* Check that the input is a signal name. */
245         signo = __signal_from_string(s);
246         if (signo > 0)
247                 return signo;
248
249         /* Check that the input is RTMIN or
250          * RTMIN+n (0 <= n <= SIGRTMAX-SIGRTMIN). */
251         p = startswith(s, "RTMIN");
252         if (p) {
253                 if (*p == '\0')
254                         return SIGRTMIN;
255                 if (*p != '+')
256                         return -EINVAL;
257
258                 r = safe_atoi(p, &signo);
259                 if (r < 0)
260                         return r;
261
262                 if (signo < 0 || signo > SIGRTMAX - SIGRTMIN)
263                         return -ERANGE;
264
265                 return signo + SIGRTMIN;
266         }
267
268         /* Check that the input is RTMAX or
269          * RTMAX-n (0 <= n <= SIGRTMAX-SIGRTMIN). */
270         p = startswith(s, "RTMAX");
271         if (p) {
272                 if (*p == '\0')
273                         return SIGRTMAX;
274                 if (*p != '-')
275                         return -EINVAL;
276
277                 r = safe_atoi(p, &signo);
278                 if (r < 0)
279                         return r;
280
281                 if (signo > 0 || signo < SIGRTMIN - SIGRTMAX)
282                         return -ERANGE;
283
284                 return signo + SIGRTMAX;
285         }
286
287         return -EINVAL;
288 }
289
290
291 #if 0 /// UNNEEDED by elogind
292 void nop_signal_handler(int sig) {
293         /* nothing here */
294 }
295 #endif // 0