From a8b5f8b423e5d54ba8bb6e68cc5b9dc22215d302 Mon Sep 17 00:00:00 2001
From: Ben Pfaff <blp@nicira.com>
Date: Wed, 15 Jul 2009 10:54:51 -0700
Subject: [PATCH] Add function get_null_fd(), to reduce code redundancy.

---
 extras/ezio/ezio-term.c |  5 +----
 lib/process.c           |  2 ++
 lib/socket-util.c       | 18 ++++++++++++++++++
 lib/socket-util.h       |  1 +
 secchan/executer.c      | 27 ++++++++++-----------------
 5 files changed, 32 insertions(+), 21 deletions(-)

diff --git a/extras/ezio/ezio-term.c b/extras/ezio/ezio-term.c
index 93ec1c280..846ccfded 100644
--- a/extras/ezio/ezio-term.c
+++ b/extras/ezio/ezio-term.c
@@ -106,7 +106,7 @@ main(int argc, char *argv[])
     argv += optind;
 
     /* Make sure that the ezio3 terminfo entry is available. */
-    dummy_fd = open("/dev/null", O_RDWR);
+    dummy_fd = get_null_fd();
     if (dummy_fd >= 0) {
         if (setupterm("ezio3", dummy_fd, &retval) == ERR) {
             if (retval == 0) {
@@ -118,9 +118,6 @@ main(int argc, char *argv[])
             }
         }
         del_curterm(cur_term);
-        close(dummy_fd);
-    } else {
-        ovs_error(errno, "failed to open /dev/null");
     }
 
     /* Lock serial port. */
diff --git a/lib/process.c b/lib/process.c
index f752a3560..7b583cac0 100644
--- a/lib/process.c
+++ b/lib/process.c
@@ -187,6 +187,8 @@ process_start(char **argv,
         unblock_sigchld(&oldsigs);
         for (fd = 0; fd < fd_max; fd++) {
             if (is_member(fd, null_fds, n_null_fds)) {
+                /* We can't use get_null_fd() here because we might have
+                 * already closed its fd. */
                 int nullfd = open("/dev/null", O_RDWR);
                 dup2(nullfd, fd);
                 close(nullfd);
diff --git a/lib/socket-util.c b/lib/socket-util.c
index 33e179e1c..086a329ea 100644
--- a/lib/socket-util.c
+++ b/lib/socket-util.c
@@ -299,6 +299,24 @@ guess_netmask(uint32_t ip)
             : htonl(0));                          /* ??? */
 }
 
+/* Returns a readable and writable fd for /dev/null, if successful, otherwise
+ * a negative errno value.  The caller must not close the returned fd (because
+ * the same fd will be handed out to subsequent callers). */
+int
+get_null_fd(void)
+{
+    static int null_fd = -1;
+    if (null_fd < 0) {
+        null_fd = open("/dev/null", O_RDWR);
+        if (null_fd < 0) {
+            int error = errno;
+            VLOG_ERR("could not open /dev/null: %s", strerror(error));
+            return -error;
+        }
+    }
+    return null_fd;
+}
+
 int
 read_fully(int fd, void *p_, size_t size, size_t *bytes_read)
 {
diff --git a/lib/socket-util.h b/lib/socket-util.h
index 34dc92f6b..3ba2c477b 100644
--- a/lib/socket-util.h
+++ b/lib/socket-util.h
@@ -32,6 +32,7 @@ int make_unix_socket(int style, bool nonblock, bool passcred,
                      const char *bind_path, const char *connect_path);
 int get_unix_name_len(socklen_t sun_len);
 uint32_t guess_netmask(uint32_t ip);
+int get_null_fd(void);
 
 int read_fully(int fd, void *, size_t, size_t *bytes_read);
 int write_fully(int fd, const void *, size_t, size_t *bytes_written);
diff --git a/secchan/executer.c b/secchan/executer.c
index 210d7cbcf..6b8c8e52b 100644
--- a/secchan/executer.c
+++ b/secchan/executer.c
@@ -71,10 +71,7 @@ struct executer {
 };
 
 /* File descriptors for waking up when a child dies. */
-static int signal_fds[2];
-
-/* File descriptor for /dev/null. */
-static int null_fd = -1;
+static int signal_fds[2] = {-1, -1};
 
 static void send_child_status(struct rconn *, uint32_t xid, uint32_t status,
                               const void *data, size_t size);
@@ -205,9 +202,9 @@ executer_handle_request(struct executer *e, struct rconn *rconn,
          * subprocesses at once?  Would also want to catch fatal signals and
          * kill them at the same time though. */
         fatal_signal_fork();
-        dup2(null_fd, 0);
+        dup2(get_null_fd(), 0);
         dup2(output_fds[1], 1);
-        dup2(null_fd, 2);
+        dup2(get_null_fd(), 2);
         max_fds = get_max_fds();
         for (i = 3; i < max_fds; i++) {
             close(i);
@@ -448,7 +445,13 @@ executer_create(const char *command_acl, const char *command_dir,
     struct sigaction sa;
 
     *executerp = NULL;
-    if (null_fd == -1) {
+    if (signal_fds[0] == -1) {
+        /* Make sure we can get a fd for /dev/null. */
+        int null_fd = get_null_fd();
+        if (null_fd < 0) {
+            return -null_fd;
+        }
+
         /* Create pipe for notifying us that SIGCHLD was invoked. */
         if (pipe(signal_fds)) {
             VLOG_ERR("pipe failed: %s", strerror(errno));
@@ -456,16 +459,6 @@ executer_create(const char *command_acl, const char *command_dir,
         }
         set_nonblocking(signal_fds[0]);
         set_nonblocking(signal_fds[1]);
-
-        /* Open /dev/null. */
-        null_fd = open("/dev/null", O_RDWR);
-        if (null_fd < 0) {
-            int error = errno;
-            VLOG_ERR("could not open /dev/null: %s", strerror(error));
-            close(signal_fds[0]);
-            close(signal_fds[1]);
-            return error;
-        }
     }
 
     /* Set up signal handler. */
-- 
2.47.0