From f024ccfe1c22a59d89457f9b78cf230fb17ba5de Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Tue, 29 Dec 2015 20:47:17 +0100 Subject: finish satd-diminished, satd-timer to be written MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- src/README | 2 + src/daemon.h | 10 +++++ src/satd-diminished.c | 104 ++++++++++++++++++++++++++++++++++++++++---------- src/satd.c | 30 +++++++++++---- 4 files changed, 119 insertions(+), 27 deletions(-) diff --git a/src/README b/src/README index d9404d2..c77d17e 100644 --- a/src/README +++ b/src/README @@ -9,6 +9,8 @@ satd-add.c The part of satd responding to sat, satd-diminished.c fork– satd-rm.c The part of satd responding to satrm, satd-diminished.c fork–exec:s to this. satd-list.c The part of satd responding to satlist, satd-diminished.c fork–exec:s to this. satd-run.c The part of satd responding to satr, satd-diminished.c fork–exec:s to this. +satd-timer.c The part of satd responsible for running expired jobs and setting timers + to wait for new expirations, satd-diminished.c fork–exec:s to this. parse_time.[ch] Use by sat.c to parse the time argument. Only rudimentary parsing is done. diff --git a/src/daemon.h b/src/daemon.h index 7567a74..c36e314 100644 --- a/src/daemon.h +++ b/src/daemon.h @@ -45,6 +45,16 @@ */ #define STATE_FILENO 4 +/** + * The file descriptor for the CLOCK_BOOTTIME timer. + */ +#define BOOT_FILENO 5 + +/** + * The file descriptor for the CLOCK_REALTIME timer. + */ +#define REAL_FILENO 6 + /** * Command: queue a job. diff --git a/src/satd-diminished.c b/src/satd-diminished.c index e2ba0b9..059ca83 100644 --- a/src/satd-diminished.c +++ b/src/satd-diminished.c @@ -25,8 +25,11 @@ #include #include #include +#include #include #include +#include +#include @@ -38,12 +41,24 @@ */ #define DAEMON_IMAGE(name) LIBEXECDIR "/" PACKAGE "/satd-" name +/** + * The value on `timer_pid` when there is not "timer" image running. + */ +#define NO_TIMER_SPAWED -2 /* Must be negative, but not -1. */ + /** * Signal that has been received, 0 if none. */ -static volatile sig_atomic_t received_signo = 0; +static volatile sig_atomic_t received_signo = SIGCHLD; /* Forces the "timer" image to run. */ + +/** + * The PID the "timer" fork, `NO_TIMER_SPAWED` if not running. + * + * It does not matter that this is lost on a successful SIGHUP. + */ +static volatile pid_t timer_pid = NO_TIMER_SPAWED; @@ -56,8 +71,8 @@ static void sighandler(int signo) { int saved_errno = errno; - if (signo == SIGCHLD) - waitpid(-1, NULL, WNOHANG); + if ((signo == SIGCHLD) && (waitpid(-1, NULL, WNOHANG) == timer_pid)) + timer_pid = NO_TIMER_SPAWED; else received_signo = (sig_atomic_t)signo; errno = saved_errno; @@ -67,8 +82,8 @@ sighandler(int signo) /** * Spawn a libexec. * - * @param command The command to spawn. - * @param fd File descriptor to the socket. + * @param command The command to spawn, -1 for "timer". + * @param fd File descriptor to the socket, -1 iff `command` is -1. * @param argv `argv` from `main`. * @param envp `envp` from `main`. * @return 0 on success, -1 on error. @@ -77,9 +92,10 @@ static int spawn(int command, int fd, char *argv[], char *envp[]) { const char *image; + pid_t pid; fork_again: - switch (fork()) { + switch ((pid = fork())) { case -1: if (errno != EAGAIN) return -1; @@ -87,26 +103,52 @@ fork_again: goto fork_again; case 0: switch (command) { - case SAT_QUEUE: image = DAEMON_IMAGE("add"); break; - case SAT_REMOVE: image = DAEMON_IMAGE("rm"); break; - case SAT_PRINT: image = DAEMON_IMAGE("list"); break; - case SAT_RUN: image = DAEMON_IMAGE("run"); break; + case SAT_QUEUE: image = DAEMON_IMAGE("add"); break; + case SAT_REMOVE: image = DAEMON_IMAGE("rm"); break; + case SAT_PRINT: image = DAEMON_IMAGE("list"); break; + case SAT_RUN: image = DAEMON_IMAGE("run"); break; + case -1: image = DAEMON_IMAGE("timer"); break; default: fprintf(stderr, "%s: invalid command received.\n", argv[0]); goto child_fail; } - if (dup2(fd, SOCK_FILENO) != -1) - close(fd), fd = SOCK_FILENO, execve(image, argv, envp); + if (command < 0) { + close(SOCK_FILENO); + execve(image, argv, envp); + } else { + close(BOOT_FILENO), close(REAL_FILENO); + if (dup2(fd, SOCK_FILENO) != -1) + close(fd), fd = SOCK_FILENO, execve(image, argv, envp); + } perror(argv[0]); child_fail: close(fd); exit(1); default: + if (command < 0) + timer_pid = pid; return 0; } } +/** + * Determine whether a timer is set. + * + * @param fd The file descriptor of the timer. + * @return 1 if set, 0 if unset, -1 on error. + */ +static int +is_timer_set(int fd) +{ + struct itimerspec spec; + if (timerfd_gettime(fd, &spec)) + return -1; + return (spec.it_interval.tv_sec || spec.it_value.tv_sec || + spec.it_interval.tv_nsec || spec.it_value.tv_nsec); +} + + /** * The sat daemon. * @@ -120,38 +162,59 @@ fork_again: int main(int argc, char *argv[], char *envp[]) { - int fd = -1, rc = 0; - char type; + int fd = -1, rc = 0, accepted = 0, r; + unsigned char type; + fd_set fdset; + int64_t _overrun; /* Set up signal handlers. */ t (signal(SIGHUP, sighandler) == SIG_ERR); t (signal(SIGCHLD, sighandler) == SIG_ERR); /* The magnificent loop. */ -accept_again: +again: + if (accepted && (timer_pid == NO_TIMER_SPAWED)) { + t (r = is_timer_set(BOOT_FILENO), r < 0); if (r) goto not_done; + t (r = is_timer_set(REAL_FILENO), r < 0); if (r) goto not_done; + goto done; + } +not_done: if (received_signo == SIGHUP) { execve(DAEMON_IMAGE("diminished"), argv, envp); perror(argv[0]); + } else if (received_signo == SIGCHLD) { + t (spawn(-1, -1, argv, envp)); } received_signo = 0; - /* TODO run jobs */ + FD_ZERO(&fdset); + FD_SET(SOCK_FILENO, &fdset); + FD_SET(BOOT_FILENO, &fdset); + FD_SET(REAL_FILENO, &fdset); /* This is the highest one. */ + if (select(REAL_FILENO + 1, &fdset, NULL, NULL, NULL) == -1) { + t (errno != EINTR); + } + if (FD_ISSET(BOOT_FILENO, &fdset)) t (read(BOOT_FILENO, &_overrun, (size_t)8) < 8); + if (FD_ISSET(REAL_FILENO, &fdset)) t (read(REAL_FILENO, &_overrun, (size_t)8) < 8); + if (!FD_ISSET(SOCK_FILENO, &fdset)) + goto again; if (fd = accept(SOCK_FILENO, NULL, NULL), fd == -1) { switch (errno) { case ECONNABORTED: case EINTR: - goto accept_again; + goto again; default: /* Including EMFILE, ENFILE, and ENOMEM * because of potential resource leak. */ goto fail; } } - if (read(fd, &type, sizeof(char)) <= 0) + accepted = 1; + if (read(fd, &type, sizeof(type)) <= 0) perror(argv[0]); else - t (spawn(type, fd, argv, envp)); + t (spawn((int)type, fd, argv, envp)); close(fd), fd = -1; - goto accept_again; + goto again; fail: perror(argv[0]); @@ -159,6 +222,7 @@ fail: close(fd); rc = 1; done: + while (waitpid(-1, NULL, 0) > 0); unlink(argv[1]); if (!rc) unlink(argv[2]); diff --git a/src/satd.c b/src/satd.c index be50082..df2cda9 100644 --- a/src/satd.c +++ b/src/satd.c @@ -29,6 +29,7 @@ #include #include #include +#include @@ -195,8 +196,9 @@ int main(int argc, char *argv[]) { struct sockaddr_un address; - int sock = -1, state = -1, foreground = 0; + int sock = -1, state = -1, boot = -1, real = -1, foreground = 0; char *path = NULL; + struct itimerspec spec; const char *dir; /* Parse command line. */ @@ -222,17 +224,30 @@ main(int argc, char *argv[]) t (state = open(path, O_RDWR | O_CREAT /* but not O_EXCL */, S_IRWXU), state == -1); free(path), path = NULL; - /* The state fill shall be on fd STATE_FILENO. */ + /* The state file shall be on fd STATE_FILENO. */ t (dup2_and_null(state, STATE_FILENO) == -1); state = STATE_FILENO; /* Create socket. */ t (sock = create_socket(&address), sock == -1); - - /* Socket shall be on fd SOCK_FILENO. */ t (dup2_and_null(sock, SOCK_FILENO) == -1); sock = SOCK_FILENO; + /* Create CLOCK_BOOTTIME timer. */ + t (boot = timerfd_create(CLOCK_BOOTTIME, 0), boot == -1); + t (dup2_and_null(boot, BOOT_FILENO) == -1); + boot = BOOT_FILENO; + + /* Create CLOCK_REALTIME timer. */ + t (real = timerfd_create(CLOCK_REALTIME, 0), real == -1); + t (dup2_and_null(real, BOOT_FILENO) == -1); + real = BOOT_FILENO; + + /* Configure timers. */ + memset(&spec, 0, sizeof(spec)); + t (timerfd_settime(boot, TFD_TIMER_ABSTIME, &spec, NULL)); + t (timerfd_settime(real, TFD_TIMER_ABSTIME, &spec, NULL)); + /* Listen for incoming conections. */ #if SOMAXCONN < SATD_BACKLOG t (listen(sock, SOMAXCONN)); @@ -241,7 +256,7 @@ main(int argc, char *argv[]) #endif /* Daemonise. */ - t (foreground ? 0 : daemonise("satd", DAEMONISE_KEEP_FDS, sock, -1)); + t (foreground ? 0 : daemonise("satd", DAEMONISE_KEEP_FDS, 3, 4, 5, 6, -1)); /* Change to a process image without all this initialisation text. */ execl(LIBEXECDIR "/" PACKAGE "/satd-diminished", argv0, address.sun_path, NULL); @@ -254,8 +269,9 @@ fail: unlink(address.sun_path); close(sock); } - if (state >= 0) - close(state); + if (state >= 0) close(state); + if (boot >= 0) close(boot); + if (real >= 0) close(real); undaemonise(); return 1; } -- cgit v1.2.3-70-g09d2