diff --git a/configure.ac b/configure.ac index 14bf306..97a606a 100644 --- a/configure.ac +++ b/configure.ac @@ -40,7 +40,7 @@ fi # Checks for libraries. # Checks for header files. -AC_CHECK_HEADERS([sys/ndir.h sys/dir.h dir.h dirent.h]) +AC_CHECK_HEADERS([sys/ndir.h sys/dir.h ndir.h dirent.h]) # Checks for typedefs, structures, and compiler characteristics. AC_TYPE_UID_T @@ -123,7 +123,8 @@ AC_LINK_IFELSE( AC_MSG_RESULT([yes])], [AC_MSG_RESULT([no])]) -AC_CHECK_FUNCS([clearenv dirfd fopencookie __fpurge getexecname getline sysconf]) +AC_CHECK_FUNCS([clearenv dirfd fopencookie __fpurge getexecname getline \ + pstat_getproc sysconf]) AC_CONFIG_FILES([ Makefile diff --git a/src/closefrom.c b/src/closefrom.c index b7e2ad5..423a004 100644 --- a/src/closefrom.c +++ b/src/closefrom.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2005, 2007, 2010 + * Copyright (c) 2004-2005, 2007, 2010, 2012-2014 * Todd C. Miller * * Permission to use, copy, modify, and distribute this software for any @@ -18,7 +18,6 @@ #include #include -#include #include #include #ifdef STDC_HEADERS @@ -30,20 +29,26 @@ # endif #endif /* STDC_HEADERS */ #include -#ifdef HAVE_DIRENT_H -# include -# define NAMLEN(dirent) strlen((dirent)->d_name) +#include +#ifdef HAVE_PSTAT_GETPROC +# include +# include #else -# define dirent direct -# define NAMLEN(dirent) (dirent)->d_namlen -# ifdef HAVE_SYS_NDIR_H -# include -# endif -# ifdef HAVE_SYS_DIR_H -# include -# endif -# ifdef HAVE_NDIR_H -# include +# ifdef HAVE_DIRENT_H +# include +# define NAMLEN(dirent) strlen((dirent)->d_name) +# else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# ifdef HAVE_SYS_NDIR_H +# include +# endif +# ifdef HAVE_SYS_DIR_H +# include +# endif +# ifdef HAVE_NDIR_H +# include +# endif # endif #endif @@ -51,15 +56,13 @@ # define OPEN_MAX 256 #endif -#ifndef HAVE_FCNTL_CLOSEM -# ifndef HAVE_DIRFD -# define closefrom_fallback closefrom -# endif +#if defined(HAVE_FCNTL_CLOSEM) && !defined(HAVE_DIRFD) +# define closefrom closefrom_fallback #endif /* * Close all file descriptors greater than or equal to lowfd. - * This is the expensive (ballback) method. + * This is the expensive (fallback) method. */ void closefrom_fallback(int lowfd) @@ -79,44 +82,74 @@ closefrom_fallback(int lowfd) if (maxfd < 0) maxfd = OPEN_MAX; - for (fd = lowfd; fd < maxfd; fd++) + for (fd = lowfd; fd < maxfd; fd++) { +#ifdef __APPLE__ + /* Avoid potential libdispatch crash when we close its fds. */ + (void)fcntl((int)fd, F_SETFD, FD_CLOEXEC); +#else (void)close((int)fd); +#endif + } } /* * Close all file descriptors greater than or equal to lowfd. * We try the fast way first, falling back on the slow method. */ -#ifdef HAVE_FCNTL_CLOSEM +#if defined(HAVE_FCNTL_CLOSEM) void closefrom(int lowfd) { if (fcntl(lowfd, F_CLOSEM, 0) == -1) closefrom_fallback(lowfd); } -#else -# ifdef HAVE_DIRFD +#elif defined(HAVE_PSTAT_GETPROC) void closefrom(int lowfd) { - struct dirent *dent; - DIR *dirp; - char *endp; - long fd; + struct pst_status pstat; + int fd; + + if (pstat_getproc(&pstat, sizeof(pstat), 0, getpid()) != -1) { + for (fd = lowfd; fd <= pstat.pst_highestfd; fd++) + (void)close(fd); + } else { + closefrom_fallback(lowfd); + } +} +#elif defined(HAVE_DIRFD) +void +closefrom(int lowfd) +{ + const char *path; + DIR *dirp; + + /* Use /proc/self/fd (or /dev/fd on FreeBSD) if it exists. */ +# if defined(__FreeBSD__) || defined(__APPLE__) + path = "/dev/fd"; +# else + path = "/proc/self/fd"; +# endif + if ((dirp = opendir(path)) != NULL) { + struct dirent *dent; - /* Use /proc/self/fd directory if it exists. */ - dirp = opendir("/proc/self/fd"); - if (dirp != NULL) { while ((dent = readdir(dirp)) != NULL) { - fd = strtol(dent->d_name, &endp, 10); - if (dent->d_name != endp && *endp == '\0' && - fd >= 0 && fd < INT_MAX && fd >= lowfd && - fd != dirfd(dirp)) - (void)close((int)fd); + const char *errstr; + int fd; + + fd = strtonum(dent->d_name, lowfd, INT_MAX, &errstr); + if (errstr == NULL && fd != dirfd(dirp)) { +# ifdef __APPLE__ + /* Avoid potential libdispatch crash when we + * close its fds. */ + (void)fcntl(fd, F_SETFD, FD_CLOEXEC); +# else + (void)close(fd); +# endif + } } (void)closedir(dirp); } else closefrom_fallback(lowfd); } -#endif /* HAVE_DIRFD */ #endif /* HAVE_FCNTL_CLOSEM */