diff --git a/src/util.c b/src/util.c index ab6096f..21dbb66 100644 --- a/src/util.c +++ b/src/util.c @@ -34,6 +34,10 @@ #include #endif +#ifdef HAVE_BSD_NETWORK +#include +#endif + /* SURF random number generator */ static u32 seed[32]; @@ -831,9 +835,34 @@ void close_fds(long max_fd, int spare1, int spare2, int spare3) #endif #ifdef FDESCFS - DIR *d; + DIR *d = NULL; - if ((d = opendir(FDESCFS))) +# ifdef HAVE_BSD_NETWORK + dev_t dirdev = 0; + char fdescfs[] = FDESCFS; /* string must be writable */ + struct stat statbuf; + + /* On BSD, fdescfs is normally mounted at /dev/fd. However + if it is NOT mounted, devfs creates a directory at /dev/fd + which contains (only) the file descriptors 0,1 and 2. + + Under these conditions, opendir() will succeed, and + if we proceed we will fail to close extant + file descriptors which should be closed. + + Check that there is a filesystem mounted at /dev/fd + by checking that the device changes between /dev/fd + and /dev. If if doesn't, fall back to the dumb path. */ + + if (stat(fdescfs, &statbuf) != -1) + dirdev = statbuf.st_dev; + + if (stat(dirname(fdescfs), &statbuf) != -1 && + dirdev != statbuf.st_dev) +# endif + d = opendir(FDESCFS); + + if (d) { struct dirent *de;