/* * Copy me if you can. * by 20h */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "arg.h" #include "log.h" pid_t spawn_handler(int fd, char **argv) { pid_t pid = fork(); if (pid < 0) edie("fork"); if (pid == 0) { dup2(fd, 0); execv(argv[0], argv); edie("execl"); } 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(SIGCHLD, SIG_IGN); 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) edie("socket"); slen = 64*1024; if (setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &slen, sizeof(slen)) < 0) { edie("setsockopt"); } slen = 1; if (setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &slen, sizeof(slen)) < 0) { edie("setsockopt"); } if (bind(fd, (void *)&nls, sizeof(nls))) edie("bind"); fcntl(fd, F_SETFD, FD_CLOEXEC); return fd; } void usage(void) { die("usage: %s runpath [...]\n", argv0); } int main(int argc, char *argv[]) { struct pollfd fds; ARGBEGIN { default: usage(); } ARGEND; fds.events = POLLIN; fds.fd = init_netlink_socket(); initsignals(); while (poll(&fds, 1, -1) > -1) { if (fds.revents & POLLIN) { int status; pid_t childpid = spawn_handler(fds.fd, argv); waitpid(childpid, &status, 0); } } return 0; }