All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH] rework daemonizing logic in qemu-nbd
@ 2012-01-14 12:39 Michael Tokarev
  2012-01-15 10:42 ` Paolo Bonzini
  0 siblings, 1 reply; 9+ messages in thread
From: Michael Tokarev @ 2012-01-14 12:39 UTC (permalink / raw)
  To: qemu-devel; +Cc: Paolo Bonzini, mjt

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.

Signed-Off-By: Michael Tokarev <mjt@tls.msk.ru>
---
 qemu-nbd.c |   83 ++++++++++++++++++++++++++++++++++++------------------------
 1 files changed, 50 insertions(+), 33 deletions(-)

diff --git a/qemu-nbd.c b/qemu-nbd.c
index e76c782..6a84cde 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"
 
@@ -415,54 +416,58 @@ 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.
+         * pass errors.
          */
         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 from /dev/null,
+             * stdout (temporarily) to the pipe to parent,
+             * and keep stderr for error report.
+             * When initializing is done, redirect stdout and stderr
+             * to /dev/null (stdin).
              */
-            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) {
-                err(EXIT_FAILURE, "Cannot read from daemon");
+            close(cpipe[0]);
+            if (cpipe[1] != STDOUT_FILENO) {
+                dup2(cpipe[1], STDOUT_FILENO);
+                close(cpipe[1]);
             }
-
-            /* Usually the daemon should not print any message.
-             * Exit with zero status in that case.
+        } 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().
              */
-            exit(errors);
+            ret = read(cpipe[0], &ret, sizeof(ret));
+            pid = waitpid(pid, &ret, WNOHANG);
+            if (pid < 0) {
+                err(EXIT_FAILURE, "Cannot read from daemon");
+            }
+            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 +532,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 redirects stdout to /dev/null too, and closes parent pipe */
+        dup2(STDIN_FILENO, STDOUT_FILENO);
+    }
+
     do {
         main_loop_wait(false);
     } while (!sigterm_reported && (persistent || !nbd_started || nb_fds > 0));
-- 
1.7.2.5

^ permalink raw reply related	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2012-01-16  7:41 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-01-14 12:39 [Qemu-devel] [PATCH] rework daemonizing logic in qemu-nbd Michael Tokarev
2012-01-15 10:42 ` Paolo Bonzini
2012-01-15 12:50   ` Michael Tokarev
2012-01-15 16:11     ` Paolo Bonzini
2012-01-15 16:44       ` Michael Tokarev
2012-01-15 17:31         ` Paolo Bonzini
2012-01-15 17:46           ` Paolo Bonzini
2012-01-16  7:22           ` Michael Tokarev
2012-01-16  7:41             ` Paolo Bonzini

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.