qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH v2] rework daemonizing logic in qemu-nbd


From: Michael Tokarev
Subject: [Qemu-devel] [PATCH v2] rework daemonizing logic in qemu-nbd
Date: Sat, 14 Jan 2012 16:39:28 +0400

qemu-nbd uses daemon(3) routine to daemonize, and while
at it, it uses several hacks to make daemon(3) to work
as intended.  Instead of all these hacks, implement
daemon(3) functionality (which is a very simple function)
directly but in a way which is much more suitable for the
use case. It lets us to remove several hacks completely,
and stop using daemon() which is marked as deprecated
on e.g. MacOS.  Some more hacks around daemon(3) will
be removed in subsequent series.

This patch, while decoupling daemon(3), also moves chdir(/)
to the place before main loop, which fixes a problem with
relative pathnames.

Signed-Off-By: Michael Tokarev <address@hidden>
---
 qemu-nbd.c |   81 ++++++++++++++++++++++++++++++++++-------------------------
 1 files changed, 47 insertions(+), 34 deletions(-)

diff --git a/qemu-nbd.c b/qemu-nbd.c
index e76c782..1dfef16 100644
--- a/qemu-nbd.c
+++ b/qemu-nbd.c
@@ -32,6 +32,7 @@
 #include <signal.h>
 #include <libgen.h>
 #include <pthread.h>
+#include <sys/wait.h>
 
 #define SOCKET_PATH    "/var/lock/qemu-nbd-%s"
 
@@ -304,6 +305,7 @@ int main(int argc, char **argv)
     int sockfd, devfd;
     int persistent = 0;
     pthread_t client_thread;
+    int cpipefd = -1;
 
     /* The client thread uses SIGTERM to interrupt the server.  A signal
      * handler ensures that "qemu-nbd -v -c" exits with a nice status code.
@@ -415,54 +417,53 @@ int main(int argc, char **argv)
     }
 
     if (device && !verbose) {
-        int stderr_fd[2];
+        int cpipe[2];
         pid_t pid;
-        int ret;
 
-        if (qemu_pipe(stderr_fd) == -1) {
+        if (qemu_pipe(cpipe) == -1) {
             err(EXIT_FAILURE, "Error setting up communication pipe");
         }
 
-        /* Now daemonize, but keep a communication channel open to
-         * print errors and exit with the proper status code.
+        /* Now daemonize, but keep a communication channel open.
          */
         pid = fork();
         if (pid == 0) {
-            close(stderr_fd[0]);
-            ret = qemu_daemon(0, 0);
-
-            /* Temporarily redirect stderr to the parent's pipe...  */
-            dup2(stderr_fd[1], STDERR_FILENO);
-            if (ret == -1) {
+            int nullfd = open("/dev/null", O_RDWR);
+            if (nullfd < 0 || setsid() < 0) {
                 err(EXIT_FAILURE, "Failed to daemonize");
             }
-
-            /* ... close the descriptor we inherited and go on.  */
-            close(stderr_fd[1]);
-        } else {
-            bool errors = false;
-            char *buf;
-
-            /* In the parent.  Print error messages from the child until
-             * it closes the pipe.
+            /* redirect stdin and stdout to/from /dev/null,
+             * and keep stderr for error report.
+             * When initializing is done, redirect stderr
+             * to /dev/null (stdin) and close the pipe.
              */
-            close(stderr_fd[1]);
-            buf = g_malloc(1024);
-            while ((ret = read(stderr_fd[0], buf, 1024)) > 0) {
-                errors = true;
-                ret = qemu_write_full(STDERR_FILENO, buf, ret);
-                if (ret == -1) {
-                    exit(EXIT_FAILURE);
-                }
+            if (nullfd != STDIN_FILENO) {
+                dup2(nullfd, STDIN_FILENO);
+                close(nullfd);
             }
-            if (ret == -1) {
+            close(cpipe[0]);
+            cpipefd = cpipe[1];
+        } else if (pid < 0) {
+            err(EXIT_FAILURE, "Failed to daemonize");
+        } else {
+            close(cpipe[1]);
+            /* In parent, just a dummy read till the pipe gets closed.
+             * When it does, check process exit status using waitpid().
+             */
+            ret = read(cpipe[0], &ret, sizeof(ret));
+            pid = waitpid(pid, &ret, WNOHANG);
+            if (pid < 0) {
                 err(EXIT_FAILURE, "Cannot read from daemon");
             }
-
-            /* Usually the daemon should not print any message.
-             * Exit with zero status in that case.
-             */
-            exit(errors);
+            return
+              /* waitpid(pid, WNOHANG) returns 0 if the process
+               * in question did not change state. In this case
+               * we assume our child successfully initialized and
+               * is now running, so exit succcessfully here.
+               */
+              pid == 0 ? 0 :
+              /* else our child exited, so return its exit status */
+              WIFEXITED(ret) ? WEXITSTATUS(ret) : 1;
         }
     }
 
@@ -527,6 +528,18 @@ int main(int argc, char **argv)
     qemu_set_fd_handler2(sockfd, nbd_can_accept, nbd_accept, NULL,
                          (void *)(uintptr_t)sockfd);
 
+    /* now complete the daemonizing procedure.
+     */
+    if (device && !verbose) {
+        if (chdir("/") < 0) {
+            err(EXIT_FAILURE, "unable to chdir to /");
+        }
+        /* this redirects stderr to /dev/null */
+        dup2(STDIN_FILENO, STDERR_FILENO);
+        /* this closes pipe to parent so it can exit */
+       close(cpipefd);
+    }
+
     do {
         main_loop_wait(false);
     } while (!sigterm_reported && (persistent || !nbd_started || nb_fds > 0));
-- 
1.7.2.5




reply via email to

[Prev in Thread] Current Thread [Next in Thread]