diff options
Diffstat (limited to '')
-rw-r--r-- | daemon.c | 113 |
1 files changed, 111 insertions, 2 deletions
diff --git a/daemon.c b/daemon.c index 3dc0640..cd12f92 100644 --- a/daemon.c +++ b/daemon.c @@ -20,6 +20,7 @@ #include <grp.h> #include <poll.h> #include <pwd.h> +#include <signal.h> #include <stdarg.h> #include <stdbool.h> #include <stdint.h> @@ -27,7 +28,9 @@ #include <stdlib.h> #include <string.h> #include <sys/stat.h> +#include <sys/time.h> #include <sys/timespec.h> +#include <sys/wait.h> #include <sysexits.h> #include <syslog.h> #include <unistd.h> @@ -47,6 +50,11 @@ struct timespec restartInterval = { .tv_sec = 1 }; struct Set256 stopExits; +static volatile sig_atomic_t signals[NSIG]; +static void signalHandler(int signal) { + signals[signal]++; +} + static void configerr(bool exit, const char *format, ...) { va_list ap; va_start(ap, format); @@ -219,10 +227,111 @@ int main(int argc, char *argv[]) { if (len < 0) syslog(LOG_WARNING, "%s: %m", pidPath); } - // TODO: Main loop. - + signal(SIGHUP, signalHandler); + signal(SIGINT, signalHandler); + signal(SIGTERM, signalHandler); + signal(SIGCHLD, signalHandler); + signal(SIGINFO, signalHandler); + + for (size_t i = 0; i < services.len; ++i) { + serviceStart(&services.ptr[i]); + } + + // TODO: setproctitle to number of services currently running. + + sigset_t mask; + sigemptyset(&mask); + for (;;) { + struct pollfd fds[1 + 2 * services.len]; + fds[0].fd = fifo; + fds[0].events = POLLIN; + + struct timespec deadline = {0}; + for (size_t i = 0; i < services.len; ++i) { + struct Service *service = &services.ptr[i]; + + fds[1 + 2 * i].fd = service->outPipe[0]; + fds[2 + 2 * i].fd = service->errPipe[0]; + fds[1 + 2 * i].events = POLLIN; + fds[2 + 2 * i].events = POLLIN; + + if (service->intent != Start) continue; + if (service->state == Start) continue; + if ( + !timespecisset(&deadline) || + timespeccmp(&service->restartDeadline, &deadline, <) + ) deadline = service->restartDeadline; + } + + struct timespec now = {0}; + struct timespec timeout = {0}; + if (timespecisset(&deadline)) { + clock_gettime(CLOCK_MONOTONIC_FAST, &now); + timespecsub(&deadline, &now, &timeout); + } + if (timeout.tv_sec < 0 || timeout.tv_nsec < 0) { + timespecclear(&timeout); + } + + int nfds = ppoll( + fds, 1 + 2 * services.len, + (timespecisset(&deadline) ? &timeout : NULL), + &mask + ); + + // TODO: Handle FIFO and pipes. + + clock_gettime(CLOCK_MONOTONIC_FAST, &now); + for (size_t i = 0; i < services.len; ++i) { + struct Service *service = &services.ptr[i]; + if (service->intent != Start) continue; + if (service->state == Start) continue; + if (timespeccmp(&service->restartDeadline, &now, <=)) { + serviceStart(service); + } + } + + if (signals[SIGCHLD]) { + int status; + pid_t pid; + while (0 < (pid = waitpid(-1, &status, WNOHANG))) { + serviceReap(pid, status); + } + if (pid < 0 && errno != ECHILD) syslog(LOG_ERR, "waitpid: %m"); + signals[SIGCHLD] = 0; + } + + if (signals[SIGINT] || signals[SIGTERM]) { + break; + } + if (signals[SIGHUP]) { + parseConfig(false, configPath); + signals[SIGHUP] = 0; + } + if (signals[SIGINFO]) { + // TODO: status * + signals[SIGINFO] = 0; + } + } + close(fifo); unlink(fifoPath); + + size_t count = 0; + for (size_t i = 0; i < services.len; ++i) { + serviceStop(&services.ptr[i]); + if (services.ptr[i].state == Start) count++; + } + while (count--) { + int status; + pid_t pid = wait(&status); + if (pid < 0) { + syslog(LOG_ERR, "wait: %m"); + continue; + } + serviceReap(pid, status); + } + if (pidPath) { close(pidFile); unlink(pidPath); |