1#include <stdio.h>2#include <errno.h>3#include <string.h>4#include <libgen.h>5#include <stdlib.h>6#include <unistd.h>7#include <fcntl.h>8#include <poll.h>9#include <signal.h>1011#include <sys/types.h>12#include <sys/wait.h>13#include <X11/Xlib.h>1415#define die(msg) do { perror(msg); \16 exit(EXIT_FAILURE); } while (0)1718static void19chld(int num, siginfo_t *info, void *ctx)20{21 (void)num;22 (void)ctx;23 int wstatus;2425 if (waitpid(info->si_pid, &wstatus, WNOHANG) > 0)26 exit(WEXITSTATUS(wstatus));27}2829static void30evloop(int fd, pid_t chld)31{32 struct pollfd fds[1];3334 fds[0] = (struct pollfd) {35 .fd = fd,36 .events = POLLIN|POLLERR|POLLHUP,37 };3839 for (;;) {40 if (poll(fds, 1, -1) == -1) {41 if (errno == EINTR)42 continue;4344 if (kill(chld, SIGTERM) == -1)45 die("kill failed after poll failed");46 die("poll failed");47 }4849 /* From XSelectInput(3):50 * The XSelectInput function requests that the X51 * server report the events associated with the52 * specified event mask. Initially, X will not report53 * any of these events.54 *55 * Thus we should never receive new data on the file56 * descriptor. If poll(3) returns the socket was most57 * likely closed by the X server and we can terminate58 * our program.59 */60 if (kill(chld, SIGHUP) == -1)61 die("kill failed");62 exit(EXIT_SUCCESS);63 }64}6566int67main(int argc, char **argv)68{69 int fd;70 Display *dpy;71 pid_t pid;72 struct sigaction sa;7374 if (argc < 2) {75 fprintf(stderr, "Usage: %s COMMAND ...\n", basename(argv[0]));76 return EXIT_FAILURE;77 }7879 sa.sa_sigaction = chld;80 sa.sa_flags = SA_SIGINFO | SA_RESTART;81 if (sigemptyset(&sa.sa_mask) == -1)82 die("sigemptyset failed");83 if (sigaction(SIGCHLD, &sa, NULL) == -1)84 die("sigaction failed");8586 if (!(dpy = XOpenDisplay(NULL))) {87 fprintf(stderr, "Couldn't open display '%s'\n", XDisplayName(NULL));88 return EXIT_FAILURE;89 }9091 if ((fd = XConnectionNumber(dpy)) == -1) {92 fprintf(stderr, "Couldn't obtain fd for X connection\n");93 return EXIT_FAILURE;94 }9596 if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)97 die("fcntl failed");9899 switch ((pid = fork())) {100 case -1:101 die("fork failed");102 case 0:103 memmove(&argv[0], &argv[1], --argc * sizeof(char*));104 argv[argc] = (char*)NULL;105106 if (execvp(argv[0], argv) == -1)107 die("execvp failed");108 break;109 default:110 evloop(fd, pid);111 break;112 }113114 return EXIT_SUCCESS;115}