]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/signal-util.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.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 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <errno.h>
22 #include <stdarg.h>
23 #include <stdio.h>
24
25 #include "macro.h"
26 #include "parse-util.h"
27 #include "signal-util.h"
28 #include "stdio-util.h"
29 #include "string-table.h"
30 #include "string-util.h"
31
32 int reset_all_signal_handlers(void) {
33 static const struct sigaction sa = {
34 .sa_handler = SIG_DFL,
35 .sa_flags = SA_RESTART,
36 };
37 int sig, r = 0;
38
39 for (sig = 1; sig < _NSIG; sig++) {
40
41 /* These two cannot be caught... */
42 if (IN_SET(sig, SIGKILL, SIGSTOP))
43 continue;
44
45 /* On Linux the first two RT signals are reserved by
46 * glibc, and sigaction() will return EINVAL for them. */
47 if ((sigaction(sig, &sa, NULL) < 0))
48 if (errno != EINVAL && r >= 0)
49 r = -errno;
50 }
51
52 return r;
53 }
54
55 int reset_signal_mask(void) {
56 sigset_t ss;
57
58 if (sigemptyset(&ss) < 0)
59 return -errno;
60
61 if (sigprocmask(SIG_SETMASK, &ss, NULL) < 0)
62 return -errno;
63
64 return 0;
65 }
66
67 static int sigaction_many_ap(const struct sigaction *sa, int sig, va_list ap) {
68 int r = 0;
69
70 /* negative signal ends the list. 0 signal is skipped. */
71
72 if (sig < 0)
73 return 0;
74
75 if (sig > 0) {
76 if (sigaction(sig, sa, NULL) < 0)
77 r = -errno;
78 }
79
80 while ((sig = va_arg(ap, int)) >= 0) {
81
82 if (sig == 0)
83 continue;
84
85 if (sigaction(sig, sa, NULL) < 0) {
86 if (r >= 0)
87 r = -errno;
88 }
89 }
90
91 return r;
92 }
93
94 int sigaction_many(const struct sigaction *sa, ...) {
95 va_list ap;
96 int r;
97
98 va_start(ap, sa);
99 r = sigaction_many_ap(sa, 0, ap);
100 va_end(ap);
101
102 return r;
103 }
104
105 int ignore_signals(int sig, ...) {
106
107 static const struct sigaction sa = {
108 .sa_handler = SIG_IGN,
109 .sa_flags = SA_RESTART,
110 };
111
112 va_list ap;
113 int r;
114
115 va_start(ap, sig);
116 r = sigaction_many_ap(&sa, sig, ap);
117 va_end(ap);
118
119 return r;
120 }
121
122 int default_signals(int sig, ...) {
123
124 static const struct sigaction sa = {
125 .sa_handler = SIG_DFL,
126 .sa_flags = SA_RESTART,
127 };
128
129 va_list ap;
130 int r;
131
132 va_start(ap, sig);
133 r = sigaction_many_ap(&sa, sig, ap);
134 va_end(ap);
135
136 return r;
137 }
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 xsprintf(buf, "RTMIN+%d", signo - SIGRTMIN);
238 else
239 xsprintf(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 (SIGNAL_VALID(signo))
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 void nop_signal_handler(int sig) {
278 /* nothing here */
279 }