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