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