]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/signal-util.c
Merge pull request #158 from ssahani/net
[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 "util.h"
23 #include "signal-util.h"
24
25 int reset_all_signal_handlers(void) {
26 static const struct sigaction sa = {
27 .sa_handler = SIG_DFL,
28 .sa_flags = SA_RESTART,
29 };
30 int sig, r = 0;
31
32 for (sig = 1; sig < _NSIG; sig++) {
33
34 /* These two cannot be caught... */
35 if (sig == SIGKILL || sig == SIGSTOP)
36 continue;
37
38 /* On Linux the first two RT signals are reserved by
39 * glibc, and sigaction() will return EINVAL for them. */
40 if ((sigaction(sig, &sa, NULL) < 0))
41 if (errno != EINVAL && r >= 0)
42 r = -errno;
43 }
44
45 return r;
46 }
47
48 int reset_signal_mask(void) {
49 sigset_t ss;
50
51 if (sigemptyset(&ss) < 0)
52 return -errno;
53
54 if (sigprocmask(SIG_SETMASK, &ss, NULL) < 0)
55 return -errno;
56
57 return 0;
58 }
59
60 static int sigaction_many_ap(const struct sigaction *sa, int sig, va_list ap) {
61 int r = 0;
62
63 /* negative signal ends the list. 0 signal is skipped. */
64
65 if (sig < 0)
66 return 0;
67
68 if (sig > 0) {
69 if (sigaction(sig, sa, NULL) < 0)
70 r = -errno;
71 }
72
73 while ((sig = va_arg(ap, int)) >= 0) {
74
75 if (sig == 0)
76 continue;
77
78 if (sigaction(sig, sa, NULL) < 0) {
79 if (r >= 0)
80 r = -errno;
81 }
82 }
83
84 return r;
85 }
86
87 int sigaction_many(const struct sigaction *sa, ...) {
88 va_list ap;
89 int r;
90
91 va_start(ap, sa);
92 r = sigaction_many_ap(sa, 0, ap);
93 va_end(ap);
94
95 return r;
96 }
97
98 int ignore_signals(int sig, ...) {
99
100 static const struct sigaction sa = {
101 .sa_handler = SIG_IGN,
102 .sa_flags = SA_RESTART,
103 };
104
105 va_list ap;
106 int r;
107
108 va_start(ap, sig);
109 r = sigaction_many_ap(&sa, sig, ap);
110 va_end(ap);
111
112 return r;
113 }
114
115 int default_signals(int sig, ...) {
116
117 static const struct sigaction sa = {
118 .sa_handler = SIG_DFL,
119 .sa_flags = SA_RESTART,
120 };
121
122 va_list ap;
123 int r;
124
125 va_start(ap, sig);
126 r = sigaction_many_ap(&sa, sig, ap);
127 va_end(ap);
128
129 return r;
130 }
131
132 static int sigset_add_many_ap(sigset_t *ss, va_list ap) {
133 int sig, r = 0;
134
135 assert(ss);
136
137 while ((sig = va_arg(ap, int)) >= 0) {
138
139 if (sig == 0)
140 continue;
141
142 if (sigaddset(ss, sig) < 0) {
143 if (r >= 0)
144 r = -errno;
145 }
146 }
147
148 return r;
149 }
150
151 int sigset_add_many(sigset_t *ss, ...) {
152 va_list ap;
153 int r;
154
155 va_start(ap, ss);
156 r = sigset_add_many_ap(ss, ap);
157 va_end(ap);
158
159 return r;
160 }
161
162 int sigprocmask_many(int how, ...) {
163 va_list ap;
164 sigset_t ss;
165 int r;
166
167 if (sigemptyset(&ss) < 0)
168 return -errno;
169
170 va_start(ap, how);
171 r = sigset_add_many_ap(&ss, ap);
172 va_end(ap);
173
174 if (r < 0)
175 return r;
176
177 if (sigprocmask(how, &ss, NULL) < 0)
178 return -errno;
179
180 return 0;
181 }
182
183 static const char *const __signal_table[] = {
184 [SIGHUP] = "HUP",
185 [SIGINT] = "INT",
186 [SIGQUIT] = "QUIT",
187 [SIGILL] = "ILL",
188 [SIGTRAP] = "TRAP",
189 [SIGABRT] = "ABRT",
190 [SIGBUS] = "BUS",
191 [SIGFPE] = "FPE",
192 [SIGKILL] = "KILL",
193 [SIGUSR1] = "USR1",
194 [SIGSEGV] = "SEGV",
195 [SIGUSR2] = "USR2",
196 [SIGPIPE] = "PIPE",
197 [SIGALRM] = "ALRM",
198 [SIGTERM] = "TERM",
199 #ifdef SIGSTKFLT
200 [SIGSTKFLT] = "STKFLT", /* Linux on SPARC doesn't know SIGSTKFLT */
201 #endif
202 [SIGCHLD] = "CHLD",
203 [SIGCONT] = "CONT",
204 [SIGSTOP] = "STOP",
205 [SIGTSTP] = "TSTP",
206 [SIGTTIN] = "TTIN",
207 [SIGTTOU] = "TTOU",
208 [SIGURG] = "URG",
209 [SIGXCPU] = "XCPU",
210 [SIGXFSZ] = "XFSZ",
211 [SIGVTALRM] = "VTALRM",
212 [SIGPROF] = "PROF",
213 [SIGWINCH] = "WINCH",
214 [SIGIO] = "IO",
215 [SIGPWR] = "PWR",
216 [SIGSYS] = "SYS"
217 };
218
219 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int);
220
221 const char *signal_to_string(int signo) {
222 static thread_local char buf[sizeof("RTMIN+")-1 + DECIMAL_STR_MAX(int) + 1];
223 const char *name;
224
225 name = __signal_to_string(signo);
226 if (name)
227 return name;
228
229 if (signo >= SIGRTMIN && signo <= SIGRTMAX)
230 snprintf(buf, sizeof(buf), "RTMIN+%d", signo - SIGRTMIN);
231 else
232 snprintf(buf, sizeof(buf), "%d", signo);
233
234 return buf;
235 }
236
237 int signal_from_string(const char *s) {
238 int signo;
239 int offset = 0;
240 unsigned u;
241
242 signo = __signal_from_string(s);
243 if (signo > 0)
244 return signo;
245
246 if (startswith(s, "RTMIN+")) {
247 s += 6;
248 offset = SIGRTMIN;
249 }
250 if (safe_atou(s, &u) >= 0) {
251 signo = (int) u + offset;
252 if (signo > 0 && signo < _NSIG)
253 return signo;
254 }
255 return -EINVAL;
256 }
257
258 int signal_from_string_try_harder(const char *s) {
259 int signo;
260 assert(s);
261
262 signo = signal_from_string(s);
263 if (signo <= 0)
264 if (startswith(s, "SIG"))
265 return signal_from_string(s+3);
266
267 return signo;
268 }