diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2023-05-02 16:02:32 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2023-05-02 16:15:34 +0300 |
commit | 15874b30207fa29faf8ce9e64add011b5afa8e05 (patch) | |
tree | e0a36792cdbcdd822bcaa41fae9cf991b310f7a2 | |
parent | 5ba0926fabd419e51f777f138389e3588bbd1ce9 (diff) | |
download | wydawca-master.tar.gz wydawca-master.tar.bz2 |
-rw-r--r-- | am/ax_closefrom.m4 | 64 | ||||
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | src/Makefile.am | 1 | ||||
-rw-r--r-- | src/closefrom.c | 135 | ||||
-rw-r--r-- | src/directive.c | 10 | ||||
-rw-r--r-- | src/exec.c | 3 | ||||
-rw-r--r-- | src/wydawca.h | 3 |
7 files changed, 212 insertions, 7 deletions
diff --git a/am/ax_closefrom.m4 b/am/ax_closefrom.m4 new file mode 100644 index 0000000..959e767 --- /dev/null +++ b/am/ax_closefrom.m4 @@ -0,0 +1,64 @@ +# SYNOPSIS +# +# AX_CLOSEFROM +# +# DESCRIPTION +# +# This macro figures out the best way to close all file descriptors +# greater than or equal to the given one. It evaluates the following +# variants: +# +# 1. closefrom call (FreeBSD) +# 2. F_CLOSEM fcntl (NetBSD, AIX, IRIX) +# 3. proc_pidinfo call (Darwin) +# 4. /proc/self/fd filesystem (Linux) +# +# If none of these is applicable, brute force approach will be used. +# +# LICENSE +# +# 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/>. + +AC_DEFUN([AX_CLOSEFROM], +[ +AC_CHECK_FUNCS([sysconf getdtablesize closefrom proc_pidinfo]) + +AC_CHECK_DECL([F_CLOSEM], + AC_DEFINE([HAVE_FCNTL_CLOSEM], [1], + [Use F_CLOSEM fcntl for wy_close_fds_from]), + [], + [#include <limits.h> + #include <fcntl.h> +]) + +AC_CHECK_HEADERS([libproc.h]) + +AC_MSG_CHECKING([for closefrom interface]) +if test "$ac_cv_func_closefrom" = yes; then + closefrom_api=closefrom +elif test "$ac_cv_have_decl_F_CLOSEM" = yes; then + closefrom_api=F_CLOSEM +elif test "${ac_cv_header_libproc_h}-$ac_cv_func_proc_pidinfo" = "yes-yes"; then + closefrom_api=proc_pidinfo +elif test -d "/proc/self/fd" ; then + AC_DEFINE([HAVE_PROC_SELF_FD], [1], [Define if you have /proc/self/fd]) + closefrom_api=proc +else + closefrom_api=bruteforce +fi +AC_MSG_RESULT([$closefrom_api]) +]) diff --git a/configure.ac b/configure.ac index 963fc05..b08fcb1 100644 --- a/configure.ac +++ b/configure.ac @@ -52,13 +52,14 @@ AC_CHECK_MEMBERS([struct tm.tm_gmtoff],,, # Checks for library functions. AC_FUNC_VPRINTF AC_CHECK_FUNCS([setegid setregid setresgid setresuid seteuid \ - setreuid vsyslog sysconf getdtablesize]) + setreuid vsyslog]) # Check for POSIX threads support AX_PTHREAD([], [AC_MSG_ERROR([POSIX threads support is required, but not available])]) AX_THREAD_NAMES +AX_CLOSEFROM # ********************** # Mailutils 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, @@ -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); |