aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2023-05-02 16:02:32 +0300
committerSergey Poznyakoff <gray@gnu.org>2023-05-02 16:15:34 +0300
commit15874b30207fa29faf8ce9e64add011b5afa8e05 (patch)
treee0a36792cdbcdd822bcaa41fae9cf991b310f7a2 /src
parent5ba0926fabd419e51f777f138389e3588bbd1ce9 (diff)
downloadwydawca-master.tar.gz
wydawca-master.tar.bz2
Add interface for closing file descriptors greater than or equal to the given one.HEADmaster
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am1
-rw-r--r--src/closefrom.c135
-rw-r--r--src/directive.c10
-rw-r--r--src/exec.c3
-rw-r--r--src/wydawca.h3
5 files changed, 146 insertions, 6 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 46bdcc7..3d32d59 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -20,6 +20,7 @@ wydawca_SOURCES=\
backup.c\
builtin.c\
builtin.h\
+ closefrom.c\
cmdline.h\
config.c\
dictionary.c\
diff --git a/src/closefrom.c b/src/closefrom.c
new file mode 100644
index 0000000..a7a144c
--- /dev/null
+++ b/src/closefrom.c
@@ -0,0 +1,135 @@
+/* This file is part of Wydawca
+ Copyright (C) 2021-2023 Sergey Poznyakoff
+
+ Wydawca is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3, or (at your option)
+ any later version.
+
+ Wydawca is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with wydawca. If not, see <http://www.gnu.org/licenses/>. */
+#include <config.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#if defined (HAVE_FUNC_CLOSEFROM)
+static int
+close_fds_sys(int minfd)
+{
+ closefrom(minfd);
+ return 0;
+}
+
+#elif defined (HAVE_FCNTL_CLOSEM)
+# include <fcntl.h>
+
+static int
+close_fds_sys(int minfd)
+{
+ fcntl(minfd, F_CLOSEM, 0);
+ return 0;
+}
+
+#elif defined (HAVE_LIBPROC_H) && defined (HAVE_FUNC_PROC_PIDINFO)
+#include <libproc.h>
+
+static int
+close_fds_sys(int minfd)
+{
+ pid_t pid = getpid();
+ struct proc_fdinfo *fdinfo;
+ int i, n, size;
+
+ size = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0);
+ if (size == 0)
+ return 0;
+ else if (size < 0)
+ return -1;
+
+ fdinfo = calloc(size, sizeof(fdinfo[0]));
+ if (!fdinfo)
+ return -1;
+
+ n = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fdinfo, size);
+ if (n <= 0) {
+ free(fdinfo);
+ return -1;
+ }
+
+ n /= PROC_PIDLISTFD_SIZE;
+
+ for (i = minfd; i < n; i++)
+ close(fdinfo_buf[i].proc_fd);
+
+ free(fdinfo);
+ return 0;
+}
+
+#elif defined (HAVE_PROC_SELF_FD)
+# include <sys/types.h>
+# include <dirent.h>
+# include <limits.h>
+
+static int
+close_fds_sys(int minfd)
+{
+ DIR *dir;
+ struct dirent *ent;
+
+ dir = opendir("/proc/self/fd");
+ if (!dir)
+ return -1;
+ while ((ent = readdir(dir)) != NULL) {
+ if (ent->d_name[0] != '.') {
+ char *p;
+ long n = strtol(ent->d_name, &p, 10);
+ if (n >= minfd && n < INT_MAX && *p == 0)
+ close((int) n);
+ }
+ }
+ closedir(dir);
+ return 0;
+}
+
+#else
+# define close_fds_sys(fd) (-1)
+#endif
+
+#if defined (HAVE_SYSCONF) && defined (_SC_OPEN_MAX)
+# define __getmaxfd() sysconf(_SC_OPEN_MAX)
+#elif defined (HAVE_GETDTABLESIZE)
+# define __getmaxfd() getdtablesize()
+#elif defined OPEN_MAX
+# define __getmaxfd() OPEN_MAX
+#else
+# define __getmaxfd() 256
+#endif
+
+static int
+close_fds_bruteforce(int minfd)
+{
+ int i, n = __getmaxfd();
+
+ for (i = minfd; i < n; i++)
+ close(i);
+
+ return 0;
+}
+
+void
+wy_close_fds_from(int minfd)
+{
+ if (close_fds_sys(minfd))
+ close_fds_bruteforce(minfd);
+}
+
+void
+wy_close_fds_above(int fd)
+{
+ wy_close_fds_from(fd + 1);
+}
diff --git a/src/directive.c b/src/directive.c
index e69888b..0df6611 100644
--- a/src/directive.c
+++ b/src/directive.c
@@ -558,10 +558,12 @@ run_check_script(const char *script, struct wy_triplet *trp,
if (efd == -1)
_exit(127);
- for (i = getdtablesize(); i >= 0; i--) {
- if (i != p[1] && i != efd)
- close(i);
- }
+ /* Select the biggest fd. */
+ i = p[1];
+ if (efd > i)
+ i = efd;
+ /* Close all fds above it. */
+ wy_close_fds_above(i);
if (p[1] != 1 && dup2(p[1], 1) != 1) {
wy_log(LOG_CRIT,
diff --git a/src/exec.c b/src/exec.c
index 6c342c8..a56963f 100644
--- a/src/exec.c
+++ b/src/exec.c
@@ -52,8 +52,7 @@ start_prog(int argc, const char **argv, pid_t * ppid)
close(p[0]);
/* Close unneded descripitors */
- for (i = getdtablesize(); i > 2; i--)
- close(i);
+ wy_close_fds_above(2);
execvp(argv[0], (char **) argv);
wy_log(LOG_CRIT, _("cannot run %s: %s"), argv[0], strerror(errno));
diff --git a/src/wydawca.h b/src/wydawca.h
index 21e1d9e..66c820d 100644
--- a/src/wydawca.h
+++ b/src/wydawca.h
@@ -560,3 +560,6 @@ void *wy_thr_connection_watcher(void *ptr);
char *wy_tempdir(void);
int wy_rmdir_r(const char *name);
+
+void wy_close_fds_from(int minfd);
+void wy_close_fds_above(int minfd);

Return to:

Send suggestions and report system problems to the System administrator.