diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2021-01-25 18:00:03 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2021-01-25 18:59:29 +0200 |
commit | e8196c272d9760b01a7ae87366015169ba399766 (patch) | |
tree | c4b6edede626ad03b4ea4da7a826206bb6a8b0b3 | |
parent | 3e8ea8d7eab4c2b657be9732a4c5e846bac45458 (diff) | |
download | micron-e8196c272d9760b01a7ae87366015169ba399766.tar.gz micron-e8196c272d9760b01a7ae87366015169ba399766.tar.bz2 |
New function for closing all file descriptors starting from N
Imported from mailutils.
* configure.ac: Select a suitable interface for closing all file
descriptors greater than or equal to a chosen one.
* src/Makefile.am (libmicron_a_SOURCES): Add closefds.c
* src/closefds.c: New file.
* src/crontab.c (command_edit): Use close_fds.
* src/defs.h (close_fds): New proto.
-rw-r--r-- | configure.ac | 31 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/closefds.c | 126 | ||||
-rw-r--r-- | src/crontab.c | 6 | ||||
-rw-r--r-- | src/defs.h | 2 | ||||
-rw-r--r-- | src/runner.c | 11 |
6 files changed, 165 insertions, 13 deletions
diff --git a/configure.ac b/configure.ac index 1c889c4..170902a 100644 --- a/configure.ac +++ b/configure.ac @@ -70,6 +70,37 @@ if test $status_inotify = yes; then fi AM_CONDITIONAL([COND_INOTIFY],[test $status_inotify = yes]) +# ********************** +# Select interface used to close file descriptors greater than or +# equal to the given one. +# +# Variants: +# 1. closefrom call (FreeBSD) +# 2. F_CLOSEM fcntl (NetBSD, AIX, IRIX) +# 3. proc_pidinfo call (Darwin) +# 4. /proc/self/fd filesystem (Linux) +# 5. Brute force +# +# The defines created here direct conditionalal compilation in +# src/closefds.c + +AC_CHECK_FUNCS([closefrom]) +AC_CHECK_DECL([F_CLOSEM], + AC_DEFINE([HAVE_FCNTL_CLOSEM], [1], + [Use F_CLOSEM fcntl for mu_close_fds]), + [], + [#include <limits.h> + #include <fcntl.h> +]) + +AC_CHECK_HEADERS([libproc.h]) +AC_CHECK_FUNCS([proc_pidinfo]) + +if test -d "/proc/self/fd" ; then + AC_DEFINE([HAVE_PROC_SELF_FD], [1], [Define if you have /proc/self/fd]) +fi + +# AC_SUBST([CRONTAB_GID],[crontab]) AC_ARG_WITH([crontab-gid], [AC_HELP_STRING([--with-crontab-gid=GID], diff --git a/src/Makefile.am b/src/Makefile.am index 3eaea27..50a344e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -19,6 +19,7 @@ micrond_SOURCES=\ micrond.c\ micrond.h\ runner.c + if COND_INOTIFY micrond_SOURCES += watcher.c endif @@ -28,6 +29,7 @@ crontab_SOURCES=crontab.c noinst_LIBRARIES = libmicron.a libmicron_a_SOURCES =\ + closefds.c\ micron.c\ micron.h\ micron_log.c\ diff --git a/src/closefds.c b/src/closefds.c new file mode 100644 index 0000000..4677ed1 --- /dev/null +++ b/src/closefds.c @@ -0,0 +1,126 @@ +/* micron - a minimal cron implementation + Copyright (C) 2020-2021 Sergey Poznyakoff + + Micron 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 of the License, or (at your + option) any later version. + + Micron 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 micron. If not, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> +#include <stdlib.h> +#include <unistd.h> + +#if defined (HAVE_FUNC_CLOSEFROM) +# include <unistd.h> + +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) { + long n; + char *p; + + if (ent->d_name[0] == '.') + continue; + + 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 + +static int +close_fds_bruteforce(int minfd) +{ + int i, n = sysconf(_SC_OPEN_MAX); + + for (i = minfd; i < n; i++) + close(i); + + return 0; +} + +void +close_fds(int minfd) +{ + if (close_fds_sys(minfd)) + close_fds_bruteforce(minfd); +} diff --git a/src/crontab.c b/src/crontab.c index 6ad74a6..6fc48d9 100644 --- a/src/crontab.c +++ b/src/crontab.c @@ -601,17 +601,13 @@ command_edit(int argc, char **argv) goto finish; } if (pid == 0) { - int i; - if (fchdir(tempdirfd)) { terror("failed to change to %s/%s: %s", tempdir, template, strerror(errno)); _exit(127); } - for (i = sysconf(_SC_OPEN_MAX); i > 2; i--) { - close(i); - } + close_fds(3); execlp("/bin/sh", "sh", "-c", editor_command, NULL); _exit(127); @@ -51,6 +51,8 @@ struct string_reference { char str[1]; }; typedef struct string_reference *String; + +void close_fds(int minfd); diff --git a/src/runner.c b/src/runner.c index 12f2bb0..0b481ae 100644 --- a/src/runner.c +++ b/src/runner.c @@ -265,7 +265,6 @@ runner_start(struct cronjob *job) } if (pid == 0) { - int i; char const *shell; /* Restore default signal handlers */ @@ -288,10 +287,8 @@ runner_start(struct cronjob *job) } /* Close the rest of descriptors */ - for (i = sysconf(_SC_OPEN_MAX); i > 2; i--) { - close(i); - } - + close_fds(3); + shell = env_get(ENV_SHELL, env); execle(shell, shell, "-c", job->command, NULL, env); fprintf(stderr, "execle failed: shell=%s, command=%s\n", @@ -355,9 +352,7 @@ mailer_start(struct proctab *pt, const char *mailto) job_setprivs(pt->job, pt->env); dup2(p[0], 0); - for (i = sysconf(_SC_OPEN_MAX); i > 0; i--) { - close(i); - } + close_fds(1); open("/dev/null", O_WRONLY); dup(1); execlp("/bin/sh", "sh", "-c", mailer_command, NULL); |