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