master xplshn/aruu / cmd / pseudo / respawn.c
  1/* See LICENSE file for copyright and license details. */
  2
  3#include <sys/stat.h>
  4#include <sys/time.h>
  5#include <sys/types.h>
  6#include <sys/wait.h>
  7
  8#include <errno.h>
  9#include <fcntl.h>
 10#include <poll.h>
 11#include <signal.h>
 12#include <stdio.h>
 13#include <stdlib.h>
 14#include <unistd.h>
 15
 16#include "util.h"
 17#include "wexec.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  {
 51    // ?man -d:num: specify directory
 52    case 'd':
 53      delay = estrtol(EARGF(usage()), 0);
 54      break;
 55    // ?man -l:str: list in long format
 56    case 'l':
 57      fifo = EARGF(usage());
 58      break;
 59    default:
 60      usage();
 61  }
 62  ARGEND;
 63
 64  if (argc < 1)
 65    usage();
 66
 67  if (fifo && delay > 0)
 68    usage();
 69
 70  setsid();
 71
 72  signal(SIGTERM, sigterm);
 73
 74  if (fifo) {
 75    pollset->fd = open(fifo, O_RDONLY | O_NONBLOCK);
 76    if (pollset->fd < 0)
 77      eprintf("open %s:", fifo);
 78    pollset->events = POLLIN;
 79  }
 80
 81  while (1) {
 82    if (fifo) {
 83      pollset->revents = 0;
 84      polln            = poll(pollset, 1, -1);
 85      if (polln <= 0) {
 86        if (polln == 0 || errno == EAGAIN)
 87          continue;
 88        eprintf("poll:");
 89      }
 90      while ((n = read(pollset->fd, buf, sizeof(buf))) > 0)
 91        ;
 92      if (n < 0)
 93        if (errno != EAGAIN)
 94          eprintf("read %s:", fifo);
 95      if (n == 0) {
 96        close(pollset->fd);
 97        pollset->fd = open(fifo, O_RDONLY | O_NONBLOCK);
 98        if (pollset->fd < 0)
 99          eprintf("open %s:", fifo);
100        pollset->events = POLLIN;
101      }
102    }
103    pid = fork();
104    if (pid < 0)
105      eprintf("fork:");
106    switch (pid) {
107      case 0:
108        wexecvp_self(argv[0], argv);
109        savederrno = errno;
110        weprintf("wexecvp %s:", argv[0]);
111        _exit(savederrno == ENOENT ? 127 : 126);
112        break;
113      default:
114        waitpid(pid, NULL, 0);
115        break;
116    }
117    if (!fifo)
118      sleep(delay);
119  }
120  /* not reachable */
121  return 0;
122}