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