diff options
-rw-r--r-- | scan.c | 102 |
1 files changed, 101 insertions, 1 deletions
@@ -9,12 +9,18 @@ #include <sys/types.h> #include <sys/stat.h> #include <sys/event.h> +#include <sys/file.h> #include <sys/procctl.h> #include <sys/queue.h> #include <sys/time.h> #include <sys/wait.h> #include <unistd.h> +/* + * TODO: + * - Don't start procs instantly after they die, wait some seconds first. + */ + const char supdir[] = "/home/marius/r/svc"; char *super_path[] = { "/home/marius/r/supervise", NULL, NULL }; @@ -279,12 +285,104 @@ try_wait() } 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; + sigmask_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 (setprocmask(SIG_BLOCK, &mask, NULL) == -1) + err(1, "setprocmask()"); + + if (write(ctrl_fd, "x", 1) != 1) { + if (errno != EPIPE) + err(1, "write()"); + } + + if (setprocmask(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()"); +} + +int main(int argc, char **argv) { - int kq, dir_fd; + int kq, dir_fd, lock_fd; struct kevent evt; pid_t mypid = getpid(); + lock_fd = acquire_lock(); + if (procctl(P_PID, mypid, PROC_REAP_ACQUIRE, NULL) == -1) err(1, "procctl()"); @@ -323,6 +421,8 @@ main(int argc, char **argv) perror("close()"); if (close(dir_fd) == -1) perror("close()"); + if (close(lock_fd) == -1) + perror("close()"); reset_signals(); /* Make SIGTERM/INT work again in case reap_all uses a long time. */ |