]> git.armaanb.net Git - opendoas.git/blob - libopenbsd/closefrom.c
0d393530b4a6a80c9e2ec787f66ade0be667ebf9
[opendoas.git] / libopenbsd / closefrom.c
1 /*
2  * SPDX-License-Identifier: ISC
3  *
4  * Copyright (c) 2004-2005, 2007, 2010, 2012-2015, 2017-2018
5  *      Todd C. Miller <Todd.Miller@sudo.ws>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19
20 /*
21  * This is an open source non-commercial project. Dear PVS-Studio, please check it.
22  * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
23  */
24
25 #include <sys/types.h>
26 #include <unistd.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <fcntl.h>
30 #include <limits.h>
31 #ifdef HAVE_PSTAT_GETPROC
32 # include <sys/pstat.h>
33 #else
34 # include <dirent.h>
35 #endif
36
37 #include "openbsd.h"
38
39 #ifndef _POSIX_OPEN_MAX
40 # define _POSIX_OPEN_MAX        20
41 #endif
42
43 /*
44  * Close all file descriptors greater than or equal to lowfd.
45  * This is the expensive (fallback) method.
46  */
47 static void
48 closefrom_fallback(int lowfd)
49 {
50     long fd, maxfd;
51
52     /*
53      * Fall back on sysconf(_SC_OPEN_MAX).  We avoid checking
54      * resource limits since it is possible to open a file descriptor
55      * and then drop the rlimit such that it is below the open fd.
56      */
57     maxfd = sysconf(_SC_OPEN_MAX);
58     if (maxfd < 0)
59         maxfd = _POSIX_OPEN_MAX;
60
61     for (fd = lowfd; fd < maxfd; fd++) {
62 #ifdef __APPLE__
63         /* Avoid potential libdispatch crash when we close its fds. */
64         (void) fcntl((int) fd, F_SETFD, FD_CLOEXEC);
65 #else
66         (void) close((int) fd);
67 #endif
68     }
69 }
70
71 /*
72  * Close all file descriptors greater than or equal to lowfd.
73  * We try the fast way first, falling back on the slow method.
74  */
75 void
76 closefrom(int lowfd)
77 {
78 #if defined(HAVE_PSTAT_GETPROC)
79     struct pst_status pstat;
80 #elif defined(HAVE_DIRFD)
81     const char *path;
82     DIR *dirp;
83 #endif
84
85     /* Try the fast method first, if possible. */
86 #if defined(HAVE_FCNTL_CLOSEM)
87     if (fcntl(lowfd, F_CLOSEM, 0) != -1)
88         return;
89 #endif
90 #if defined(HAVE_PSTAT_GETPROC)
91     /*
92      * EOVERFLOW is not a fatal error for the fields we use.
93      * See the "EOVERFLOW Error" section of pstat_getvminfo(3).
94      */
95     if (pstat_getproc(&pstat, sizeof(pstat), 0, getpid()) != -1 ||
96         errno == EOVERFLOW) {
97         int fd;
98
99         for (fd = lowfd; fd <= pstat.pst_highestfd; fd++)
100             (void) close(fd);
101         return;
102     }
103 #elif defined(HAVE_DIRFD)
104     /* Use /proc/self/fd (or /dev/fd on macOS) if it exists. */
105 # ifdef __APPLE__
106     path = _PATH_DEV "fd";
107 # else
108     path = "/proc/self/fd";
109 # endif
110     if ((dirp = opendir(path)) != NULL) {
111         struct dirent *dent;
112         while ((dent = readdir(dirp)) != NULL) {
113             const char *errstr;
114             int fd = strtonum(dent->d_name, lowfd, INT_MAX, &errstr);
115             if (errstr == NULL && fd != dirfd(dirp)) {
116 # ifdef __APPLE__
117                 /* Avoid potential libdispatch crash when we close its fds. */
118                 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
119 # else
120                 (void) close(fd);
121 # endif
122             }
123         }
124         (void) closedir(dirp);
125         return;
126     }
127 #endif /* HAVE_DIRFD */
128
129     /* Do things the slow way. */
130     closefrom_fallback(lowfd);
131 }