aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2021-01-25 18:00:03 +0200
committerSergey Poznyakoff <gray@gnu.org>2021-01-25 18:59:29 +0200
commite8196c272d9760b01a7ae87366015169ba399766 (patch)
treec4b6edede626ad03b4ea4da7a826206bb6a8b0b3
parent3e8ea8d7eab4c2b657be9732a4c5e846bac45458 (diff)
downloadmicron-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.ac31
-rw-r--r--src/Makefile.am2
-rw-r--r--src/closefds.c126
-rw-r--r--src/crontab.c6
-rw-r--r--src/defs.h2
-rw-r--r--src/runner.c11
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);
diff --git a/src/defs.h b/src/defs.h
index a387484..d569d61 100644
--- a/src/defs.h
+++ b/src/defs.h
@@ -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);

Return to:

Send suggestions and report system problems to the System administrator.