Line data Source code
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 1001 : int reset_all_signal_handlers(void) {
26 : static const struct sigaction sa = {
27 : .sa_handler = SIG_DFL,
28 : .sa_flags = SA_RESTART,
29 : };
30 1001 : int sig, r = 0;
31 :
32 65065 : for (sig = 1; sig < _NSIG; sig++) {
33 :
34 : /* These two cannot be caught... */
35 64064 : if (sig == SIGKILL || sig == SIGSTOP)
36 2002 : continue;
37 :
38 : /* On Linux the first two RT signals are reserved by
39 : * glibc, and sigaction() will return EINVAL for them. */
40 62062 : if ((sigaction(sig, &sa, NULL) < 0))
41 2002 : if (errno != EINVAL && r >= 0)
42 0 : r = -errno;
43 : }
44 :
45 1001 : return r;
46 : }
47 :
48 1001 : int reset_signal_mask(void) {
49 : sigset_t ss;
50 :
51 1001 : if (sigemptyset(&ss) < 0)
52 0 : return -errno;
53 :
54 1001 : if (sigprocmask(SIG_SETMASK, &ss, NULL) < 0)
55 0 : return -errno;
56 :
57 1001 : return 0;
58 : }
59 :
60 3 : static int sigaction_many_ap(const struct sigaction *sa, int sig, va_list ap) {
61 3 : int r = 0;
62 :
63 : /* negative signal ends the list. 0 signal is skipped. */
64 :
65 3 : if (sig < 0)
66 0 : return 0;
67 :
68 3 : if (sig > 0) {
69 3 : if (sigaction(sig, sa, NULL) < 0)
70 0 : r = -errno;
71 : }
72 :
73 13 : while ((sig = va_arg(ap, int)) >= 0) {
74 :
75 7 : if (sig == 0)
76 0 : continue;
77 :
78 7 : if (sigaction(sig, sa, NULL) < 0) {
79 0 : if (r >= 0)
80 0 : r = -errno;
81 : }
82 : }
83 :
84 3 : return r;
85 : }
86 :
87 0 : int sigaction_many(const struct sigaction *sa, ...) {
88 : va_list ap;
89 : int r;
90 :
91 0 : va_start(ap, sa);
92 0 : r = sigaction_many_ap(sa, 0, ap);
93 0 : va_end(ap);
94 :
95 0 : return r;
96 : }
97 :
98 2 : 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 2 : va_start(ap, sig);
109 2 : r = sigaction_many_ap(&sa, sig, ap);
110 2 : va_end(ap);
111 :
112 2 : return r;
113 : }
114 :
115 1 : 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 1 : va_start(ap, sig);
126 1 : r = sigaction_many_ap(&sa, sig, ap);
127 1 : va_end(ap);
128 :
129 1 : return r;
130 : }
131 :
132 15 : static int sigset_add_many_ap(sigset_t *ss, va_list ap) {
133 15 : int sig, r = 0;
134 :
135 15 : assert(ss);
136 :
137 342 : while ((sig = va_arg(ap, int)) >= 0) {
138 :
139 312 : if (sig == 0)
140 0 : continue;
141 :
142 312 : if (sigaddset(ss, sig) < 0) {
143 0 : if (r >= 0)
144 0 : r = -errno;
145 : }
146 : }
147 :
148 15 : return r;
149 : }
150 :
151 11 : int sigset_add_many(sigset_t *ss, ...) {
152 : va_list ap;
153 : int r;
154 :
155 11 : va_start(ap, ss);
156 11 : r = sigset_add_many_ap(ss, ap);
157 11 : va_end(ap);
158 :
159 11 : return r;
160 : }
161 :
162 4 : int sigprocmask_many(int how, sigset_t *old, ...) {
163 : va_list ap;
164 : sigset_t ss;
165 : int r;
166 :
167 4 : if (sigemptyset(&ss) < 0)
168 0 : return -errno;
169 :
170 4 : va_start(ap, old);
171 4 : r = sigset_add_many_ap(&ss, ap);
172 4 : va_end(ap);
173 :
174 4 : if (r < 0)
175 0 : return r;
176 :
177 4 : if (sigprocmask(how, &ss, old) < 0)
178 0 : return -errno;
179 :
180 4 : 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 59 : DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int);
220 :
221 59 : 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 59 : name = __signal_to_string(signo);
226 59 : if (name)
227 58 : return name;
228 :
229 1 : if (signo >= SIGRTMIN && signo <= SIGRTMAX)
230 1 : snprintf(buf, sizeof(buf), "RTMIN+%d", signo - SIGRTMIN);
231 : else
232 0 : snprintf(buf, sizeof(buf), "%d", signo);
233 :
234 1 : return buf;
235 : }
236 :
237 0 : int signal_from_string(const char *s) {
238 : int signo;
239 0 : int offset = 0;
240 : unsigned u;
241 :
242 0 : signo = __signal_from_string(s);
243 0 : if (signo > 0)
244 0 : return signo;
245 :
246 0 : if (startswith(s, "RTMIN+")) {
247 0 : s += 6;
248 0 : offset = SIGRTMIN;
249 : }
250 0 : if (safe_atou(s, &u) >= 0) {
251 0 : signo = (int) u + offset;
252 0 : if (signo > 0 && signo < _NSIG)
253 0 : return signo;
254 : }
255 0 : return -EINVAL;
256 : }
257 :
258 0 : int signal_from_string_try_harder(const char *s) {
259 : int signo;
260 0 : assert(s);
261 :
262 0 : signo = signal_from_string(s);
263 0 : if (signo <= 0)
264 0 : if (startswith(s, "SIG"))
265 0 : return signal_from_string(s+3);
266 :
267 0 : return signo;
268 : }
|