summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStef Walter <stefw@gnome.org>2013-02-20 11:50:25 +0100
committerStef Walter <stef@thewalter.net>2014-06-23 11:33:48 +0200
commitcbc9273ec1e59a3ce05cd9423b326e9d258e6a5a (patch)
tree5a3e8458e3b044073e7c85daa8fd516b134f9928
parent774d6c65160d4438cddda59ecd63024866cfea39 (diff)
downloadp11-kit-cbc9273ec1e59a3ce05cd9423b326e9d258e6a5a.tar.gz
Add compatibility fdwalk() function
This is used when execing another process to close all open file descriptors that we don't wish to be inherited.
-rw-r--r--common/compat.c73
-rw-r--r--common/compat.h7
-rw-r--r--configure.ac3
3 files changed, 83 insertions, 0 deletions
diff --git a/common/compat.c b/common/compat.c
index 85a33c8..fd4e137 100644
--- a/common/compat.c
+++ b/common/compat.c
@@ -37,6 +37,7 @@
#include "compat.h"
#include <assert.h>
+#include <dirent.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
@@ -81,6 +82,8 @@
#ifdef OS_UNIX
+#include <unistd.h>
+
#if defined (HAVE_PROGRAM_INVOCATION_SHORT_NAME) && !HAVE_DECL_PROGRAM_INVOCATION_SHORT_NAME
extern char *program_invocation_short_name;
#endif
@@ -851,3 +854,73 @@ strerror_r (int errnum,
}
#endif /* HAVE_STRERROR_R */
+
+#ifdef OS_UNIX
+
+#include <unistd.h>
+
+#ifndef HAVE_FDWALK
+
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+
+int
+fdwalk (int (* cb) (void *data, int fd),
+ void *data)
+{
+ struct dirent *de;
+ char *end;
+ DIR *dir;
+ int open_max;
+ long num;
+ int res = 0;
+ int fd;
+
+#ifdef HAVE_SYS_RESOURCE_H
+ struct rlimit rl;
+#endif
+
+ dir = opendir ("/proc/self/fd");
+ if (dir != NULL) {
+ while ((de = readdir (dir)) != NULL) {
+ end = NULL;
+ num = (int) strtol (de->d_name, &end, 10);
+
+ /* didn't parse or is the opendir() fd */
+ if (!end || *end != '\0' ||
+ (int)num == dirfd (dir))
+ continue;
+
+ fd = num;
+
+ /* call the callback */
+ res = cb (data, fd);
+ if (res != 0)
+ break;
+ }
+
+ closedir (dir);
+ return res;
+ }
+
+ /* No /proc, brute force */
+#ifdef HAVE_SYS_RESOURCE_H
+ if (getrlimit (RLIMIT_NOFILE, &rl) == 0 && rl.rlim_max != RLIM_INFINITY)
+ open_max = rl.rlim_max;
+ else
+#endif
+ open_max = sysconf (_SC_OPEN_MAX);
+
+ for (fd = 0; fd < open_max; fd++) {
+ res = cb (data, fd);
+ if (res != 0)
+ break;
+ }
+
+ return res;
+}
+
+#endif /* HAVE_FDWALK */
+
+#endif /* OS_UNIX */
diff --git a/common/compat.h b/common/compat.h
index d7fe414..4771370 100644
--- a/common/compat.h
+++ b/common/compat.h
@@ -325,4 +325,11 @@ int strerror_r (int errnum,
#endif /* HAVE_STRERROR_R */
+#ifndef HAVE_FDWALK
+
+int fdwalk (int (* cb) (void *data, int fd),
+ void *data);
+
+#endif
+
#endif /* __COMPAT_H__ */
diff --git a/configure.ac b/configure.ac
index 79693a2..8109e2c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -85,11 +85,14 @@ if test "$os_unix" = "yes"; then
])
# These are thngs we can work around
+ AC_CHECK_HEADERS([sys/resource.h])
+ AC_CHECK_MEMBERS([struct dirent.d_type],,,[#include <dirent.h>])
AC_CHECK_FUNCS([getprogname getexecname basename mkstemp mkdtemp])
AC_CHECK_FUNCS([getauxval issetugid getresuid])
AC_CHECK_FUNCS([strnstr memdup strndup strerror_r])
AC_CHECK_FUNCS([asprintf vasprintf vsnprintf])
AC_CHECK_FUNCS([timegm])
+ AC_CHECK_FUNCS([fdwalk])
AC_CHECK_DECLS([asprintf, vasprintf], [], [], [[#include <stdio.h>]])