From c8f09036fbdcf6f71e5ab081ef33c2ec0ff71b33 Mon Sep 17 00:00:00 2001 From: Marius Halden Date: Sun, 29 Nov 2015 21:41:30 +0100 Subject: Rename scan.c and supervise.c --- Makefile | 8 +- scan.c | 488 --------------------------------------------------------- supervise.c | 104 ------------ svcscan.c | 488 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ svcsupervise.c | 104 ++++++++++++ 5 files changed, 596 insertions(+), 596 deletions(-) delete mode 100644 scan.c delete mode 100644 supervise.c create mode 100644 svcscan.c create mode 100644 svcsupervise.c diff --git a/Makefile b/Makefile index f4be2ba..81cdd2a 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ -scan: scan.c - ${CC} -o scan -Wall -Werror -pedantic scan.c +svcscan: svcscan.c + ${CC} -o svcscan -Wall -Werror -pedantic svcscan.c -supervise: supervise.c - ${CC} -o supervise -Wall -Werror -pedantic supervise.c +svcsupervise: svcsupervise.c + ${CC} -o svcsupervise -Wall -Werror -pedantic svcsupervise.c diff --git a/scan.c b/scan.c deleted file mode 100644 index 8e92a68..0000000 --- a/scan.c +++ /dev/null @@ -1,488 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -char *supdir = "/home/marius/r/svc"; -char *super_path[] = { "/home/marius/r/supervise", NULL, NULL }; - -struct svc { - char dir[MAXNAMLEN + 1]; - pid_t supervisor; - - TAILQ_ENTRY(svc) entries; -}; - -TAILQ_HEAD(svcrunlist, svc) services = TAILQ_HEAD_INITIALIZER(services); -TAILQ_HEAD(svcnorunlist, svc) svc_norun = TAILQ_HEAD_INITIALIZER(svc_norun); - -struct svc * -find_svc_sup(pid_t p) -{ - struct svc *np; - - TAILQ_FOREACH(np, &services, entries) { - if (np->supervisor == p) - return np; - } - - return NULL; -} - -struct svc * -find_run_svc_dir(const char *dir) -{ - struct svc *np; - TAILQ_FOREACH(np, &services, entries) { - if (strcmp(np->dir, dir) == 0) - return np; - } - - return NULL; -} - -struct svc * -find_norun_svc_dir(const char *dir) -{ - struct svc *np; - TAILQ_FOREACH(np, &svc_norun, entries) { - if (strcmp(np->dir, dir) == 0) - return np; - } - - return NULL; -} - -struct svc * -find_svc_dir(const char *dir) -{ - struct svc *tmp; - - tmp = find_run_svc_dir(dir); - if (tmp != NULL) - return tmp; - - tmp = find_norun_svc_dir(dir); - return tmp; -} - -void -move_norun(struct svc *service) -{ - TAILQ_REMOVE(&services, service, entries); - TAILQ_INSERT_TAIL(&svc_norun, service, entries); -} - -void -move_run(struct svc *service) -{ - TAILQ_REMOVE(&svc_norun, service, entries); - TAILQ_INSERT_TAIL(&services, service, entries); -} - -void -remove_svc_norun(struct svc *service) -{ - TAILQ_REMOVE(&svc_norun, service, entries); - - if (service->supervisor != -1) - fprintf(stderr, "Removed service (%s) with pid (%d) for supervisor\n", service->dir, service->supervisor); - - free(service); -} - -int -direxists(const char *dir) -{ - int r = 0; - struct stat sb; - char *path; - - if ((asprintf(&path, "%s/%s", supdir, dir)) == -1 || path == NULL) - err(1, "asprintf()"); - - if (stat(path, &sb) != -1) { - if (S_ISDIR(sb.st_mode)) - r = 1; - } else { - if (errno != ENOENT) - perror("stat()"); - } - - free(path); - - return r; -} - -void -start_supervisor(struct svc *service) -{ - char *path; - if ((asprintf(&path, "%s/%s", supdir, service->dir)) == -1 || - path == NULL) - err(1, "asprintf()"); - - pid_t p = fork(); - if (p == 0) { /* Child */ - setsid(); - - super_path[1] = path; - - if (execv(super_path[0], super_path)) - err(1, "execv()"); - } else if (p > 0) { /* Parent */ - service->supervisor = p; - } else { - err(1, "fork()"); - } - - free(path); -} - -void -start_dead() -{ - struct svc *np, *tmp; - - TAILQ_FOREACH_SAFE(np, &svc_norun, entries, tmp) { - if (!direxists(np->dir)) { - remove_svc_norun(np); - continue; - } - - start_supervisor(np); - - move_run(np); - } -} - -void -add_missing_svc(const char *name) -{ - struct svc *tmp; - - tmp = find_svc_dir(name); - if (tmp != NULL) - return; /* We already have it */ - - tmp = malloc(sizeof(struct svc)); - if (tmp == NULL) - err(1, "malloc()"); - - if (strlcpy(tmp->dir, name, (MAXNAMLEN + 1)) >= (MAXNAMLEN + 1)) - errx(1, "strlcpy()"); - - tmp->supervisor = -1; - - TAILQ_INSERT_TAIL(&svc_norun, tmp, entries); -} - -void -scan_svcdir(int dir_fd) -{ - DIR *dir; - struct dirent *dp; - - if ((dir = fdopendir(dir_fd)) == NULL) - err(1, "opendir()"); - - while ((dp = readdir(dir)) != NULL) { - if (dp->d_type != DT_DIR) - continue; - if (dp->d_name[0] == '.') - continue; - - add_missing_svc(dp->d_name); - } - - rewinddir(dir); - - if (fdclosedir(dir) == -1) - err(1, "closedir()"); -} - -void -reap_all() -{ - int r, m = 0; - - for (;;) { - r = waitpid(-1, NULL, WNOHANG); - - if (r == 0) { - m++; - if (m >= 3) - break; - sleep(1); - } - - if (r == -1) { - if (errno == EINTR) - continue; - if (errno != ECHILD) - perror("waitpid()"); - break; - } - } -} - -int -try_wait() -{ - int p, s, r = 0; - for (;;) { - struct svc *tmp; - - p = waitpid(-1, &s, WNOHANG); - if (p == 0) - break; - if (p == -1) { - if (errno == EINTR) /* Impossible? */ - continue; - if (errno != ECHILD) - perror("waitpid()"); - break; - } - - r = 1; - - tmp = find_svc_sup(p); - if (tmp == NULL) - continue; /* XXX: Log something here? */ - - tmp->supervisor = -1; - move_norun(tmp); - } - - return r; -} - -int -acquire_lock() -{ - int lock_fd; - char *lock_path; - - if (asprintf(&lock_path, "%s/lock", supdir) == -1 || lock_path == NULL) - err(1, "asprintf()"); - - if ((lock_fd = open(lock_path, O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC, 0644)) == -1) - err(1, "open()"); - - if (flock(lock_fd, LOCK_EX | LOCK_NB) == -1) { - if (errno == EWOULDBLOCK) { - fprintf(stderr, "%s is locked\n", lock_path); - exit(1); - } else { - err(1, "flock()"); - } - } - - free(lock_path); - - return lock_fd; -} - -void -signal_existing(int dir_fd) -{ - DIR *dir; - struct dirent *dp; - char *ctrl_path, *lock_path; - int ctrl_fd, lock_fd; - sigset_t mask; - - sigemptyset(&mask); - sigaddset(&mask, SIGPIPE); - - dir = fdopendir(dir_fd); - - while ((dp = readdir(dir)) != NULL) { - if (dp->d_type != DT_DIR) - continue; - if (dp->d_name[0] == '.') - continue; - - if (asprintf(&ctrl_path, "%s/supervise/control", dp->d_name) == -1 || ctrl_path == NULL) - err(1, "asprintf()"); - if (asprintf(&lock_path, "%s/supervise/lock", dp->d_name) == -1 || lock_path == NULL) - err(1, "asprintf()"); - - if ((lock_fd = open(lock_path, O_RDONLY | O_NONBLOCK | O_CLOEXEC)) == -1) - err(1, "open()"); - - if (flock(lock_fd, LOCK_EX | LOCK_NB) == -1) { - if (errno == EWOULDBLOCK) { - if ((ctrl_fd = open(ctrl_path, O_WRONLY | O_CLOEXEC)) == -1) - err(1, "open()"); - - if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) - err(1, "setprocmask()"); - - if (write(ctrl_fd, "x", 1) != 1) { - if (errno != EPIPE) - err(1, "write()"); - } - - if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1) - err(1, "setprocmask()"); - - if (close(ctrl_fd) == -1) - err(1, "close()"); - } else { - err(1, "flock()"); - } - } - - if (close(lock_fd) == -1) - err(1, "flock()"); - - free(lock_path); - free(ctrl_path); - } - - rewinddir(dir); - - if (fdclosedir(dir) == -1) - err(1, "fdclosedir()"); -} - -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 kq, dir_fd, lock_fd, e, i; - struct kevent evt[6], revt[6]; - struct procctl_reaper_kill rk; - struct procctl_reaper_status rs; - pid_t mypid = getpid(); - - if (argc > 1) - supdir = argv[1]; - - if (chdir(supdir) == -1) - err(1, "chdir()"); - - lock_fd = acquire_lock(); - - setup_signals(); - - if (procctl(P_PID, mypid, PROC_REAP_ACQUIRE, NULL) == -1) - err(1, "procctl()"); - - dir_fd = open(supdir, O_RDONLY | O_DIRECTORY | O_CLOEXEC); - if (dir_fd == -1) - err(1, "open()"); - - kq = kqueue(); - if (kq == -1) - err(1, "kqueue()"); - - EV_SET(&evt[0], dir_fd, EVFILT_VNODE, EV_ADD | EV_ENABLE, NOTE_WRITE | NOTE_EXTEND, 0, 0); - EV_SET(&evt[1], SIGHUP, EVFILT_SIGNAL, EV_ADD | EV_ENABLE | EV_CLEAR, 0, 0, 0); - EV_SET(&evt[2], SIGINT, EVFILT_SIGNAL, EV_ADD | EV_ENABLE | EV_CLEAR, 0, 0, 0); - EV_SET(&evt[3], SIGTERM, EVFILT_SIGNAL, EV_ADD | EV_ENABLE | EV_CLEAR, 0, 0, 0); - EV_SET(&evt[4], SIGCHLD, EVFILT_SIGNAL, EV_ADD | EV_ENABLE | EV_CLEAR, 0, 0, 0); - EV_SET(&evt[5], 1, EVFILT_TIMER, EV_ADD | EV_ENABLE | EV_ONESHOT, NOTE_SECONDS, 5, 0); - - if (kevent(kq, evt, 5, NULL, 0, NULL) == -1) - err(1, "kevent()"); - - scan_svcdir(dir_fd); - start_dead(); - - for (;;) { - if ((e = kevent(kq, NULL, 0, revt, 6, NULL)) == -1) { - if (errno != EINTR) - perror("kevent()"); - } else if (e > 0) { - for (i = 0; i < e; i++) { - if (revt[i].filter == EVFILT_VNODE && revt[i].ident == dir_fd) { - scan_svcdir(dir_fd); - } else if (revt[i].filter == EVFILT_SIGNAL) { - if (revt[i].ident == SIGCHLD) { - if (try_wait()) { - if (kevent(kq, &evt[5], 1, NULL, 0, NULL) == -1) - perror("kevent()"); - } - } - if (revt[i].ident == SIGHUP || revt[i].ident == SIGINT || revt[i].ident == SIGTERM) { - goto end; - } - } else if (revt[i].filter == EVFILT_TIMER && revt[i].ident == 1) { - start_dead(); - } else { - fprintf(stderr, "Unknown event\n"); - } - } - } - } - -end: - if (procctl(P_PID, mypid, PROC_REAP_STATUS, &rs) != -1) { - if (rs.rs_children > 0) { - rk.rk_sig = SIGTERM; - rk.rk_flags = REAPER_KILL_CHILDREN; - if (procctl(P_PID, mypid, PROC_REAP_KILL, &rk)) - perror("procctl()"); - } - } else { - perror("procctl()"); - } - - if (close(kq) == -1) - perror("close()"); - if (close(dir_fd) == -1) - perror("close()"); - if (close(lock_fd) == -1) - perror("close()"); - - reset_signals(); - - fprintf(stderr, "Waiting for children to exit\n"); - reap_all(); - - return 0; -} diff --git a/supervise.c b/supervise.c deleted file mode 100644 index 95ede21..0000000 --- a/supervise.c +++ /dev/null @@ -1,104 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -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()"); -} - -int -main(int argc, char **argv) -{ - int lock_fd; - - 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()"); - - start_proc(); /* XXX: Main loop goes here */ - - if (close(lock_fd) == -1) - perror("close()"); - - return 0; -} diff --git a/svcscan.c b/svcscan.c new file mode 100644 index 0000000..1de5b46 --- /dev/null +++ b/svcscan.c @@ -0,0 +1,488 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char *supdir = "/home/marius/r/svc"; +char *super_path[] = { "/home/marius/r/svcsupervise", NULL, NULL }; + +struct svc { + char dir[MAXNAMLEN + 1]; + pid_t supervisor; + + TAILQ_ENTRY(svc) entries; +}; + +TAILQ_HEAD(svcrunlist, svc) services = TAILQ_HEAD_INITIALIZER(services); +TAILQ_HEAD(svcnorunlist, svc) svc_norun = TAILQ_HEAD_INITIALIZER(svc_norun); + +struct svc * +find_svc_sup(pid_t p) +{ + struct svc *np; + + TAILQ_FOREACH(np, &services, entries) { + if (np->supervisor == p) + return np; + } + + return NULL; +} + +struct svc * +find_run_svc_dir(const char *dir) +{ + struct svc *np; + TAILQ_FOREACH(np, &services, entries) { + if (strcmp(np->dir, dir) == 0) + return np; + } + + return NULL; +} + +struct svc * +find_norun_svc_dir(const char *dir) +{ + struct svc *np; + TAILQ_FOREACH(np, &svc_norun, entries) { + if (strcmp(np->dir, dir) == 0) + return np; + } + + return NULL; +} + +struct svc * +find_svc_dir(const char *dir) +{ + struct svc *tmp; + + tmp = find_run_svc_dir(dir); + if (tmp != NULL) + return tmp; + + tmp = find_norun_svc_dir(dir); + return tmp; +} + +void +move_norun(struct svc *service) +{ + TAILQ_REMOVE(&services, service, entries); + TAILQ_INSERT_TAIL(&svc_norun, service, entries); +} + +void +move_run(struct svc *service) +{ + TAILQ_REMOVE(&svc_norun, service, entries); + TAILQ_INSERT_TAIL(&services, service, entries); +} + +void +remove_svc_norun(struct svc *service) +{ + TAILQ_REMOVE(&svc_norun, service, entries); + + if (service->supervisor != -1) + fprintf(stderr, "Removed service (%s) with pid (%d) for supervisor\n", service->dir, service->supervisor); + + free(service); +} + +int +direxists(const char *dir) +{ + int r = 0; + struct stat sb; + char *path; + + if ((asprintf(&path, "%s/%s", supdir, dir)) == -1 || path == NULL) + err(1, "asprintf()"); + + if (stat(path, &sb) != -1) { + if (S_ISDIR(sb.st_mode)) + r = 1; + } else { + if (errno != ENOENT) + perror("stat()"); + } + + free(path); + + return r; +} + +void +start_supervisor(struct svc *service) +{ + char *path; + if ((asprintf(&path, "%s/%s", supdir, service->dir)) == -1 || + path == NULL) + err(1, "asprintf()"); + + pid_t p = fork(); + if (p == 0) { /* Child */ + setsid(); + + super_path[1] = path; + + if (execv(super_path[0], super_path)) + err(1, "execv()"); + } else if (p > 0) { /* Parent */ + service->supervisor = p; + } else { + err(1, "fork()"); + } + + free(path); +} + +void +start_dead() +{ + struct svc *np, *tmp; + + TAILQ_FOREACH_SAFE(np, &svc_norun, entries, tmp) { + if (!direxists(np->dir)) { + remove_svc_norun(np); + continue; + } + + start_supervisor(np); + + move_run(np); + } +} + +void +add_missing_svc(const char *name) +{ + struct svc *tmp; + + tmp = find_svc_dir(name); + if (tmp != NULL) + return; /* We already have it */ + + tmp = malloc(sizeof(struct svc)); + if (tmp == NULL) + err(1, "malloc()"); + + if (strlcpy(tmp->dir, name, (MAXNAMLEN + 1)) >= (MAXNAMLEN + 1)) + errx(1, "strlcpy()"); + + tmp->supervisor = -1; + + TAILQ_INSERT_TAIL(&svc_norun, tmp, entries); +} + +void +scan_svcdir(int dir_fd) +{ + DIR *dir; + struct dirent *dp; + + if ((dir = fdopendir(dir_fd)) == NULL) + err(1, "opendir()"); + + while ((dp = readdir(dir)) != NULL) { + if (dp->d_type != DT_DIR) + continue; + if (dp->d_name[0] == '.') + continue; + + add_missing_svc(dp->d_name); + } + + rewinddir(dir); + + if (fdclosedir(dir) == -1) + err(1, "closedir()"); +} + +void +reap_all() +{ + int r, m = 0; + + for (;;) { + r = waitpid(-1, NULL, WNOHANG); + + if (r == 0) { + m++; + if (m >= 3) + break; + sleep(1); + } + + if (r == -1) { + if (errno == EINTR) + continue; + if (errno != ECHILD) + perror("waitpid()"); + break; + } + } +} + +int +try_wait() +{ + int p, s, r = 0; + for (;;) { + struct svc *tmp; + + p = waitpid(-1, &s, WNOHANG); + if (p == 0) + break; + if (p == -1) { + if (errno == EINTR) /* Impossible? */ + continue; + if (errno != ECHILD) + perror("waitpid()"); + break; + } + + r = 1; + + tmp = find_svc_sup(p); + if (tmp == NULL) + continue; /* XXX: Log something here? */ + + tmp->supervisor = -1; + move_norun(tmp); + } + + return r; +} + +int +acquire_lock() +{ + int lock_fd; + char *lock_path; + + if (asprintf(&lock_path, "%s/lock", supdir) == -1 || lock_path == NULL) + err(1, "asprintf()"); + + if ((lock_fd = open(lock_path, O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC, 0644)) == -1) + err(1, "open()"); + + if (flock(lock_fd, LOCK_EX | LOCK_NB) == -1) { + if (errno == EWOULDBLOCK) { + fprintf(stderr, "%s is locked\n", lock_path); + exit(1); + } else { + err(1, "flock()"); + } + } + + free(lock_path); + + return lock_fd; +} + +void +signal_existing(int dir_fd) +{ + DIR *dir; + struct dirent *dp; + char *ctrl_path, *lock_path; + int ctrl_fd, lock_fd; + sigset_t mask; + + sigemptyset(&mask); + sigaddset(&mask, SIGPIPE); + + dir = fdopendir(dir_fd); + + while ((dp = readdir(dir)) != NULL) { + if (dp->d_type != DT_DIR) + continue; + if (dp->d_name[0] == '.') + continue; + + if (asprintf(&ctrl_path, "%s/supervise/control", dp->d_name) == -1 || ctrl_path == NULL) + err(1, "asprintf()"); + if (asprintf(&lock_path, "%s/supervise/lock", dp->d_name) == -1 || lock_path == NULL) + err(1, "asprintf()"); + + if ((lock_fd = open(lock_path, O_RDONLY | O_NONBLOCK | O_CLOEXEC)) == -1) + err(1, "open()"); + + if (flock(lock_fd, LOCK_EX | LOCK_NB) == -1) { + if (errno == EWOULDBLOCK) { + if ((ctrl_fd = open(ctrl_path, O_WRONLY | O_CLOEXEC)) == -1) + err(1, "open()"); + + if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) + err(1, "setprocmask()"); + + if (write(ctrl_fd, "x", 1) != 1) { + if (errno != EPIPE) + err(1, "write()"); + } + + if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1) + err(1, "setprocmask()"); + + if (close(ctrl_fd) == -1) + err(1, "close()"); + } else { + err(1, "flock()"); + } + } + + if (close(lock_fd) == -1) + err(1, "flock()"); + + free(lock_path); + free(ctrl_path); + } + + rewinddir(dir); + + if (fdclosedir(dir) == -1) + err(1, "fdclosedir()"); +} + +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 kq, dir_fd, lock_fd, e, i; + struct kevent evt[6], revt[6]; + struct procctl_reaper_kill rk; + struct procctl_reaper_status rs; + pid_t mypid = getpid(); + + if (argc > 1) + supdir = argv[1]; + + if (chdir(supdir) == -1) + err(1, "chdir()"); + + lock_fd = acquire_lock(); + + setup_signals(); + + if (procctl(P_PID, mypid, PROC_REAP_ACQUIRE, NULL) == -1) + err(1, "procctl()"); + + dir_fd = open(supdir, O_RDONLY | O_DIRECTORY | O_CLOEXEC); + if (dir_fd == -1) + err(1, "open()"); + + kq = kqueue(); + if (kq == -1) + err(1, "kqueue()"); + + EV_SET(&evt[0], dir_fd, EVFILT_VNODE, EV_ADD | EV_ENABLE, NOTE_WRITE | NOTE_EXTEND, 0, 0); + EV_SET(&evt[1], SIGHUP, EVFILT_SIGNAL, EV_ADD | EV_ENABLE | EV_CLEAR, 0, 0, 0); + EV_SET(&evt[2], SIGINT, EVFILT_SIGNAL, EV_ADD | EV_ENABLE | EV_CLEAR, 0, 0, 0); + EV_SET(&evt[3], SIGTERM, EVFILT_SIGNAL, EV_ADD | EV_ENABLE | EV_CLEAR, 0, 0, 0); + EV_SET(&evt[4], SIGCHLD, EVFILT_SIGNAL, EV_ADD | EV_ENABLE | EV_CLEAR, 0, 0, 0); + EV_SET(&evt[5], 1, EVFILT_TIMER, EV_ADD | EV_ENABLE | EV_ONESHOT, NOTE_SECONDS, 5, 0); + + if (kevent(kq, evt, 5, NULL, 0, NULL) == -1) + err(1, "kevent()"); + + scan_svcdir(dir_fd); + start_dead(); + + for (;;) { + if ((e = kevent(kq, NULL, 0, revt, 6, NULL)) == -1) { + if (errno != EINTR) + perror("kevent()"); + } else if (e > 0) { + for (i = 0; i < e; i++) { + if (revt[i].filter == EVFILT_VNODE && revt[i].ident == dir_fd) { + scan_svcdir(dir_fd); + } else if (revt[i].filter == EVFILT_SIGNAL) { + if (revt[i].ident == SIGCHLD) { + if (try_wait()) { + if (kevent(kq, &evt[5], 1, NULL, 0, NULL) == -1) + perror("kevent()"); + } + } + if (revt[i].ident == SIGHUP || revt[i].ident == SIGINT || revt[i].ident == SIGTERM) { + goto end; + } + } else if (revt[i].filter == EVFILT_TIMER && revt[i].ident == 1) { + start_dead(); + } else { + fprintf(stderr, "Unknown event\n"); + } + } + } + } + +end: + if (procctl(P_PID, mypid, PROC_REAP_STATUS, &rs) != -1) { + if (rs.rs_children > 0) { + rk.rk_sig = SIGTERM; + rk.rk_flags = REAPER_KILL_CHILDREN; + if (procctl(P_PID, mypid, PROC_REAP_KILL, &rk)) + perror("procctl()"); + } + } else { + perror("procctl()"); + } + + if (close(kq) == -1) + perror("close()"); + if (close(dir_fd) == -1) + perror("close()"); + if (close(lock_fd) == -1) + perror("close()"); + + reset_signals(); + + fprintf(stderr, "Waiting for children to exit\n"); + reap_all(); + + return 0; +} diff --git a/svcsupervise.c b/svcsupervise.c new file mode 100644 index 0000000..95ede21 --- /dev/null +++ b/svcsupervise.c @@ -0,0 +1,104 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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()"); +} + +int +main(int argc, char **argv) +{ + int lock_fd; + + 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()"); + + start_proc(); /* XXX: Main loop goes here */ + + if (close(lock_fd) == -1) + perror("close()"); + + return 0; +} -- cgit v1.2.3