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