/* * Copy me if you can. * by 20h * * Copyright (c) 2015 Natanael Copa */ #include #include #include #include #include #include #include #include #include #include #include "arg.h" char *argv0; pid_t spawn_handler(int fd, char **argv) { pid_t pid = fork(); if (pid < 0) err(1, "fork"); if (pid == 0) { if (fd > 0) dup2(fd, 0); execv(argv[0], argv); err(1, argv[0]); } return pid; } void sighandler(int sig) { switch(sig) { case SIGHUP: case SIGINT: case SIGQUIT: case SIGABRT: case SIGTERM: exit(0); break; default: break; } } void initsignals(void) { signal(SIGHUP, sighandler); signal(SIGINT, sighandler); signal(SIGQUIT, sighandler); signal(SIGABRT, sighandler); signal(SIGTERM, sighandler); signal(SIGPIPE, SIG_IGN); } int init_netlink_socket(void) { struct sockaddr_nl nls; int fd, slen; memset(&nls, 0, sizeof(nls)); nls.nl_family = AF_NETLINK; nls.nl_pid = getpid(); nls.nl_groups = -1; fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); if (fd < 0) err(1, "socket"); /* kernel will not create events bigger than 16kb, but we need buffer up all events during coldplug */ slen = 1024*1024; if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &slen, sizeof(slen)) < 0) { err(1, "setsockopt"); } slen = 1; if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &slen, sizeof(slen)) < 0) { err(1, "setsockopt"); } if (bind(fd, (void *)&nls, sizeof(nls))) err(1, "bind"); fcntl(fd, F_SETFD, FD_CLOEXEC); return fd; } void usage(void) { errx(1, "usage: %s [-s] [-t triggerpath] runpath [...]\n", argv0); } int main(int argc, char *argv[]) { struct pollfd fds; int single_run = 0; char *trigger_argv[3] = { NULL, NULL, NULL}; pid_t childpid; int status, r; ARGBEGIN { case 's': single_run = 1; break; case 't': trigger_argv[0] = EARGF(usage()); trigger_argv[1] = trigger_argv[0]; break; default: usage(); } ARGEND; if (argv[0] == NULL) usage(); fds.events = POLLIN; fds.fd = init_netlink_socket(); initsignals(); if (trigger_argv[0]) { childpid = spawn_handler(0, trigger_argv); r = waitpid(childpid, &status, 0); } while (poll(&fds, 1, -1) > -1) { if (fds.revents & POLLIN) { childpid = spawn_handler(fds.fd, argv); r = waitpid(childpid, &status, 0); if(r == -1) { warn("waitpid(%d)", childpid); } else if (single_run && WIFEXITED(status)) { return WEXITSTATUS(status); } } } return 0; }