aboutsummaryrefslogtreecommitdiffstats
path: root/src/pdeath.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/pdeath.c')
-rw-r--r--src/pdeath.c170
1 files changed, 170 insertions, 0 deletions
diff --git a/src/pdeath.c b/src/pdeath.c
new file mode 100644
index 0000000..2d564a8
--- /dev/null
+++ b/src/pdeath.c
@@ -0,0 +1,170 @@
+/* See LICENSE file for copyright and license details. */
+
+#include <sys/prctl.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+
+#define FAILURE 127
+
+struct sig {
+ int signo;
+ const char *name;
+} sigs[] = {
+ {SIGHUP, "HUP"},
+ {SIGINT, "INT"},
+ {SIGQUIT, "QUIT"},
+ {SIGILL, "ILL"},
+ {SIGTRAP, "TRAP"},
+ {SIGABRT, "ABRT"},
+ {SIGIOT, "IOT"},
+ {SIGBUS, "BUS"},
+ {SIGFPE, "FPE"},
+ {SIGKILL, "KILL"},
+ {SIGUSR1, "USR1"},
+ {SIGSEGV, "SEGV"},
+ {SIGUSR2, "USR2"},
+ {SIGPIPE, "PIPE"},
+ {SIGALRM, "ALRM"},
+ {SIGTERM, "TERM"},
+ {SIGSTKFLT, "TKFLT"},
+ {SIGCLD, "CLD"},
+ {SIGCHLD, "CHLD"},
+ {SIGCONT, "CONT"},
+ {SIGSTOP, "STOP"},
+ {SIGTSTP, "TSTP"},
+ {SIGTTIN, "TTIN"},
+ {SIGTTOU, "TTOU"},
+ {SIGURG, "URG"},
+ {SIGXCPU, "XCPU"},
+ {SIGXFSZ, "XFSZ"},
+ {SIGVTALRM, "VTALRM"},
+ {SIGPROF, "PROF"},
+ {SIGWINCH, "WINCH"},
+ {SIGPOLL, "POLL"},
+ {SIGIO, "IO"},
+ {SIGPWR, "PWR"},
+ {SIGSYS, "SYS"},
+ {SIGUNUSED, "UNUSED"},
+ {0, NULL}
+};
+
+const char *argv0;
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: %s (signal)[(+|-)off] command [arguments]...\n", argv0);
+ fprintf(stderr, "usage: %s -L\n", argv0);
+ exit(FAILURE);
+}
+
+static void
+invalid_signal(void)
+{
+ fprintf(stderr, "%s: invalid signal\n", argv0);
+ exit(FAILURE);
+}
+
+static void
+print_signals(void)
+{
+ struct sig *sig = sigs;
+ for (; sig->name; sig++)
+ printf("%s\n", sig->name);
+ printf("RTMIN\nRTMAX\n");
+}
+
+static int
+strict_strtoi(const char *str, int min, int max)
+{
+ char *end;
+ long int ret;
+ errno = 0;
+ ret = strtol(str, &end, 10);
+ if (errno || *end)
+ usage();
+ if (ret < min || ret > max)
+ invalid_signal();
+ return (int)ret;
+}
+
+static int
+get_signal(const char *str)
+{
+ struct sig *sig = sigs;
+ int have_prefix = 0;
+ char *end;
+ long int ret;
+ if (!strncasecmp(str, "SIG", 3)) {
+ str += 3;
+ have_prefix = 1;
+ }
+ if (!strcasecmp(str, "RTMIN"))
+ return SIGRTMIN;
+ if (!strcasecmp(str, "RTMAX"))
+ return SIGRTMAX;
+ for (; sig->name; sig++) {
+ if (!strcasecmp(str, sig->name))
+ return sig->signo;
+ }
+ if (!have_prefix) {
+ errno = 0;
+ ret = strtol(str, &end, 10);
+ if (!errno && !*end && 0 <= ret && ret < _NSIG)
+ return (int)ret;
+
+ }
+ invalid_signal();
+ return -1;
+}
+
+int
+main(int argc, char *argv[])
+{
+ char *off;
+ char sign = '\0';
+ int signo;
+
+ argv0 = *argv ? (argc--, *argv++) : "pdeath";
+
+ if (*argv && **argv == '-') {
+ if (argc == 1 && !strcmp(*argv, "-L")) {
+ print_signals();
+ if (fflush(stdout) || fclose(stdout)) {
+ perror(argv0);
+ return FAILURE;
+ }
+ return 0;
+ }
+ usage();
+ }
+
+ if (argc < 2)
+ usage();
+
+ if ((off = strpbrk(*argv, "+-"))) {
+ sign = *off;
+ *off++ = '\0';
+ }
+ signo = get_signal(*argv);
+ if (sign == '-')
+ signo -= strict_strtoi(off, 0, signo);
+ else if (sign == '+')
+ signo += strict_strtoi(off, 0, _NSIG - 1 - signo);
+ argv++, argc--;
+
+ if (prctl(PR_SET_PDEATHSIG, signo) == -1) {
+ perror(argv0);
+ return FAILURE;
+ }
+
+ execvp(*argv, argv);
+ fprintf(stderr, "%s: %s: %s\n", argv0, strerror(errno), *argv);
+ return FAILURE;
+}