1/*
2 * Copyright (c) 2004-2005, 2007, 2010
3 *	Todd C. Miller <Todd.Miller@courtesan.com>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include <config.h>
19
20#include <sys/types.h>
21#include <sys/param.h>
22#include <unistd.h>
23#include <stdio.h>
24#ifdef STDC_HEADERS
25# include <stdlib.h>
26# include <stddef.h>
27#else
28# ifdef HAVE_STDLIB_H
29#  include <stdlib.h>
30# endif
31#endif /* STDC_HEADERS */
32#include <fcntl.h>
33#ifdef HAVE_DIRENT_H
34# include <dirent.h>
35# define NAMLEN(dirent) strlen((dirent)->d_name)
36#else
37# define dirent direct
38# define NAMLEN(dirent) (dirent)->d_namlen
39# ifdef HAVE_SYS_NDIR_H
40#  include <sys/ndir.h>
41# endif
42# ifdef HAVE_SYS_DIR_H
43#  include <sys/dir.h>
44# endif
45# ifdef HAVE_NDIR_H
46#  include <ndir.h>
47# endif
48#endif
49
50#include "missing.h"
51
52#ifndef HAVE_FCNTL_CLOSEM
53# ifndef HAVE_DIRFD
54#   define closefrom_fallback	closefrom
55# endif
56#endif
57
58/*
59 * Close all file descriptors greater than or equal to lowfd.
60 * This is the expensive (ballback) method.
61 */
62void
63closefrom_fallback(lowfd)
64    int lowfd;
65{
66    long fd, maxfd;
67
68    /*
69     * Fall back on sysconf() or getdtablesize().  We avoid checking
70     * resource limits since it is possible to open a file descriptor
71     * and then drop the rlimit such that it is below the open fd.
72     */
73#ifdef HAVE_SYSCONF
74    maxfd = sysconf(_SC_OPEN_MAX);
75#else
76    maxfd = getdtablesize();
77#endif /* HAVE_SYSCONF */
78    if (maxfd < 0)
79	maxfd = OPEN_MAX;
80
81    for (fd = lowfd; fd < maxfd; fd++)
82#if 6497333
83	(void) fcntl((int) fd, F_SETFD, 1);
84#else
85	(void) close((int) fd);
86#endif
87}
88
89/*
90 * Close all file descriptors greater than or equal to lowfd.
91 * We try the fast way first, falling back on the slow method.
92 */
93#ifdef HAVE_FCNTL_CLOSEM
94void
95closefrom(lowfd)
96    int lowfd;
97{
98    if (fcntl(lowfd, F_CLOSEM, 0) == -1)
99	closefrom_fallback(lowfd);
100}
101#else
102# ifdef HAVE_DIRFD
103void
104closefrom(lowfd)
105    int lowfd;
106{
107    struct dirent *dent;
108    DIR *dirp;
109    char *endp;
110    long fd;
111
112    /* Use /dev/fd directory if it exists. */
113    if ((dirp = opendir("/dev/fd")) != NULL) {
114	while ((dent = readdir(dirp)) != NULL) {
115	    fd = strtol(dent->d_name, &endp, 10);
116	    if (dent->d_name != endp && *endp == '\0' &&
117		fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp))
118		(void) close((int) fd);
119	}
120	(void) closedir(dirp);
121    } else
122	closefrom_fallback(lowfd);
123}
124#endif /* HAVE_DIRFD */
125#endif /* HAVE_FCNTL_CLOSEM */
126