gpg: Un-deprecate option --auto-key-retrieve.
[gnupg.git] / common / exechelp-posix.c
index 87c6e55..aefb653 100644 (file)
 # include <sys/stat.h>
 #endif
 
+#if __linux__
+# include <sys/types.h>
+# include <dirent.h>
+#endif /*__linux__ */
+
 #include "util.h"
 #include "i18n.h"
 #include "sysutils.h"
@@ -97,6 +102,43 @@ get_max_fds (void)
 #ifdef HAVE_GETRLIMIT
   struct rlimit rl;
 
+  /* Under Linux we can figure out the highest used file descriptor by
+   * reading /proc/PID/fd.  This is in the common cases much fast than
+   * for example doing 4096 close calls where almost all of them will
+   * fail.  On a system with a limit of 4096 files and only 8 files
+   * open with the highest number being 10, we speedup close_all_fds
+   * from 125ms to 0.4ms including readdir.
+   *
+   * Another option would be to close the file descriptors as returned
+   * from reading that directory - however then we need to snapshot
+   * that list before starting to close them.  */
+#ifdef __linux__
+  {
+    DIR *dir = NULL;
+    struct dirent *dir_entry;
+    const char *s;
+    int x;
+
+    dir = opendir ("/proc/self/fd");
+    if (dir)
+      {
+        while ((dir_entry = readdir (dir)))
+          {
+            s = dir_entry->d_name;
+            if ( *s < '0' || *s > '9')
+              continue;
+            x = atoi (s);
+            if (x > max_fds)
+              max_fds = x;
+          }
+        closedir (dir);
+      }
+    if (max_fds != -1)
+      return max_fds + 1;
+    }
+#endif /* __linux__ */
+
+
 # ifdef RLIMIT_NOFILE
   if (!getrlimit (RLIMIT_NOFILE, &rl))
     max_fds = rl.rlim_max;
@@ -236,7 +278,7 @@ get_all_open_fds (void)
 static void
 do_exec (const char *pgmname, const char *argv[],
          int fd_in, int fd_out, int fd_err,
-         void (*preexec)(void) )
+         int *except, void (*preexec)(void) )
 {
   char **arg_list;
   int i, j;
@@ -282,7 +324,7 @@ do_exec (const char *pgmname, const char *argv[],
     }
 
   /* Close all other files. */
-  close_all_fds (3, NULL);
+  close_all_fds (3, except);
 
   if (preexec)
     preexec ();
@@ -378,7 +420,7 @@ gnupg_create_pipe (int filedes[2])
 /* Fork and exec the PGMNAME, see exechelp.h for details.  */
 gpg_error_t
 gnupg_spawn_process (const char *pgmname, const char *argv[],
-                     void (*preexec)(void), unsigned int flags,
+                     int *except, void (*preexec)(void), unsigned int flags,
                      estream_t *r_infp,
                      estream_t *r_outfp,
                      estream_t *r_errfp,
@@ -483,7 +525,8 @@ gnupg_spawn_process (const char *pgmname, const char *argv[],
       gcry_control (GCRYCTL_TERM_SECMEM);
       es_fclose (outfp);
       es_fclose (errfp);
-      do_exec (pgmname, argv, inpipe[0], outpipe[1], errpipe[1], preexec);
+      do_exec (pgmname, argv, inpipe[0], outpipe[1], errpipe[1],
+               except, preexec);
       /*NOTREACHED*/
     }
 
@@ -533,7 +576,7 @@ gnupg_spawn_process_fd (const char *pgmname, const char *argv[],
     {
       gcry_control (GCRYCTL_TERM_SECMEM);
       /* Run child. */
-      do_exec (pgmname, argv, infd, outfd, errfd, NULL);
+      do_exec (pgmname, argv, infd, outfd, errfd, NULL, NULL);
       /*NOTREACHED*/
     }
 
@@ -686,7 +729,7 @@ gnupg_spawn_process_detached (const char *pgmname, const char *argv[],
         for (i=0; envp[i]; i++)
           putenv (xstrdup (envp[i]));
 
-      do_exec (pgmname, argv, -1, -1, -1, NULL);
+      do_exec (pgmname, argv, -1, -1, -1, NULL, NULL);
 
       /*NOTREACHED*/
     }