Systemd/src/basic/signal-util.c
Lennart Poettering 0c69794138 tree-wide: remove Lennart's copyright lines
These lines are generally out-of-date, incomplete and unnecessary. With
SPDX and git repository much more accurate and fine grained information
about licensing and authorship is available, hence let's drop the
per-file copyright notice. Of course, removing copyright lines of others
is problematic, hence this commit only removes my own lines and leaves
all others untouched. It might be nicer if sooner or later those could
go away too, making git the only and accurate source of authorship
information.
2018-06-14 10:20:20 +02:00

291 lines
6.7 KiB
C

/* SPDX-License-Identifier: LGPL-2.1+ */
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include "macro.h"
#include "parse-util.h"
#include "signal-util.h"
#include "stdio-util.h"
#include "string-table.h"
#include "string-util.h"
int reset_all_signal_handlers(void) {
static const struct sigaction sa = {
.sa_handler = SIG_DFL,
.sa_flags = SA_RESTART,
};
int sig, r = 0;
for (sig = 1; sig < _NSIG; sig++) {
/* These two cannot be caught... */
if (IN_SET(sig, SIGKILL, SIGSTOP))
continue;
/* On Linux the first two RT signals are reserved by
* glibc, and sigaction() will return EINVAL for them. */
if ((sigaction(sig, &sa, NULL) < 0))
if (errno != EINVAL && r >= 0)
r = -errno;
}
return r;
}
int reset_signal_mask(void) {
sigset_t ss;
if (sigemptyset(&ss) < 0)
return -errno;
if (sigprocmask(SIG_SETMASK, &ss, NULL) < 0)
return -errno;
return 0;
}
static int sigaction_many_ap(const struct sigaction *sa, int sig, va_list ap) {
int r = 0;
/* negative signal ends the list. 0 signal is skipped. */
if (sig < 0)
return 0;
if (sig > 0) {
if (sigaction(sig, sa, NULL) < 0)
r = -errno;
}
while ((sig = va_arg(ap, int)) >= 0) {
if (sig == 0)
continue;
if (sigaction(sig, sa, NULL) < 0) {
if (r >= 0)
r = -errno;
}
}
return r;
}
int sigaction_many(const struct sigaction *sa, ...) {
va_list ap;
int r;
va_start(ap, sa);
r = sigaction_many_ap(sa, 0, ap);
va_end(ap);
return r;
}
int ignore_signals(int sig, ...) {
static const struct sigaction sa = {
.sa_handler = SIG_IGN,
.sa_flags = SA_RESTART,
};
va_list ap;
int r;
va_start(ap, sig);
r = sigaction_many_ap(&sa, sig, ap);
va_end(ap);
return r;
}
int default_signals(int sig, ...) {
static const struct sigaction sa = {
.sa_handler = SIG_DFL,
.sa_flags = SA_RESTART,
};
va_list ap;
int r;
va_start(ap, sig);
r = sigaction_many_ap(&sa, sig, ap);
va_end(ap);
return r;
}
static int sigset_add_many_ap(sigset_t *ss, va_list ap) {
int sig, r = 0;
assert(ss);
while ((sig = va_arg(ap, int)) >= 0) {
if (sig == 0)
continue;
if (sigaddset(ss, sig) < 0) {
if (r >= 0)
r = -errno;
}
}
return r;
}
int sigset_add_many(sigset_t *ss, ...) {
va_list ap;
int r;
va_start(ap, ss);
r = sigset_add_many_ap(ss, ap);
va_end(ap);
return r;
}
int sigprocmask_many(int how, sigset_t *old, ...) {
va_list ap;
sigset_t ss;
int r;
if (sigemptyset(&ss) < 0)
return -errno;
va_start(ap, old);
r = sigset_add_many_ap(&ss, ap);
va_end(ap);
if (r < 0)
return r;
if (sigprocmask(how, &ss, old) < 0)
return -errno;
return 0;
}
static const char *const __signal_table[] = {
[SIGHUP] = "HUP",
[SIGINT] = "INT",
[SIGQUIT] = "QUIT",
[SIGILL] = "ILL",
[SIGTRAP] = "TRAP",
[SIGABRT] = "ABRT",
[SIGBUS] = "BUS",
[SIGFPE] = "FPE",
[SIGKILL] = "KILL",
[SIGUSR1] = "USR1",
[SIGSEGV] = "SEGV",
[SIGUSR2] = "USR2",
[SIGPIPE] = "PIPE",
[SIGALRM] = "ALRM",
[SIGTERM] = "TERM",
#ifdef SIGSTKFLT
[SIGSTKFLT] = "STKFLT", /* Linux on SPARC doesn't know SIGSTKFLT */
#endif
[SIGCHLD] = "CHLD",
[SIGCONT] = "CONT",
[SIGSTOP] = "STOP",
[SIGTSTP] = "TSTP",
[SIGTTIN] = "TTIN",
[SIGTTOU] = "TTOU",
[SIGURG] = "URG",
[SIGXCPU] = "XCPU",
[SIGXFSZ] = "XFSZ",
[SIGVTALRM] = "VTALRM",
[SIGPROF] = "PROF",
[SIGWINCH] = "WINCH",
[SIGIO] = "IO",
[SIGPWR] = "PWR",
[SIGSYS] = "SYS"
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int);
const char *signal_to_string(int signo) {
static thread_local char buf[STRLEN("RTMIN+") + DECIMAL_STR_MAX(int) + 1];
const char *name;
name = __signal_to_string(signo);
if (name)
return name;
if (signo >= SIGRTMIN && signo <= SIGRTMAX)
xsprintf(buf, "RTMIN+%d", signo - SIGRTMIN);
else
xsprintf(buf, "%d", signo);
return buf;
}
int signal_from_string(const char *s) {
const char *p;
int signo, r;
/* Check that the input is a signal number. */
if (safe_atoi(s, &signo) >= 0) {
if (SIGNAL_VALID(signo))
return signo;
else
return -ERANGE;
}
/* Drop "SIG" prefix. */
if (startswith(s, "SIG"))
s += 3;
/* Check that the input is a signal name. */
signo = __signal_from_string(s);
if (signo > 0)
return signo;
/* Check that the input is RTMIN or
* RTMIN+n (0 <= n <= SIGRTMAX-SIGRTMIN). */
p = startswith(s, "RTMIN");
if (p) {
if (*p == '\0')
return SIGRTMIN;
if (*p != '+')
return -EINVAL;
r = safe_atoi(p, &signo);
if (r < 0)
return r;
if (signo < 0 || signo > SIGRTMAX - SIGRTMIN)
return -ERANGE;
return signo + SIGRTMIN;
}
/* Check that the input is RTMAX or
* RTMAX-n (0 <= n <= SIGRTMAX-SIGRTMIN). */
p = startswith(s, "RTMAX");
if (p) {
if (*p == '\0')
return SIGRTMAX;
if (*p != '-')
return -EINVAL;
r = safe_atoi(p, &signo);
if (r < 0)
return r;
if (signo > 0 || signo < SIGRTMIN - SIGRTMAX)
return -ERANGE;
return signo + SIGRTMAX;
}
return -EINVAL;
}
void nop_signal_handler(int sig) {
/* nothing here */
}