chiark / gitweb /
Prep v228: Add remaining updates from upstream (2/3)
[elogind.git] / src / basic / signal-util.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2015 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include "parse-util.h"
23 #include "signal-util.h"
24 #include "string-table.h"
25 #include "string-util.h"
26 #include "util.h"
27
28 int reset_all_signal_handlers(void) {
29         static const struct sigaction sa = {
30                 .sa_handler = SIG_DFL,
31                 .sa_flags = SA_RESTART,
32         };
33         int sig, r = 0;
34
35         for (sig = 1; sig < _NSIG; sig++) {
36
37                 /* These two cannot be caught... */
38                 if (sig == SIGKILL || sig == SIGSTOP)
39                         continue;
40
41                 /* On Linux the first two RT signals are reserved by
42                  * glibc, and sigaction() will return EINVAL for them. */
43                 if ((sigaction(sig, &sa, NULL) < 0))
44                         if (errno != EINVAL && r >= 0)
45                                 r = -errno;
46         }
47
48         return r;
49 }
50
51 int reset_signal_mask(void) {
52         sigset_t ss;
53
54         if (sigemptyset(&ss) < 0)
55                 return -errno;
56
57         if (sigprocmask(SIG_SETMASK, &ss, NULL) < 0)
58                 return -errno;
59
60         return 0;
61 }
62
63 static int sigaction_many_ap(const struct sigaction *sa, int sig, va_list ap) {
64         int r = 0;
65
66         /* negative signal ends the list. 0 signal is skipped. */
67
68         if (sig < 0)
69                 return 0;
70
71         if (sig > 0) {
72                 if (sigaction(sig, sa, NULL) < 0)
73                         r = -errno;
74         }
75
76         while ((sig = va_arg(ap, int)) >= 0) {
77
78                 if (sig == 0)
79                         continue;
80
81                 if (sigaction(sig, sa, NULL) < 0) {
82                         if (r >= 0)
83                                 r = -errno;
84                 }
85         }
86
87         return r;
88 }
89
90 /// UNNEEDED by elogind
91 #if 0
92 int sigaction_many(const struct sigaction *sa, ...) {
93         va_list ap;
94         int r;
95
96         va_start(ap, sa);
97         r = sigaction_many_ap(sa, 0, ap);
98         va_end(ap);
99
100         return r;
101 }
102 #endif // 0
103
104 int ignore_signals(int sig, ...) {
105
106         static const struct sigaction sa = {
107                 .sa_handler = SIG_IGN,
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 /// UNNEEDED by elogind
122 #if 0
123 int default_signals(int sig, ...) {
124
125         static const struct sigaction sa = {
126                 .sa_handler = SIG_DFL,
127                 .sa_flags = SA_RESTART,
128         };
129
130         va_list ap;
131         int r;
132
133         va_start(ap, sig);
134         r = sigaction_many_ap(&sa, sig, ap);
135         va_end(ap);
136
137         return r;
138 }
139 #endif // 0
140
141 static int sigset_add_many_ap(sigset_t *ss, va_list ap) {
142         int sig, r = 0;
143
144         assert(ss);
145
146         while ((sig = va_arg(ap, int)) >= 0) {
147
148                 if (sig == 0)
149                         continue;
150
151                 if (sigaddset(ss, sig) < 0) {
152                         if (r >= 0)
153                                 r = -errno;
154                 }
155         }
156
157         return r;
158 }
159
160 int sigset_add_many(sigset_t *ss, ...) {
161         va_list ap;
162         int r;
163
164         va_start(ap, ss);
165         r = sigset_add_many_ap(ss, ap);
166         va_end(ap);
167
168         return r;
169 }
170
171 int sigprocmask_many(int how, sigset_t *old, ...) {
172         va_list ap;
173         sigset_t ss;
174         int r;
175
176         if (sigemptyset(&ss) < 0)
177                 return -errno;
178
179         va_start(ap, old);
180         r = sigset_add_many_ap(&ss, ap);
181         va_end(ap);
182
183         if (r < 0)
184                 return r;
185
186         if (sigprocmask(how, &ss, old) < 0)
187                 return -errno;
188
189         return 0;
190 }
191
192 static const char *const __signal_table[] = {
193         [SIGHUP] = "HUP",
194         [SIGINT] = "INT",
195         [SIGQUIT] = "QUIT",
196         [SIGILL] = "ILL",
197         [SIGTRAP] = "TRAP",
198         [SIGABRT] = "ABRT",
199         [SIGBUS] = "BUS",
200         [SIGFPE] = "FPE",
201         [SIGKILL] = "KILL",
202         [SIGUSR1] = "USR1",
203         [SIGSEGV] = "SEGV",
204         [SIGUSR2] = "USR2",
205         [SIGPIPE] = "PIPE",
206         [SIGALRM] = "ALRM",
207         [SIGTERM] = "TERM",
208 #ifdef SIGSTKFLT
209         [SIGSTKFLT] = "STKFLT",  /* Linux on SPARC doesn't know SIGSTKFLT */
210 #endif
211         [SIGCHLD] = "CHLD",
212         [SIGCONT] = "CONT",
213         [SIGSTOP] = "STOP",
214         [SIGTSTP] = "TSTP",
215         [SIGTTIN] = "TTIN",
216         [SIGTTOU] = "TTOU",
217         [SIGURG] = "URG",
218         [SIGXCPU] = "XCPU",
219         [SIGXFSZ] = "XFSZ",
220         [SIGVTALRM] = "VTALRM",
221         [SIGPROF] = "PROF",
222         [SIGWINCH] = "WINCH",
223         [SIGIO] = "IO",
224         [SIGPWR] = "PWR",
225         [SIGSYS] = "SYS"
226 };
227
228 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int);
229
230 const char *signal_to_string(int signo) {
231         static thread_local char buf[sizeof("RTMIN+")-1 + DECIMAL_STR_MAX(int) + 1];
232         const char *name;
233
234         name = __signal_to_string(signo);
235         if (name)
236                 return name;
237
238         if (signo >= SIGRTMIN && signo <= SIGRTMAX)
239                 snprintf(buf, sizeof(buf), "RTMIN+%d", signo - SIGRTMIN);
240         else
241                 snprintf(buf, sizeof(buf), "%d", signo);
242
243         return buf;
244 }
245
246 int signal_from_string(const char *s) {
247         int signo;
248         int offset = 0;
249         unsigned u;
250
251         signo = __signal_from_string(s);
252         if (signo > 0)
253                 return signo;
254
255         if (startswith(s, "RTMIN+")) {
256                 s += 6;
257                 offset = SIGRTMIN;
258         }
259         if (safe_atou(s, &u) >= 0) {
260                 signo = (int) u + offset;
261                 if (signo > 0 && signo < _NSIG)
262                         return signo;
263         }
264         return -EINVAL;
265 }
266
267 int signal_from_string_try_harder(const char *s) {
268         int signo;
269         assert(s);
270
271         signo = signal_from_string(s);
272         if (signo <= 0)
273                 if (startswith(s, "SIG"))
274                         return signal_from_string(s+3);
275
276         return signo;
277 }
278
279 /// UNNEEDED by elogind
280 #if 0
281 void nop_signal_handler(int sig) {
282         /* nothing here */
283 }
284 #endif // 0