diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/daemonise.c | 406 | ||||
-rw-r--r-- | src/daemonise.h | 103 | ||||
-rw-r--r-- | src/satd.c | 2 |
3 files changed, 167 insertions, 344 deletions
diff --git a/src/daemonise.c b/src/daemonise.c index 822e0ed..be7e33e 100644 --- a/src/daemonise.c +++ b/src/daemonise.c @@ -19,7 +19,10 @@ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * - * This file is copied from <http://github.com/maandree/slibc>. + * This file is copied from <http://github.com/maandree/slibc>, + * but with unused stuff removed. It has also been slightly modified + * and changed code style (these "slight" modifications do not change + * the behaviour.) */ #define _POSIX_C_SOURCE 200809L #include "daemonise.h" @@ -36,6 +39,9 @@ #include <sys/resource.h> +#define t(...) do { if (__VA_ARGS__) goto fail; } while (0) +#define S(...) (saved_errno = errno, __VA_ARGS__, errno = saved_errno) + /** * The process's environment variables. @@ -58,31 +64,28 @@ static char* __pidfile = NULL; * * @throws Any error specified for dup(3). */ -static int dup_at_least_3(int old) +static int +dup_at_least_3(int old) { - int intermediary[3]; - int i = 0, saved_errno; - - do - { - if (old = dup(old), old == -1) - goto fail; - assert(i < 3); - if (i >= 3) - abort(); - intermediary[i++] = old; - } - while (old < 3); - i--; - - fail: - saved_errno = errno; - while (i--) - close(intermediary[i]); - errno = saved_errno; - return old; -} + int intermediary[3]; + int i = 0, saved_errno; + + do { + t (old = dup(old), old == -1); + assert(i < 3); + if (i >= 3) + abort(); + intermediary[i++] = old; + } while (old < 3); + i--; +fail: + saved_errno = errno; + while (i--) + close(intermediary[i]); + errno = saved_errno; + return old; +} /** @@ -154,39 +157,15 @@ static int dup_at_least_3(int old) * * @param name The name of the daemon. Use a hardcoded value, * not the process name. Must not be `NULL`. - * @param flags Flags to modify the behaviour of the function. - * A bitwise OR combination of the constants: - * - `DAEMONISE_NO_CLOSE` - * - `DAEMONISE_NO_SIG_DFL` - * - `DAEMONISE_KEEP_SIGMASK` - * - `DAEMONISE_KEEP_ENVIRON` - * - `DAEMONISE_KEEP_UMASK` - * - `DAEMONISE_NO_PID_FILE` - * - `DAEMONISE_KEEP_STDERR` - * - `DAEMONISE_CLOSE_STDERR` - * - `DAEMONISE_KEEP_STDIN` - * - `DAEMONISE_KEEP_STDOUT` - * - `DAEMONISE_KEEP_FDS` - * - `DAEMONISE_NEW_PID` - * @param ... Enabled if `DAEMONISE_KEEP_FDS` is used, - * do not add anything if `DAEMONISE_KEEP_FDS` - * is unused. This is a `-1`-terminated list - * of file descritors to keep open. 0, 1, and 2 - * are implied by `DAEMONISE_KEEP_STDIN`, - * `DAEMONISE_KEEP_STDOUT`, and `DAEMONISE_KEEP_STDERR`, - * respectively. All arguments are of type `int`. + * @param ... This is a `-1`-terminated list + * of file descritors to keep open. + * All arguments are of type `int`. * @return Zero on success, -1 on error. * * @throws EEXIST The PID file already exists on the system. * Unless your daemon supervisor removs old * PID files, this could mean that the daemon * has exited without removing the PID file. - * @throws EINVAL `flags` contains an unsupported bit, both - * `DAEMONISE_KEEP_STDERR` and `DAEMONISE_CLOSE_STDERR` - * are set, both `DAEMONISE_NO_PID_FILE` and - * `DAEMONISE_NEW_PID`, or both `DAEMONISE_CLOSE_STDERR` - * and `DAEMONISE_KEEP_FDS` are set whilst `2` is - * in the list of file descriptor not to close. * @throws Any error specified for signal(3). * @throws Any error specified for sigemptyset(3). * @throws Any error specified for sigprocmask(3). @@ -201,197 +180,138 @@ static int dup_at_least_3(int old) * * @since Always. */ -int daemonise(const char* name, int flags, ...) +int daemonise(const char* name, ...) { -#define t(...) do { if (__VA_ARGS__) goto fail; } while (0) - - struct rlimit rlimit; - int pipe_rw[2] = { -1, -1 }; - sigset_t set; - char** r; - char** w; - char* run; - int i, closeerr, fd = -1; - char* keep = NULL; - int keepmax = 0; - pid_t pid; - va_list args; - int saved_errno; - - - /* Validate flags. */ - if (flags & (int)~(2048L * 2 - 1)) - return errno = EINVAL, -1; - if ((flags & DAEMONISE_KEEP_STDERR) && (flags & DAEMONISE_CLOSE_STDERR)) - return errno = EINVAL, -1; - if ((flags & DAEMONISE_NO_PID_FILE) && (flags & DAEMONISE_NEW_PID)) - return errno = EINVAL, -1; - - - /* Find out which file descriptors not too close. */ - if (flags & DAEMONISE_KEEP_FDS) - { - va_start(args, flags); - while ((fd = va_arg(args, int)) >= 0) - if ((fd > 2) && (keepmax < fd)) - keepmax = fd; - fd = -1; - va_end(args); - keep = calloc((size_t)keepmax + 1, sizeof(char)); - t (keep == NULL); - va_start(args, flags); - while ((fd = va_arg(args, int)) >= 0) - switch (fd) - { - case 0: flags |= DAEMONISE_KEEP_STDIN; break; - case 1: flags |= DAEMONISE_KEEP_STDOUT; break; - case 2: flags |= DAEMONISE_KEEP_STDERR; - if (flags & DAEMONISE_CLOSE_STDERR) - return free(keep), errno = EINVAL, -1; - break; - default: - keep[fd] = 1; - break; - } - fd = -1; - va_end(args); - } - /* We assume that the maximum file descriptor is not extremely large. - * We also assume the number of file descriptors too keep is very small, - * but this does not affect us. */ - - /* Close all files except stdin, stdout, and stderr. */ - if ((flags & DAEMONISE_NO_CLOSE) == 0) - { - if (getrlimit(RLIMIT_NOFILE, &rlimit)) - rlimit.rlim_cur = 4 << 10; - for (i = 3; (rlim_t)i < rlimit.rlim_cur; i++) - /* File descriptors with numbers above and including - * `rlimit.rlim_cur` cannot be created. They cause EBADF. */ - if ((i > keepmax) || (keep[i] == 0)) - close(i); - } - free(keep), keep = NULL; - - /* Reset all signal handlers. */ - if ((flags & DAEMONISE_NO_SIG_DFL) == 0) - for (i = 1; i < _NSIG; i++) - if (signal(i, SIG_DFL) == SIG_ERR) - t (errno != EINVAL); - - /* Set signal mask. */ - if ((flags & DAEMONISE_KEEP_SIGMASK) == 0) - { - t (sigemptyset(&set)); - t (sigprocmask(SIG_SETMASK, &set, NULL)); - } - - /* Remove malformatted environment entires. */ - if (((flags & DAEMONISE_KEEP_ENVIRON) == 0) && (environ != NULL)) - { - for (r = w = environ; *r; r++) - if (strchr(*r, '=')) /* It happens that this is not the case! (Thank you PAM!) */ - *w++ = *r; - *w = NULL; - } - - /* Zero umask. */ - if ((flags & DAEMONISE_KEEP_UMASK) == 0) - umask(0); - - /* Change current working directory to '/'. */ - t (chdir("/")); - - /* Create a channel for letting the original process know when to exit. */ - if (pipe(pipe_rw)) - t ((pipe_rw[0] = pipe_rw[1] = -1)); - t (fd = dup_at_least_3(pipe_rw[0]), fd == -1); - close(pipe_rw[0]); - pipe_rw[0] = fd; - t (fd = dup_at_least_3(pipe_rw[1]), fd == -1); - close(pipe_rw[1]); - pipe_rw[1] = fd; - - /* Become a background process. */ - t (pid = fork(), pid == -1); - close(pipe_rw[!!pid]), pipe_rw[!!pid] = 1; - if (pid) - exit(read(pipe_rw[0], &fd, (size_t)1) <= 0); - - /* Temporarily become session leader. */ - t (setsid() == -1); + struct rlimit rlimit; + int pipe_rw[2] = { -1, -1 }; + sigset_t set; + char** r; + char** w; + char* run; + int i, closeerr, fd = -1; + char* keep = NULL; + int keepmax = 0; + pid_t pid; + va_list args; + int saved_errno; + + /* Find out which file descriptors not too close. */ + va_start(args, name); + while ((fd = va_arg(args, int)) >= 0) + keepmax = fd; + fd = -1; + va_end(args); + keep = calloc((size_t)keepmax + 1, sizeof(char)); + t (keep == NULL); + va_start(args, name); + while ((fd = va_arg(args, int)) >= 0) + keep[fd] = 1; + fd = -1; + va_end(args); + /* We assume that the maximum file descriptor is not extremely large. + * We also assume the number of file descriptors too keep is very small, + * but this does not affect us. */ - /* Fork again. */ - t (pid = fork(), pid == -1); - if (pid > 0) - exit(0); + /* Close all files except stdin, stdout, and stderr. */ + if (getrlimit(RLIMIT_NOFILE, &rlimit)) + rlimit.rlim_cur = 4 << 10; + for (i = 3; (rlim_t)i < rlimit.rlim_cur; i++) + /* File descriptors with numbers above and including + * `rlimit.rlim_cur` cannot be created. They cause EBADF. */ + if ((i > keepmax) || (keep[i] == 0)) + close(i); + free(keep), keep = NULL; + + /* Reset all signal handlers. */ + for (i = 1; i < _NSIG; i++) + if (signal(i, SIG_DFL) == SIG_ERR) + t (errno != EINVAL); + + /* Set signal mask. */ + t (sigemptyset(&set)); + t (sigprocmask(SIG_SETMASK, &set, NULL)); + + /* Remove malformatted environment entires. */ + if (environ) { + for (r = w = environ; *r; r++) + if (strchr(*r, '=')) /* It happens that this is not the case! (Thank you PAM!) */ + *w++ = *r; + *w = NULL; + } + + /* Zero umask. */ + umask(0); + + /* Change current working directory to '/'. */ + t (chdir("/")); + + /* Create a channel for letting the original process know when to exit. */ + if (pipe(pipe_rw)) + t ((pipe_rw[0] = pipe_rw[1] = -1)); + t (fd = dup_at_least_3(pipe_rw[0]), fd == -1); + close(pipe_rw[0]); + pipe_rw[0] = fd; + t (fd = dup_at_least_3(pipe_rw[1]), fd == -1); + close(pipe_rw[1]); + pipe_rw[1] = fd; - /* Create PID file. */ - if (flags & DAEMONISE_NO_PID_FILE) - goto no_pid_file; - run = getenv("XDG_RUNTIME_DIR"); - if (run && *run) - { - __pidfile = malloc(sizeof("/.pid") + (strlen(run) + strlen(name)) * sizeof(char)); - t (__pidfile == NULL); - stpcpy(stpcpy(stpcpy(stpcpy(__pidfile, run), "/"), name), ".pid"); - } - else - { - __pidfile = malloc(sizeof("/run/.pid") + strlen(name) * sizeof(char)); - t (__pidfile == NULL); - stpcpy(stpcpy(stpcpy(__pidfile, "/run/"), name), ".pid"); - } - fd = open(__pidfile, O_WRONLY | O_CREAT | ((flags & DAEMONISE_NEW_PID) ? 0 : O_EXCL), 0644); - if (fd == -1) - { - saved_errno = errno; - free(__pidfile), __pidfile = NULL; - errno = saved_errno; - goto fail; - } - pid = getpid(); - t (dprintf(fd, "%lli\n", (long long int)pid) < 0); - t (close(fd) && (errno != EINTR)); - no_pid_file: + /* Become a background process. */ + t (pid = fork(), pid == -1); + close(pipe_rw[!!pid]), pipe_rw[!!pid] = 1; + if (pid) + exit(read(pipe_rw[0], &fd, (size_t)1) <= 0); - /* Redirect to '/dev/null'. */ - if (flags & DAEMONISE_KEEP_STDERR) - closeerr = 0; - else if (flags & DAEMONISE_CLOSE_STDERR) - closeerr = 1; - else - closeerr = (isatty(2) || (errno == EBADF)); - t (fd = open("/dev/null", O_RDWR), fd == -1); - if ((flags & DAEMONISE_KEEP_STDIN) == 0) if (fd != 0) close(0); - if ((flags & DAEMONISE_KEEP_STDOUT) == 0) if (fd != 1) close(1); - if (closeerr) if (fd != 2) close(2); - if ((flags & DAEMONISE_KEEP_STDIN) == 0) t (dup2(fd, 0) == -1); - if ((flags & DAEMONISE_KEEP_STDOUT) == 0) t (dup2(fd, 1) == -1); - if (closeerr) t (dup2(fd, 2) == -1); - if (fd > 2) - close(fd); - fd = -1; + /* Temporarily become session leader. */ + t (setsid() == -1); - /* We are done! Let the original process exit. */ - if ((write(pipe_rw[1], &fd, (size_t)1) <= 0) || - (close(pipe_rw[1]) && (errno != EINTR))) - { - if (flags & DAEMONISE_KEEP_STDERR) - return -1; - undaemonise(); - abort(); /* Do not overcomplicate things, just abort in this unlikely event. */ - } + /* Fork again. */ + t (pid = fork(), pid == -1); + if (pid > 0) + exit(0); - return 0; - fail: - saved_errno = errno; - if (pipe_rw[0] >= 0) close(pipe_rw[0]); - if (pipe_rw[1] >= 0) close(pipe_rw[1]); - if (fd >= 0) close(fd); - free(keep); - errno = saved_errno; - return -1; + /* Create PID file. */ + run = getenv("XDG_RUNTIME_DIR"); + if (run && *run) { + __pidfile = malloc(sizeof("/.pid") + (strlen(run) + strlen(name)) * sizeof(char)); + t (__pidfile == NULL); + stpcpy(stpcpy(stpcpy(stpcpy(__pidfile, run), "/"), name), ".pid"); + } else { + __pidfile = malloc(sizeof("/run/.pid") + strlen(name) * sizeof(char)); + t (__pidfile == NULL); + stpcpy(stpcpy(stpcpy(__pidfile, "/run/"), name), ".pid"); + } + fd = open(__pidfile, O_WRONLY | O_CREAT, 0644); + if (fd == -1) { + S(free(__pidfile), __pidfile = NULL); + goto fail; + } + pid = getpid(); + t (dprintf(fd, "%lli\n", (long long int)pid) < 0); + t (close(fd) && (errno != EINTR)); + + /* Redirect to '/dev/null'. */ + closeerr = (isatty(2) || (errno == EBADF)); + t (fd = open("/dev/null", O_RDWR), fd == -1); + if (fd != 0) close(0); + if (fd != 1) close(1); + if (closeerr) if (fd != 2) close(2); + t (dup2(fd, 0) == -1); + t (dup2(fd, 1) == -1); + if (closeerr) t (dup2(fd, 2) == -1); + if (fd > 2) + close(fd); + fd = -1; + + /* We are done! Let the original process exit. */ + if ((write(pipe_rw[1], &fd, (size_t)1) <= 0) || + (close(pipe_rw[1]) && (errno != EINTR))) { + undaemonise(); + abort(); /* Do not overcomplicate things, just abort in this unlikely event. */ + } + + return 0; +fail: + return S(close(pipe_rw[0]), close(pipe_rw[1]), close(fd), free(keep)), -1; } @@ -412,13 +332,11 @@ int daemonise(const char* name, int flags, ...) */ int undaemonise(void) { - int r, saved_errno; - if (__pidfile == NULL) - return 0; - r = unlink(__pidfile); - saved_errno = errno; - free(__pidfile), __pidfile = NULL; - errno = saved_errno; - return r; + int r, saved_errno; + if (__pidfile == NULL) + return 0; + r = unlink(__pidfile); + S(free(__pidfile), __pidfile = NULL); + return r; } diff --git a/src/daemonise.h b/src/daemonise.h index 7bcea08..c318d60 100644 --- a/src/daemonise.h +++ b/src/daemonise.h @@ -23,83 +23,6 @@ /** - * Leave all opened files open. - */ -#define DAEMONISE_NO_CLOSE 1 - -/** - * Leave all signal handlers rather than - * appling default signal handlers. - */ -#define DAEMONISE_NO_SIG_DFL 2 - -/** - * Leave the signal block mask as-is. - */ -#define DAEMONISE_KEEP_SIGMASK 4 - -/** - * Do not remove malformatted environment entries. - */ -#define DAEMONISE_KEEP_ENVIRON 8 - -/** - * Do not set umask to zero. - */ -#define DAEMONISE_KEEP_UMASK 16 - -/** - * Do not create a PID file. - * - * Cannot be combined with `DAEMONISE_NEW_PID`. - */ -#define DAEMONISE_NO_PID_FILE 32 - -/** - * Do not close stderr even if it is - * a terminal device. - * - * Cannot be combined with `DAEMONISE_CLOSE_STDERR`. - */ -#define DAEMONISE_KEEP_STDERR 64 - -/** - * Close stderr even if it is - * not a terminal device. - * - * Cannot be combined with `DAEMONISE_KEEP_STDERR`. - */ -#define DAEMONISE_CLOSE_STDERR 128 - -/** - * Do not close stdin. - */ -#define DAEMONISE_KEEP_STDIN 256 - -/** - * Do not close stdout. - */ -#define DAEMONISE_KEEP_STDOUT 512 - -/** - * Enables you to select additional - * file descritors to keep open. - */ -#define DAEMONISE_KEEP_FDS 1024 - -/** - * Override the PID file if it already exists, - * rather than failing. It is a bad idea to do - * this unless you already made sure that the - * daemon is not already running. - * - * Cannot be combined with `DAEMONISE_NO_PID_FILE`. - */ -#define DAEMONISE_NEW_PID 2048 - - - -/** * Daemonise the process. This means to: * * - close all file descritors except for those to @@ -166,27 +89,9 @@ * * @param name The name of the daemon. Use a hardcoded value, * not the process name. Must not be `NULL`. - * @param flags Flags to modify the behaviour of the function. - * A bitwise OR combination of the constants: - * - `DAEMONISE_NO_CLOSE` - * - `DAEMONISE_NO_SIG_DFL` - * - `DAEMONISE_KEEP_SIGMASK` - * - `DAEMONISE_KEEP_ENVIRON` - * - `DAEMONISE_KEEP_UMASK` - * - `DAEMONISE_NO_PID_FILE` - * - `DAEMONISE_KEEP_STDERR` - * - `DAEMONISE_CLOSE_STDERR` - * - `DAEMONISE_KEEP_STDIN` - * - `DAEMONISE_KEEP_STDOUT` - * - `DAEMONISE_KEEP_FDS` - * - `DAEMONISE_NEW_PID` - * @param ... Enabled if `DAEMONISE_KEEP_FDS` is used, - * do not add anything if `DAEMONISE_KEEP_FDS` - * is unused. This is a `-1`-terminated list - * of file descritors to keep open. 0, 1, and 2 - * are implied by `DAEMONISE_KEEP_STDIN`, - * `DAEMONISE_KEEP_STDOUT`, and `DAEMONISE_KEEP_STDERR`, - * respectively. All arguments are of type `int`. + * @param ... This is a `-1`-terminated list + * of file descritors to keep open. + * All arguments are of type `int`. * @return Zero on success, -1 on error. * * @throws EEXIST The PID file already exists on the system. @@ -213,7 +118,7 @@ * * @since Always. */ -int daemonise(const char* name, int flags, ...); +int daemonise(const char* name, ...); /** @@ -114,7 +114,7 @@ main(int argc, char *argv[]) t (timerfd_settime(real, TFD_TIMER_ABSTIME, &spec, NULL)); /* Daemonise. */ - t (foreground ? 0 : daemonise("satd", DAEMONISE_KEEP_FDS | DAEMONISE_NEW_PID, 3, 4, 5, 6, -1)); + t (foreground ? 0 : daemonise("satd", /*DAEMONISE_KEEP_FDS | DAEMONISE_NEW_PID,*/ 3, 4, 5, 6, -1)); /* Change to a process image without all this initialisation text. */ execl(LIBEXECDIR "/" PACKAGE "/satd-diminished", argv0, path, NULL); |