From 0fd708b8f1ffd099d092c02af28c79101ca58524 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Mon, 11 Jul 2016 14:58:50 +0200 Subject: Place in background unless -f MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- src/gammad.c | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++++------ src/util.c | 37 +++++++++++++++++ src/util.h | 12 ++++++ 3 files changed, 170 insertions(+), 12 deletions(-) diff --git a/src/gammad.c b/src/gammad.c index eef65b7..6fb2076 100644 --- a/src/gammad.c +++ b/src/gammad.c @@ -25,6 +25,7 @@ #include #include #include +#include #include "arg.h" #include "output.h" @@ -238,7 +239,7 @@ static int is_pidfile_reusable(const char* pidfile, const char* token) { if (++tries > 1) goto bad; - usleep(100000); /* 1 tenth of a second */ + usleep(100000); /* 1 tenth of a second */ /* TODO replace with nanosleep */ goto retry; } @@ -373,7 +374,7 @@ static void usage(void) /** - * Must not be started without stdout or stderr (may be /dev/null) + * Must not be started without stdin, stdout, or stderr (may be /dev/null) * * The process closes stdout when the socket has been created * @@ -383,7 +384,8 @@ static void usage(void) */ int main(int argc, char** argv) { - int method = -1, gerror, rc = 1, preserve = 0, r; + int method = -1, gerror, rc = 1, preserve = 0, foreground = 0, r; + int keep_stderr = 0; char* sitename = NULL; libgamma_site_state_t site; libgamma_partition_state_t* partitions = NULL; @@ -391,6 +393,7 @@ int main(int argc, char** argv) size_t i, j, n, n0; char* pidpath = NULL; char* socketpath = NULL; + sigset_t mask; memset(&site, 0, sizeof(site)); @@ -407,6 +410,12 @@ int main(int argc, char** argv) case 'p': preserve = 1; break; + case 'f': + foreground = 1; + break; + case 'k': + keep_stderr = 1; + break; default: usage(); } @@ -414,6 +423,17 @@ int main(int argc, char** argv) if (argc > 0) usage(); + /* TODO Close all file descriptors above stderr */ + + /* Set umask, reset signal handlers, and reset signal mask */ + umask(0); + for (r = 1; r < _NSIG; r++) + signal(r, SIG_DFL); + if (sigfillset(&mask)) + perror(argv0); + else + sigprocmask(SIG_UNBLOCK, &mask, NULL); + /* Get method */ if ((method < 0) && (libgamma_list_methods(&method, 1, 0) < 1)) return fprintf(stderr, "%s: no adjustment method available\n", argv0), 1; @@ -436,15 +456,6 @@ int main(int argc, char** argv) goto fail; } - /* TODO socket */ - - /* Signal the spawner that the service is ready */ - close(STDOUT_FILENO); - /* Avoid potential catastrophes that would occur if a library that is being - * used was so mindless as to write to stdout. */ - if (dup2(STDERR_FILENO, STDOUT_FILENO) < 0) - perror(argv0); - /* Get partitions */ if (site.partitions_available) if (!(partitions = calloc(site.partitions_available, sizeof(*partitions)))) @@ -577,6 +588,104 @@ int main(int argc, char** argv) goto fail; } + /* TODO socket */ + + /* Change directory to / to avoid blocking umounting. */ + if (chdir("/") < 0) + perror(argv0); + + /* Place in the background unless -f */ + if (foreground == 0) + { + pid_t pid; + int fd = -1, saved_errno; + int notify_rw[2] = { -1, -1 }; + char a_byte = 0; + ssize_t got; + + if (pipe(notify_rw) < 0) + goto fail; + if (notify_rw[0] <= STDERR_FILENO) + if ((notify_rw[0] = dup2atleast(notify_rw[0], STDERR_FILENO + 1)) < 0) + goto fail_background; + if (notify_rw[1] <= STDERR_FILENO) + if ((notify_rw[1] = dup2atleast(notify_rw[1], STDERR_FILENO + 1)) < 0) + goto fail_background; + + switch ((pid = fork())) + { + case -1: + goto fail_background; + case 0: + /* Child */ + close(notify_rw[0]), notify_rw[0] = -1; + if (setsid() < 0) + goto fail_background; + switch ((pid = fork())) + { + case -1: + goto fail_background; + case 0: + /* Replace std* with /dev/null */ + fd = open("/dev/null", O_RDWR); + if (fd < 0) + goto fail; +#define xdup2(s, d) do if (s != d) { close(d); if (dup2(s, d) < 0) goto fail; } while (0) + xdup2(fd, STDIN_FILENO); + xdup2(fd, STDOUT_FILENO); + if (keep_stderr) + xdup2(fd, STDERR_FILENO); + if (fd > STDERR_FILENO) + close(fd); + fd = -1; + + /* Update PID file */ + fd = open(pidpath, O_WRONLY); + if (fd < 0) + goto fail_background; + if (dprintf(fd, "%llu\n", (unsigned long long)getpid()) < 0) + goto fail_background; + close(fd), fd = -1; + + /* Notify */ + if (write(notify_rw[1], &a_byte, 1) <= 0) + goto fail_background; + close(notify_rw[1]); + break; + default: + /* Parent */ + return 0; + } + break; + default: + /* Parent */ + close(notify_rw[1]), notify_rw[1] = -1; + got = read(notify_rw[0], &a_byte, 1); + if (got < 0) + goto fail_background; + close(notify_rw[0]); + return got == 0; + } + + goto done_background; + fail_background: + saved_errno = errno; + if (fd >= 0) close(fd); + if (notify_rw[0] >= 0) close(notify_rw[0]); + if (notify_rw[1] >= 0) close(notify_rw[1]); + errno = saved_errno; + done_background:; + } + else + { + /* Signal the spawner that the service is ready */ + close(STDOUT_FILENO); + /* Avoid potential catastrophes that would occur if a library that is being + * used was so mindless as to write to stdout. */ + if (dup2(STDERR_FILENO, STDOUT_FILENO) < 0) + perror(argv0); + } + /* Done */ rc = 0; done: diff --git a/src/util.c b/src/util.c index cb8c155..715aa6b 100644 --- a/src/util.c +++ b/src/util.c @@ -96,3 +96,40 @@ void* nread(int fd, size_t* n) return NULL; } + +/** + * Duplicate a file descriptor an make sure + * the new file descriptor's index as a + * specified minimum value + * + * @param fd The file descriptor + * @param atleast The least acceptable new file descriptor + * @return The new file descriptor, -1 on error + */ +int dup2atleast(int fd, int atleast) +{ + int* stack = malloc((size_t)(atleast + 1) * sizeof(int)); + size_t stack_ptr = 0; + int new = -1, saved_errno; + + if (stack == NULL) + goto fail; + + for (;;) + { + new = dup(fd); + if (new < 0) + goto fail; + if (new >= atleast) + break; + } + + fail: + saved_errno = errno; + while (stack_ptr--) + close(stack[stack_ptr]); + free(stack); + errno = saved_errno; + return new; +} + diff --git a/src/util.h b/src/util.h index c44164b..25c1a71 100644 --- a/src/util.h +++ b/src/util.h @@ -40,3 +40,15 @@ void* memdup(const void* src, size_t n); */ void* nread(int fd, size_t* n); + +/** + * Duplicate a file descriptor an make sure + * the new file descriptor's index as a + * specified minimum value + * + * @param fd The file descriptor + * @param atleast The least acceptable new file descriptor + * @return The new file descriptor, -1 on error + */ +int dup2atleast(int fd, int atleast); + -- cgit v1.2.3-70-g09d2