aboutsummaryrefslogblamecommitdiffstats
path: root/src/pdeath.c
blob: 2d564a89043af25f08c15bcf9c8147eedb5c6c2d (plain) (tree)









































































































































































                                                                                        
/* 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;
}