#include #include #include #include #include #include #include #include #include #include #include #include #include #include "status.h" char *const run_path[] = { "./run", NULL }; void start_proc() { pid_t p = fork(); if (p == 0) { execv(run_path[0], run_path); } else if (p > 0) { waitpid(p, NULL, 0); } else { err(1, "fork()"); } } int acquire_lock() { int lock_fd; if ((lock_fd = open("supervise/lock", O_CREAT | O_TRUNC | O_RDONLY, 0600)) == -1) err(1, "open()"); if (flock(lock_fd, LOCK_EX | LOCK_NB) == -1) { if (errno == EWOULDBLOCK) { fprintf(stderr, "Could not acquire lock\n"); exit(1); } else { err(1, "flock()"); } } return lock_fd; } void update_status() { int fd, r; unsigned char status[18]; if ((fd = open("supervise/status.new", O_CREAT | O_TRUNC | O_WRONLY | 0644)) == -1) { perror("open()"); return; } if ((r = write(fd, status, sizeof(status))) == -1) perror("write()"); if (close(fd) == -1) perror("close()"); if (r < sizeof(status)) { fprintf(stderr, "Failed to fully write status.new\n"); if (unlink("supervise/status.new") == -1) perror("unlink()"); return; } if (rename("supervise/status.new", "supervise/status") == -1) perror("rename()"); } void setup_signals() { struct sigaction act; memset(&act, 0, sizeof(act)); act.sa_handler = SIG_IGN; if (sigaction(SIGHUP, &act, NULL) == -1) err(1, "sigaction()"); if (sigaction(SIGINT, &act, NULL) == -1) err(1, "sigaction()"); if (sigaction(SIGTERM, &act, NULL) == -1) err(1, "sigaction()"); } void reset_signals() { struct sigaction act; memset(&act, 0, sizeof(act)); act.sa_handler = SIG_DFL; if (sigaction(SIGHUP, &act, NULL) == -1) err(1, "sigaction()"); if (sigaction(SIGINT, &act, NULL) == -1) err(1, "sigaction()"); if (sigaction(SIGTERM, &act, NULL) == -1) err(1, "sigaction()"); } int main(int argc, char **argv) { int ctrl_fd, ok_fd, lock_fd, kq; struct kevent evt[6], revt[6]; if (argc != 2) errx(1, "Usage: %s \n", argv[0]); if (chdir(argv[1]) == -1) err(1, "chdir()"); if (mkdir("supervise", 0700) == -1 && errno != EEXIST) err(1, "mkdir()"); lock_fd = acquire_lock(); if (mkfifo("supervise/control", 0600) == -1 && errno != EEXIST) err(1, "mkfifo()"); if (mkfifo("supervise/ok", 0600) == -1 && errno != EEXIST) err(1, "mkfifo()"); setup_signals(); kq = kqueue(); if (kq == -1) err(1, "kqueue()"); if ((ctrl_fd = open("supervise/control", O_RDONLY | O_NONBLOCK | O_CLOEXEC)) == -1) err(1, "open()"); if ((ok_fd = open("supervise/ok", O_RDONLY | O_NONBLOCK | O_CLOEXEC)) == -1) err(1, "open()"); EV_SET(&evt[0], SIGHUP, EVFILT_SIGNAL, EV_ADD | EV_ENABLE, 0, 0, 0); EV_SET(&evt[1], SIGINT, EVFILT_SIGNAL, EV_ADD | EV_ENABLE, 0, 0, 0); EV_SET(&evt[2], SIGTERM, EVFILT_SIGNAL, EV_ADD | EV_ENABLE, 0, 0, 0); EV_SET(&evt[3], SIGCHLD, EVFILT_SIGNAL, EV_ADD | EV_ENABLE, 0, 0, 0); EV_SET(&evt[4], ctrl_fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0); //EV_SET(&evt[5], ok_fd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, 0); if (kevent(kq, evt, 5, NULL, 0, NULL) == -1) err(1, "kevent()"); for (;;) { start_proc(); break; kevent(kq, NULL, 0, revt, 5, NULL); } if (close(ctrl_fd) == -1) perror("close()"); if (close(lock_fd) == -1) perror("close()"); reset_signals(); return 0; }