chiark / gitweb /
basic: parse_timestamp UTC and fractional seconds support
[elogind.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 /// UNNEEDED by elogind
116 #if 0
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 #endif // 0
134
135 static int sigset_add_many_ap(sigset_t *ss, va_list ap) {
136         int sig, r = 0;
137
138         assert(ss);
139
140         while ((sig = va_arg(ap, int)) >= 0) {
141
142                 if (sig == 0)
143                         continue;
144
145                 if (sigaddset(ss, sig) < 0) {
146                         if (r >= 0)
147                                 r = -errno;
148                 }
149         }
150
151         return r;
152 }
153
154 int sigset_add_many(sigset_t *ss, ...) {
155         va_list ap;
156         int r;
157
158         va_start(ap, ss);
159         r = sigset_add_many_ap(ss, ap);
160         va_end(ap);
161
162         return r;
163 }
164
165 int sigprocmask_many(int how, sigset_t *old, ...) {
166         va_list ap;
167         sigset_t ss;
168         int r;
169
170         if (sigemptyset(&ss) < 0)
171                 return -errno;
172
173         va_start(ap, old);
174         r = sigset_add_many_ap(&ss, ap);
175         va_end(ap);
176
177         if (r < 0)
178                 return r;
179
180         if (sigprocmask(how, &ss, old) < 0)
181                 return -errno;
182
183         return 0;
184 }
185
186 static const char *const __signal_table[] = {
187         [SIGHUP] = "HUP",
188         [SIGINT] = "INT",
189         [SIGQUIT] = "QUIT",
190         [SIGILL] = "ILL",
191         [SIGTRAP] = "TRAP",
192         [SIGABRT] = "ABRT",
193         [SIGBUS] = "BUS",
194         [SIGFPE] = "FPE",
195         [SIGKILL] = "KILL",
196         [SIGUSR1] = "USR1",
197         [SIGSEGV] = "SEGV",
198         [SIGUSR2] = "USR2",
199         [SIGPIPE] = "PIPE",
200         [SIGALRM] = "ALRM",
201         [SIGTERM] = "TERM",
202 #ifdef SIGSTKFLT
203         [SIGSTKFLT] = "STKFLT",  /* Linux on SPARC doesn't know SIGSTKFLT */
204 #endif
205         [SIGCHLD] = "CHLD",
206         [SIGCONT] = "CONT",
207         [SIGSTOP] = "STOP",
208         [SIGTSTP] = "TSTP",
209         [SIGTTIN] = "TTIN",
210         [SIGTTOU] = "TTOU",
211         [SIGURG] = "URG",
212         [SIGXCPU] = "XCPU",
213         [SIGXFSZ] = "XFSZ",
214         [SIGVTALRM] = "VTALRM",
215         [SIGPROF] = "PROF",
216         [SIGWINCH] = "WINCH",
217         [SIGIO] = "IO",
218         [SIGPWR] = "PWR",
219         [SIGSYS] = "SYS"
220 };
221
222 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int);
223
224 const char *signal_to_string(int signo) {
225         static thread_local char buf[sizeof("RTMIN+")-1 + DECIMAL_STR_MAX(int) + 1];
226         const char *name;
227
228         name = __signal_to_string(signo);
229         if (name)
230                 return name;
231
232         if (signo >= SIGRTMIN && signo <= SIGRTMAX)
233                 snprintf(buf, sizeof(buf), "RTMIN+%d", signo - SIGRTMIN);
234         else
235                 snprintf(buf, sizeof(buf), "%d", signo);
236
237         return buf;
238 }
239
240 int signal_from_string(const char *s) {
241         int signo;
242         int offset = 0;
243         unsigned u;
244
245         signo = __signal_from_string(s);
246         if (signo > 0)
247                 return signo;
248
249         if (startswith(s, "RTMIN+")) {
250                 s += 6;
251                 offset = SIGRTMIN;
252         }
253         if (safe_atou(s, &u) >= 0) {
254                 signo = (int) u + offset;
255                 if (signo > 0 && signo < _NSIG)
256                         return signo;
257         }
258         return -EINVAL;
259 }
260
261 int signal_from_string_try_harder(const char *s) {
262         int signo;
263         assert(s);
264
265         signo = signal_from_string(s);
266         if (signo <= 0)
267                 if (startswith(s, "SIG"))
268                         return signal_from_string(s+3);
269
270         return signo;
271 }