]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/signal-util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
6 #include "errno-util.h"
8 #include "missing_syscall.h"
9 #include "missing_threads.h"
10 #include "parse-util.h"
11 #include "signal-util.h"
12 #include "stdio-util.h"
13 #include "string-table.h"
14 #include "string-util.h"
16 int reset_all_signal_handlers(void) {
17 static const struct sigaction sa
= {
18 .sa_handler
= SIG_DFL
,
19 .sa_flags
= SA_RESTART
,
23 for (int sig
= 1; sig
< _NSIG
; sig
++) {
25 /* These two cannot be caught... */
26 if (IN_SET(sig
, SIGKILL
, SIGSTOP
))
29 /* On Linux the first two RT signals are reserved by
30 * glibc, and sigaction() will return EINVAL for them. */
31 if (sigaction(sig
, &sa
, NULL
) < 0)
32 if (errno
!= EINVAL
&& r
>= 0)
39 int reset_signal_mask(void) {
42 if (sigemptyset(&ss
) < 0)
45 return RET_NERRNO(sigprocmask(SIG_SETMASK
, &ss
, NULL
));
48 int sigaction_many_internal(const struct sigaction
*sa
, ...) {
54 /* negative signal ends the list. 0 signal is skipped. */
55 while ((sig
= va_arg(ap
, int)) >= 0) {
60 if (sigaction(sig
, sa
, NULL
) < 0) {
71 static int sigset_add_many_ap(sigset_t
*ss
, va_list ap
) {
76 while ((sig
= va_arg(ap
, int)) >= 0) {
81 if (sigaddset(ss
, sig
) < 0) {
90 int sigset_add_many(sigset_t
*ss
, ...) {
95 r
= sigset_add_many_ap(ss
, ap
);
101 int sigprocmask_many(int how
, sigset_t
*old
, ...) {
106 if (sigemptyset(&ss
) < 0)
110 r
= sigset_add_many_ap(&ss
, ap
);
116 if (sigprocmask(how
, &ss
, old
) < 0)
122 static const char *const static_signal_table
[] = {
139 [SIGSTKFLT
] = "STKFLT", /* Linux on SPARC doesn't know SIGSTKFLT */
150 [SIGVTALRM
] = "VTALRM",
152 [SIGWINCH
] = "WINCH",
158 DEFINE_PRIVATE_STRING_TABLE_LOOKUP(static_signal
, int);
160 const char *signal_to_string(int signo
) {
161 static thread_local
char buf
[STRLEN("RTMIN+") + DECIMAL_STR_MAX(int)];
164 name
= static_signal_to_string(signo
);
168 if (signo
>= SIGRTMIN
&& signo
<= SIGRTMAX
)
169 xsprintf(buf
, "RTMIN+%d", signo
- SIGRTMIN
);
171 xsprintf(buf
, "%d", signo
);
176 int signal_from_string(const char *s
) {
180 /* Check that the input is a signal number. */
181 if (safe_atoi(s
, &signo
) >= 0) {
182 if (SIGNAL_VALID(signo
))
188 /* Drop "SIG" prefix. */
189 if (startswith(s
, "SIG"))
192 /* Check that the input is a signal name. */
193 signo
= static_signal_from_string(s
);
197 /* Check that the input is RTMIN or
198 * RTMIN+n (0 <= n <= SIGRTMAX-SIGRTMIN). */
199 p
= startswith(s
, "RTMIN");
206 r
= safe_atoi(p
, &signo
);
210 if (signo
< 0 || signo
> SIGRTMAX
- SIGRTMIN
)
213 return signo
+ SIGRTMIN
;
216 /* Check that the input is RTMAX or
217 * RTMAX-n (0 <= n <= SIGRTMAX-SIGRTMIN). */
218 p
= startswith(s
, "RTMAX");
225 r
= safe_atoi(p
, &signo
);
229 if (signo
> 0 || signo
< SIGRTMIN
- SIGRTMAX
)
232 return signo
+ SIGRTMAX
;
238 void nop_signal_handler(int sig
) {
242 int signal_is_blocked(int sig
) {
246 r
= pthread_sigmask(SIG_SETMASK
, NULL
, &ss
);
250 return RET_NERRNO(sigismember(&ss
, sig
));
253 int pop_pending_signal_internal(int sig
, ...) {
258 if (sig
< 0) /* Empty list? */
261 if (sigemptyset(&ss
) < 0)
264 /* Add first signal (if the signal is zero, we'll silently skip it, to make it easier to build
265 * parameter lists where some element are sometimes off, similar to how sigset_add_many_ap() handles
267 if (sig
> 0 && sigaddset(&ss
, sig
) < 0)
270 /* Add all other signals */
272 r
= sigset_add_many_ap(&ss
, ap
);
277 r
= sigtimedwait(&ss
, NULL
, &(struct timespec
) { 0, 0 });
285 return r
; /* Returns the signal popped */
288 void propagate_signal(int sig
, siginfo_t
*siginfo
) {
291 /* To be called from a signal handler. Will raise the same signal again, in our process + in our threads.
293 * Note that we use raw_getpid() instead of getpid_cached(). We might have forked with raw_clone()
294 * earlier (see PID 1), and hence let's go to the raw syscall here. In particular as this is not
295 * performance sensitive code.
297 * Note that we use kill() rather than raise() as fallback, for similar reasons. */
301 if (rt_tgsigqueueinfo(p
, gettid(), sig
, siginfo
) < 0)
302 assert_se(kill(p
, sig
) >= 0);