close all open fd's on fork
authorRobin Gareus <robin@gareus.org>
Fri, 7 Jun 2013 18:50:59 +0000 (20:50 +0200)
committerRobin Gareus <robin@gareus.org>
Fri, 7 Jun 2013 18:50:59 +0000 (20:50 +0200)
gtk2_ardour/system_exec.cc

index 90c7294f5533fae89ad0ea37ec60e942818cf6a6..55dbc60bb4c2cf80c367ca1484e453692c07a2dd 100644 (file)
@@ -1,5 +1,6 @@
 /*
     Copyright (C) 2010 Paul Davis
+    Copyright 2005-2008 Lennart Poettering
     Author: Robin Gareus <robin@gareus.org>
 
     This program is free software; you can redistribute it and/or modify
@@ -23,6 +24,9 @@
 #include <errno.h>
 #include <unistd.h>
 
+#include <assert.h>
+#include <dirent.h>
+
 #ifdef __WIN32__
 #include <windows.h>
 #else
 #include <sys/wait.h>
 #include <sys/socket.h>
 #include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/resource.h>
 #endif
 
+
 #include "system_exec.h"
 
 using namespace std;
@@ -40,6 +47,104 @@ void * interposer_thread (void *arg);
 
 static void close_fd (int& fd) { if (fd >= 0) ::close (fd); fd = -1; }
 
+#ifndef __WIN32__
+/*
+ * This function was part of libasyncns.
+ * LGPL v2.1
+ * Copyright 2005-2008 Lennart Poettering
+ */
+static int close_allv(const int except_fds[]) {
+       struct rlimit rl;
+       int fd;
+
+#ifdef __linux__
+
+       DIR *d;
+
+       assert(except_fds);
+
+       if ((d = opendir("/proc/self/fd"))) {
+               struct dirent *de;
+
+               while ((de = readdir(d))) {
+                       int found;
+                       long l;
+                       char *e = NULL;
+                       int i;
+
+                       if (de->d_name[0] == '.')
+                                       continue;
+
+                       errno = 0;
+                       l = strtol(de->d_name, &e, 10);
+                       if (errno != 0 || !e || *e) {
+                               closedir(d);
+                               errno = EINVAL;
+                               return -1;
+                       }
+
+                       fd = (int) l;
+
+                       if ((long) fd != l) {
+                               closedir(d);
+                               errno = EINVAL;
+                               return -1;
+                       }
+
+                       if (fd < 3)
+                               continue;
+
+                       if (fd == dirfd(d))
+                               continue;
+
+                       found = 0;
+                       for (i = 0; except_fds[i] >= 0; i++)
+                               if (except_fds[i] == fd) {
+                                               found = 1;
+                                               break;
+                               }
+
+                       if (found) continue;
+
+                       if (close(fd) < 0) {
+                               int saved_errno;
+
+                               saved_errno = errno;
+                               closedir(d);
+                               errno = saved_errno;
+
+                               return -1;
+                       }
+               }
+
+               closedir(d);
+               return 0;
+       }
+
+#endif
+
+       if (getrlimit(RLIMIT_NOFILE, &rl) < 0)
+               return -1;
+
+       for (fd = 0; fd < (int) rl.rlim_max; fd++) {
+               int i;
+
+               if (fd <= 3)
+                               continue;
+
+               for (i = 0; except_fds[i] >= 0; i++)
+                       if (except_fds[i] == fd)
+                               continue;
+
+               if (close(fd) < 0 && errno != EBADF)
+                       return -1;
+       }
+
+       return 0;
+}
+#endif /* not on windows */
+
+
 SystemExec::SystemExec (std::string c, std::string a)
        : cmd(c)
 {
@@ -619,6 +724,11 @@ SystemExec::start (int stderr_mode)
        signal(SIGPIPE, SIG_DFL);
 #endif
 
+#ifndef __WIN32__
+       int good_fds[1] = { 0 };
+       close_allv(good_fds);
+#endif
+
        ::execve(argp[0], argp, envp);
        /* if we reach here something went wrong.. */
        char buf = 0;