daemon: New function daemon_save_fd() to preserve fds across detach.
authorBen Pfaff <blp@nicira.com>
Fri, 27 Jan 2012 17:53:17 +0000 (09:53 -0800)
committerBen Pfaff <blp@nicira.com>
Fri, 3 Feb 2012 00:26:53 +0000 (16:26 -0800)
This eliminates a kluge that was duplicated in three different daemons.

Signed-off-by: Ben Pfaff <blp@nicira.com>
lib/daemon.c
lib/daemon.h
ovsdb/ovsdb-client.c
tests/test-netflow.c
utilities/ovs-ofctl.c

index 3dd5a1abbf9ed1b4204ffeef2015301ac7bd2d68..8ef5491a7dd321cfb1db98406600318807b50e21 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
 
 #include <config.h>
 #include "daemon.h"
+#include <assert.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <signal.h>
@@ -61,6 +62,10 @@ static int daemonize_fd = -1;
  * it dies due to an error signal? */
 static bool monitor;
 
+/* For each of the standard file descriptors, whether to replace it by
+ * /dev/null (if false) or keep it for the daemon to use (if true). */
+static bool save_fds[3];
+
 static void check_already_running(void);
 static int lock_pidfile(FILE *, int command);
 
@@ -142,6 +147,20 @@ daemon_set_monitor(void)
     monitor = true;
 }
 
+/* A daemon doesn't normally have any use for the file descriptors for stdin,
+ * stdout, and stderr after it detaches.  To keep these file descriptors from
+ * e.g. holding an SSH session open, by default detaching replaces each of
+ * these file descriptors by /dev/null.  But a few daemons expect the user to
+ * redirect stdout or stderr to a file, in which case it is desirable to keep
+ * these file descriptors.  This function, therefore, disables replacing 'fd'
+ * by /dev/null when the daemon detaches. */
+void
+daemon_save_fd(int fd)
+{
+    assert(fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO);
+    save_fds[fd] = true;
+}
+
 /* If a pidfile has been configured, creates it and stores the running
  * process's pid in it.  Ensures that the pidfile will be deleted when the
  * process exits. */
@@ -402,16 +421,21 @@ monitor_daemon(pid_t daemon_pid)
     program_name = saved_program_name;
 }
 
-/* Close stdin, stdout, stderr.  If we're started from e.g. an SSH session,
- * then this keeps us from holding that session open artificially. */
+/* Close standard file descriptors (except any that the client has requested we
+ * leave open by calling daemon_save_fd()).  If we're started from e.g. an SSH
+ * session, then this keeps us from holding that session open artificially. */
 static void
 close_standard_fds(void)
 {
     int null_fd = get_null_fd();
     if (null_fd >= 0) {
-        dup2(null_fd, STDIN_FILENO);
-        dup2(null_fd, STDOUT_FILENO);
-        dup2(null_fd, STDERR_FILENO);
+        int fd;
+
+        for (fd = 0; fd < 3; fd++) {
+            if (!save_fds[fd]) {
+                dup2(null_fd, fd);
+            }
+        }
     }
 
     /* Disable logging to stderr to avoid wasting CPU time. */
index eb38d5d87971aa3d222a385ec352640520d21a08..1b4f988e3fbe627be1a55d5ad4bf9dfb1e7a7969 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2008, 2009, 2010, 2011 Nicira Networks.
+ * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -64,6 +64,7 @@ bool is_chdir_enabled(void);
 void set_detach(void);
 bool get_detach(void);
 void daemon_set_monitor(void);
+void daemon_save_fd(int fd);
 void daemonize(void);
 void daemonize_start(void);
 void daemonize_complete(void);
index afa61c3d2e6388ef9bda5d360ba1b995c10c79ac..b1c660ae927a615b2b4ccfe8e4535ca8c74c3843 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2010, 2011 Nicira Networks.
+ * Copyright (c) 2009, 2010, 2011, 2012 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -733,12 +733,8 @@ do_monitor(struct jsonrpc *rpc, const char *database,
             monitor_print(msg->result, table, &columns, true);
             fflush(stdout);
             if (get_detach()) {
-                /* daemonize() closes the standard file descriptors.  We output
-                 * to stdout, so we need to save and restore STDOUT_FILENO. */
-                int fd = dup(STDOUT_FILENO);
+                daemon_save_fd(STDOUT_FILENO);
                 daemonize();
-                dup2(fd, STDOUT_FILENO);
-                close(fd);
             }
         } else if (msg->type == JSONRPC_NOTIFY
                    && !strcmp(msg->method, "update")) {
index 5a88ada3cde0f6fe031b19da253575723c6b11df..b85c663e4d0d798256446d02d591cb99236d95bb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011 Nicira Networks.
+ * Copyright (c) 2011, 2012 Nicira Networks.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -190,7 +190,6 @@ main(int argc, char *argv[])
     bool exiting = false;
     int error;
     int sock;
-    int fd;
     int n;
 
     proctitle_init(argc, argv);
@@ -208,10 +207,7 @@ main(int argc, char *argv[])
         ovs_fatal(0, "%s: failed to open (%s)", argv[1], strerror(-sock));
     }
 
-    /* Daemonization will close stdout but we really want to keep it, so make a
-     * copy. */
-    fd = dup(STDOUT_FILENO);
-
+    daemon_save_fd(STDOUT_FILENO);
     daemonize_start();
 
     error = unixctl_server_create(NULL, &server);
@@ -222,9 +218,6 @@ main(int argc, char *argv[])
 
     daemonize_complete();
 
-    /* Now get stdout back. */
-    dup2(fd, STDOUT_FILENO);
-
     ofpbuf_init(&buf, MAX_RECV);
     n = 0;
     for (;;) {
index 70af5bdacceff6581e1bad4b1c9f56a725080a64..9b1a1b24e786ea2dd59941b963973bb1f58dfac7 100644 (file)
@@ -831,12 +831,9 @@ monitor_vconn(struct vconn *vconn)
 {
     struct unixctl_server *server;
     bool exiting = false;
-    int error, fd;
-
-    /* Daemonization will close stderr but we really want to keep it, so make a
-     * copy. */
-    fd = dup(STDERR_FILENO);
+    int error;
 
+    daemon_save_fd(STDERR_FILENO);
     daemonize_start();
     error = unixctl_server_create(NULL, &server);
     if (error) {
@@ -845,9 +842,6 @@ monitor_vconn(struct vconn *vconn)
     unixctl_command_register("exit", "", 0, 0, ofctl_exit, &exiting);
     daemonize_complete();
 
-    /* Now get stderr back. */
-    dup2(fd, STDERR_FILENO);
-
     for (;;) {
         struct ofpbuf *b;
         int retval;