From patchwork Sat Jan 14 12:39:28 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Michael Tokarev X-Patchwork-Id: 136077 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [140.186.70.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id B85C3B6EFF for ; Sat, 14 Jan 2012 23:42:25 +1100 (EST) Received: from localhost ([::1]:56293 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Rm2wA-0006wz-9G for incoming@patchwork.ozlabs.org; Sat, 14 Jan 2012 07:42:22 -0500 Received: from eggs.gnu.org ([140.186.70.92]:44245) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Rm2w4-0006ws-Pr for qemu-devel@nongnu.org; Sat, 14 Jan 2012 07:42:17 -0500 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Rm2w3-0005Pk-Bp for qemu-devel@nongnu.org; Sat, 14 Jan 2012 07:42:16 -0500 Received: from isrv.corpit.ru ([86.62.121.231]:35725) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Rm2w3-0005Pd-12 for qemu-devel@nongnu.org; Sat, 14 Jan 2012 07:42:15 -0500 Received: from gandalf.tls.msk.ru (mjt.vpn.tls.msk.ru [192.168.177.99]) by isrv.corpit.ru (Postfix) with ESMTP id 8010DA081B; Sat, 14 Jan 2012 16:42:12 +0400 (MSK) Received: by gandalf.tls.msk.ru (Postfix, from userid 1000) id E43483DE; Sat, 14 Jan 2012 16:42:10 +0400 (MSK) From: Michael Tokarev Date: Sat, 14 Jan 2012 16:39:28 +0400 To: qemu-devel@nongnu.org Message-Id: <20120114124210.E43483DE@gandalf.tls.msk.ru> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6 (newer, 2) X-Received-From: 86.62.121.231 Cc: Paolo Bonzini , mjt@tls.msk.ru Subject: [Qemu-devel] [PATCH] rework daemonizing logic in qemu-nbd X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org 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 --- 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 #include #include +#include #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));