sysdeps-unix: introduce dbus_close_all() and make use of it where appropriate
authorLennart Poettering <lennart@poettering.net>
Thu, 28 Jul 2011 03:33:46 +0000 (05:33 +0200)
committerSimon McVittie <simon.mcvittie@collabora.co.uk>
Mon, 12 Mar 2012 16:38:53 +0000 (16:38 +0000)
This is optimized on Linux and enumerates through /proc/self/fd with a
fallback on brute-force closing of fds, in case /proc is not available.

Bug: https://bugs.freedesktop.org/show_bug.cgi?id=35230
Reviewed-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
dbus/dbus-sysdeps-unix.c
dbus/dbus-sysdeps-unix.h

index da3f035..5770812 100644 (file)
@@ -3124,7 +3124,6 @@ _read_subprocess_line_argv (const char *progpath,
   int ret;
   int status;
   int orig_len;
-  int i;
 
   dbus_bool_t retval;
   sigset_t new_set, old_set;
@@ -3177,7 +3176,6 @@ _read_subprocess_line_argv (const char *progpath,
   if (pid == 0)
     {
       /* child process */
-      int maxfds;
       int fd;
 
       fd = open ("/dev/null", O_RDWR);
@@ -3201,15 +3199,7 @@ _read_subprocess_line_argv (const char *progpath,
       if (dup2 (errors_pipe[WRITE_END], 2) == -1)
         _exit (1);
 
-      maxfds = sysconf (_SC_OPEN_MAX);
-      /* Pick something reasonable if for some reason sysconf
-       * says unlimited.
-       */
-      if (maxfds < 0)
-        maxfds = 1024;
-      /* close all inherited fds */
-      for (i = 3; i < maxfds; i++)
-        close (i);
+      _dbus_close_all ();
 
       sigprocmask (SIG_SETMASK, &old_set, NULL);
 
@@ -3920,4 +3910,69 @@ _dbus_replace_install_prefix (const char *configure_time_path)
   return configure_time_path;
 }
 
+/**
+ * Closes all file descriptors except the first three (i.e. stdin,
+ * stdout, stderr).
+ */
+void
+_dbus_close_all (void)
+{
+  int maxfds, i;
+
+#ifdef __linux__
+  DIR *d;
+
+  /* On Linux we can optimize this a bit if /proc is available. If it
+     isn't available, fall back to the brute force way. */
+
+  d = opendir ("/proc/self/fd");
+  if (d)
+    {
+      for (;;)
+        {
+          struct dirent buf, *de;
+          int k, fd;
+          long l;
+          char *e = NULL;
+
+          k = readdir_r (d, &buf, &de);
+          if (k != 0 || !de)
+            break;
+
+          if (de->d_name[0] == '.')
+            continue;
+
+          errno = 0;
+          l = strtol (de->d_name, &e, 10);
+          if (errno != 0 || e == NULL || *e != '\0')
+            continue;
+
+          fd = (int) l;
+          if (fd < 3)
+            continue;
+
+          if (fd == dirfd (d))
+            continue;
+
+          close (fd);
+        }
+
+      closedir (d);
+      return;
+    }
+#endif
+
+  maxfds = sysconf (_SC_OPEN_MAX);
+
+  /* Pick something reasonable if for some reason sysconf says
+   * unlimited.
+   */
+  if (maxfds < 0)
+    maxfds = 1024;
+
+  /* close all inherited fds */
+  for (i = 3; i < maxfds; i++)
+    close (i);
+}
+
 /* tests in dbus-sysdeps-util.c */
index 9f92dcd..fbe5259 100644 (file)
@@ -132,6 +132,8 @@ dbus_uid_t    _dbus_geteuid (void);
 dbus_bool_t _dbus_parse_uid (const DBusString  *uid_str,
                              dbus_uid_t        *uid);
 
+void _dbus_close_all (void);
+
 /** @} */
 
 DBUS_END_DECLS