Improve daemonize - fix trac issue 178, debian bug http://bugs.debian.org/cgi-bin...
authorAlex Bligh <alex@alex.org.uk>
Mon, 10 Sep 2012 20:12:56 +0000 (21:12 +0100)
committerAlex Bligh <alex@alex.org.uk>
Mon, 10 Sep 2012 20:12:56 +0000 (21:12 +0100)
src/daemon.c

index f952d67..55ae2b2 100644 (file)
@@ -42,6 +42,8 @@
 #include <string.h>
 #include <signal.h>
 #include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
 #include <ctype.h>
 
 #include <sys/socket.h>
@@ -347,6 +349,67 @@ void guacd_handle_connection_xml(int fd, char* xmlconfig) {
     return;
 }
 
+void daemonize () {
+    const char *devnull = "/dev/null";
+
+    /* Fork once to ensure we aren't the process group leader */
+    int i = fork ();
+    if (i < 0) {
+        fprintf (stderr, "Unable to fork\n");
+        _exit (1);
+    }
+
+    /* Exit if we are the parent */
+    if (i > 0)
+       _exit (0);                  /* parent exits */
+
+    /* Start a new session */
+    setsid ();
+
+    /* Fork again so the session group leader exits */
+    i = fork ();
+    if (i < 0) {
+        fprintf (stderr, "Unable to fork\n");
+        _exit (1);
+    }
+
+    /* Exit if we are the parent */
+    if (i > 0)
+       _exit (0);                  /* parent exits */
+
+    if (chdir ("/") <0) {
+        fprintf (stderr, "Unable to chdir /\n");
+        _exit (1);
+    }
+
+    /* Now close all FDs and reopen the 3 stdxxx to /dev/null */
+    for (i = getdtablesize () - 1; i >= 0; i--)
+        close (i);
+
+    i = open (devnull, O_RDWR);
+    if (i == -1) {
+        fprintf (stderr, "Unable to open /dev/null\n");
+        _exit (1);
+    }
+    i = open (devnull, O_RDONLY);
+    if (i != 0) {
+        dup2 (i, 0);
+        close (i);
+    }
+    i = open (devnull, O_WRONLY);
+    if (i != 1) {
+        dup2 (i, 1);
+        close (i);
+    }
+    i = open (devnull, O_WRONLY);
+    if (i != 2) {
+        dup2 (i, 2);
+        close (i);
+    }
+}
+
+
+
 int main(int argc, char* argv[]) {
 
     /* Server */
@@ -379,9 +442,6 @@ int main(int argc, char* argv[]) {
     /* General */
     int retval;
 
-    /* Daemon Process */
-    pid_t daemon_pid;
-
     xml_init();
 
     /* Parse arguments */
@@ -414,9 +474,28 @@ int main(int argc, char* argv[]) {
         }
     }
 
+    /* Daemonize before we start opening sockets, as this closes FDs */
+    if (!foreground)
+        daemonize();
+
+    if (pidfile != NULL) {
+        /* Attempt to open pidfile and write PID */
+        FILE* pidf = fopen(pidfile, "w");
+        if (pidf) {
+            fprintf(pidf, "%d\n", getpid());
+            fclose(pidf);
+        } else {
+            /* Warn on failure */
+            guacd_log_error("Could not write PID file: %s", strerror(errno));
+            exit(EXIT_FAILURE);
+        }
+    }
+
     /* Set up logging prefix */
     strncpy(log_prefix, basename(argv[0]), sizeof(log_prefix));
 
+    /* Open log as early as we can */
+    openlog(NULL, LOG_PID, LOG_DAEMON);
 
     /* Get addresses for binding */
     if ((retval = getaddrinfo(listen_address, listen_port, &hints, &addresses))) {
@@ -481,44 +560,6 @@ int main(int argc, char* argv[]) {
         exit(EXIT_FAILURE);
     }
 
-    if (!foreground) {
-
-        /* Fork into background */
-        daemon_pid = fork();
-
-        /* If error, fail */
-        if (daemon_pid == -1) {
-            guacd_log_error("Error forking daemon process: %s", strerror(errno));
-            exit(EXIT_FAILURE);
-        }
-
-        /* If parent, write PID file and exit */
-        else if (daemon_pid != 0) {
-
-            if (pidfile != NULL) {
-
-                /* Attempt to open pidfile and write PID */
-                FILE* pidf = fopen(pidfile, "w");
-                if (pidf) {
-                    fprintf(pidf, "%d\n", daemon_pid);
-                    fclose(pidf);
-                }
-
-                /* Warn on failure */
-                else {
-                    guacd_log_error("Could not write PID file: %s", strerror(errno));
-                    exit(EXIT_FAILURE);
-                }
-
-            }
-
-            exit(EXIT_SUCCESS);
-        }
-    }
-
-    /* Open log */
-    openlog(NULL, LOG_PID, LOG_DAEMON);
-
     /* Ignore SIGPIPE */
     if (signal(SIGPIPE, SIG_IGN) == SIG_ERR) {
         guacd_log_info("Could not set handler for SIGPIPE to ignore. SIGPIPE may cause termination of the daemon.");