chiark / gitweb /
Classify processes from sessions into cgroups
[elogind.git] / src / shared / 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, sigset_t *old, ...) {
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, old) < 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 }