master xplshn/aruu / cmd / pseudo / respawn.c
  1/* See LICENSE file for copyright and license details. */
  2
  3
  4#include <sys/stat.h>
  5#include <sys/time.h>
  6#include <sys/types.h>
  7#include <sys/wait.h>
  8
  9#include <errno.h>
 10#include <fcntl.h>
 11#include <poll.h>
 12#include <signal.h>
 13#include <stdio.h>
 14#include <stdlib.h>
 15#include <unistd.h>
 16
 17#include "util.h"
 18
 19static void
 20sigterm(int sig)
 21{
 22	if (sig == SIGTERM) {
 23		kill(0, SIGTERM);
 24		_exit(0);
 25	}
 26}
 27
 28static void
 29usage(void)
 30{
 31	eprintf("usage: %s [-l fifo] [-d N] cmd [args...]\n", argv0);
 32}
 33
 34// ?man respawn: restart command on exit
 35// ?man arguments: cmd [args...
 36// ?man run a command and restart it automatically when it exits
 37int
 38main(int argc, char *argv[])
 39{
 40	char *fifo = NULL;
 41	unsigned int delay = 0;
 42	pid_t pid;
 43	char buf[BUFSIZ];
 44	int savederrno;
 45	ssize_t n;
 46	struct pollfd pollset[1];
 47	int polln;
 48
 49	ARGBEGIN {
 50	// ?man -d:num: specify directory
 51	case 'd':
 52		delay = estrtol(EARGF(usage()), 0);
 53		break;
 54	// ?man -l:str: list in long format
 55	case 'l':
 56		fifo = EARGF(usage());
 57		break;
 58	default:
 59		usage();
 60	} ARGEND;
 61
 62	if (argc < 1)
 63		usage();
 64
 65	if (fifo && delay > 0)
 66		usage();
 67
 68	setsid();
 69
 70	signal(SIGTERM, sigterm);
 71
 72	if (fifo) {
 73		pollset->fd = open(fifo, O_RDONLY | O_NONBLOCK);
 74		if (pollset->fd < 0)
 75			eprintf("open %s:", fifo);
 76		pollset->events = POLLIN;
 77	}
 78
 79	while (1) {
 80		if (fifo) {
 81			pollset->revents = 0;
 82			polln = poll(pollset, 1, -1);
 83			if (polln <= 0) {
 84				if (polln == 0 || errno == EAGAIN)
 85					continue;
 86				eprintf("poll:");
 87			}
 88			while ((n = read(pollset->fd, buf, sizeof(buf))) > 0)
 89				;
 90			if (n < 0)
 91				if (errno != EAGAIN)
 92					eprintf("read %s:", fifo);
 93			if (n == 0) {
 94				close(pollset->fd);
 95				pollset->fd = open(fifo, O_RDONLY | O_NONBLOCK);
 96				if (pollset->fd < 0)
 97					eprintf("open %s:", fifo);
 98				pollset->events = POLLIN;
 99			}
100		}
101		pid = fork();
102		if (pid < 0)
103			eprintf("fork:");
104		switch (pid) {
105		case 0:
106			execvp(argv[0], argv);
107			savederrno = errno;
108			weprintf("execvp %s:", argv[0]);
109			_exit(savederrno == ENOENT ? 127 : 126);
110			break;
111		default:
112			waitpid(pid, NULL, 0);
113			break;
114		}
115		if (!fifo)
116			sleep(delay);
117	}
118	/* not reachable */
119	return 0;
120}