rwx

Run a programm while X is running

git clone https://git.8pit.net/rwx.git

  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>
 10
 11#include <sys/types.h>
 12#include <sys/wait.h>
 13#include <X11/Xlib.h>
 14
 15#define die(msg) do { perror(msg); \
 16	exit(EXIT_FAILURE); } while (0)
 17
 18static void
 19chld(int num, siginfo_t *info, void *ctx)
 20{
 21	(void)num;
 22	(void)ctx;
 23	int wstatus;
 24
 25	if (waitpid(info->si_pid, &wstatus, WNOHANG) > 0)
 26		exit(WEXITSTATUS(wstatus));
 27}
 28
 29static void
 30evloop(int fd, pid_t chld)
 31{
 32	struct pollfd fds[1];
 33
 34	fds[0] = (struct pollfd) {
 35		.fd = fd,
 36		.events = POLLIN|POLLERR|POLLHUP,
 37	};
 38
 39	for (;;) {
 40		if (poll(fds, 1, -1) == -1) {
 41			if (errno == EINTR)
 42				continue;
 43
 44			if (kill(chld, SIGTERM) == -1)
 45				die("kill failed after poll failed");
 46			die("poll failed");
 47		}
 48
 49		/* From XSelectInput(3):
 50		 *   The XSelectInput function requests that the X
 51		 *   server report the events associated with the
 52		 *   specified event mask. Initially, X will not report
 53		 *   any of these events.
 54		 *
 55		 * Thus we should never receive new data on the file
 56		 * descriptor. If poll(3) returns the socket was most
 57		 * likely closed by the X server and we can terminate
 58		 * our program.
 59		 */
 60		if (kill(chld, SIGHUP) == -1)
 61			die("kill failed");
 62		exit(EXIT_SUCCESS);
 63	}
 64}
 65
 66int
 67main(int argc, char **argv)
 68{
 69	int fd;
 70	Display *dpy;
 71	pid_t pid;
 72	struct sigaction sa;
 73
 74	if (argc < 2) {
 75		fprintf(stderr, "Usage: %s COMMAND ...\n", basename(argv[0]));
 76		return EXIT_FAILURE;
 77	}
 78
 79	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");
 85
 86	if (!(dpy = XOpenDisplay(NULL))) {
 87		fprintf(stderr, "Couldn't open display '%s'\n", XDisplayName(NULL));
 88		return EXIT_FAILURE;
 89	}
 90
 91	if ((fd = XConnectionNumber(dpy)) == -1) {
 92		fprintf(stderr, "Couldn't obtain fd for X connection\n");
 93		return EXIT_FAILURE;
 94	}
 95
 96	if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1)
 97		die("fcntl failed");
 98
 99	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;
105
106		if (execvp(argv[0], argv) == -1)
107			die("execvp failed");
108		break;
109	default:
110		evloop(fd, pid);
111		break;
112	}
113
114	return EXIT_SUCCESS;
115}