run: Improve error diagnostics for chdir(2) failure.
[dss.git] / daemon.c
index fe51fe03a5c614ba4cc8f34a0f29e1b79cd2cf8d..0b201a8aa07b617e6eaea506cae4f096dc377e8a 100644 (file)
--- a/daemon.c
+++ b/daemon.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1997-2010 Andre Noll <maan@systemlinux.org>
+ * Copyright (C) 1997-2010 Andre Noll <maan@tuebingen.mpg.de>
  *
  * Licensed under the GPL v2. For licencing details see COPYING.
  */
@@ -19,9 +19,9 @@
 #include <stdio.h>
 
 #include "gcc-compat.h"
-#include "error.h"
+#include "err.h"
 #include "log.h"
-#include "string.h"
+#include "str.h"
 #include "daemon.h"
 
 /**
  *
  * \sa fork(2), setsid(2), dup(2).
  */
-void daemon_init(void)
+int daemon_init(void)
 {
        pid_t pid;
-       int null;
+       int null, fd[2];
 
        DSS_INFO_LOG(("daemonizing\n"));
+       if (pipe(fd) < 0)
+               goto err;
        pid = fork();
        if (pid < 0)
                goto err;
-       if (pid)
-               exit(EXIT_SUCCESS); /* parent exits */
+       if (pid) {
+               /*
+                * The parent process exits once it has received one byte from
+                * the reading end of the pipe. If the child exits before it
+                * was able to complete its setup (acquire the lock on the
+                * semaphore), the read() below will return zero. In this case
+                * we let the parent die unsuccessfully.
+                */
+               char c;
+               int ret;
+               close(fd[1]);
+               ret = read(fd[0], &c, 1);
+               if (ret <= 0) {
+                       DSS_EMERG_LOG(("child terminated unexpectedly\n"));
+                       exit(EXIT_FAILURE);
+               }
+               exit(EXIT_SUCCESS);
+       }
+       close(fd[0]);
        /* become session leader */
        if (setsid() < 0)
                goto err;
-       if (chdir("/") < 0)
-               goto err;
        umask(0);
-       null = open("/dev/null", O_RDONLY);
+       null = open("/dev/null", O_RDWR);
        if (null < 0)
                goto err;
        if (dup2(null, STDIN_FILENO) < 0)
@@ -58,7 +75,7 @@ void daemon_init(void)
        if (dup2(null, STDERR_FILENO) < 0)
                goto err;
        close(null);
-       return;
+       return fd[1];
 err:
        DSS_EMERG_LOG(("fatal: %s\n", strerror(errno)));
        exit(EXIT_FAILURE);