Skip to content

Commit

Permalink
closing FDs in optimized way
Browse files Browse the repository at this point in the history
* code ported from sudo utility
  • Loading branch information
Michal Zubac committed Feb 6, 2015
1 parent c517ec5 commit 3f847de
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 10 deletions.
28 changes: 28 additions & 0 deletions configure.ac
Expand Up @@ -577,6 +577,11 @@ AC_TYPE_SIZE_T
AC_TYPE_UID_T
AC_HEADER_TIME


AH_TEMPLATE(HAVE_DD_FD, [Define to 1 if your `DIR' contains dd_fd.])
AH_TEMPLATE(HAVE_DIRFD, [Define to 1 if you have the `dirfd' function or macro.])
AH_TEMPLATE(HAVE_FCNTL_CLOSEM, [Define to 1 if your system has the F_CLOSEM fcntl.])

#
# Checks for library functions.
#
Expand Down Expand Up @@ -1129,6 +1134,29 @@ AC_CHECK_FUNCS(getvfsstat, [have_getvfsstat="yes"])
have_listmntent="no"
AC_CHECK_FUNCS(listmntent, [have_listmntent="yes"])

AC_CHECK_FUNCS(closefrom, [], [AC_LIBOBJ(closefrom)
AC_CHECK_DECL(F_CLOSEM, AC_DEFINE(HAVE_FCNTL_CLOSEM), [],
[ #include <limits.h>
#include <fcntl.h> ])
])

dnl
dnl Check for the dirfd function/macro. If not found, look for dd_fd in DIR.
dnl
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
#include <$ac_header_dirent>]], [[DIR *d; (void)dirfd(d);]])], [AC_DEFINE(HAVE_DIRFD)], [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <sys/types.h>
#include <$ac_header_dirent>]], [[DIR d; memset(&d, 0, sizeof(d)); return(d.dd_fd);]])], [AC_DEFINE(HAVE_DD_FD)], [])])
AC_CHECK_MEMBERS([struct dirent.d_type], [], [], [
AC_INCLUDES_DEFAULT
#include <$ac_header_dirent>
])

AC_CHECK_FUNCS(closefrom, [], [AC_LIBOBJ(closefrom)
AC_CHECK_DECL(F_CLOSEM, AC_DEFINE(HAVE_FCNTL_CLOSEM), [],
[ #include <limits.h>
#include <fcntl.h> ])
])

have_getmntent="no"
AC_CHECK_FUNCS(getmntent, [have_getmntent="c"])
if test "x$have_getmntent" = "xno"; then
Expand Down
3 changes: 2 additions & 1 deletion src/Makefile.am
Expand Up @@ -22,6 +22,7 @@ bin_PROGRAMS = collectd-nagios collectdctl collectd-tg

collectd_SOURCES = collectd.c collectd.h \
common.c common.h \
compat/closefrom.c \
configfile.c configfile.h \
filter_chain.c filter_chain.h \
meta_data.c meta_data.h \
Expand Down Expand Up @@ -87,7 +88,7 @@ else
collectd_LDADD += -loconfig
endif

collectdmon_SOURCES = collectdmon.c
collectdmon_SOURCES = collectdmon.c compat/closefrom.c
collectdmon_CPPFLAGS = $(AM_CPPFLAGS)

collectd_nagios_SOURCES = collectd-nagios.c
Expand Down
10 changes: 4 additions & 6 deletions src/collectdmon.c
Expand Up @@ -50,6 +50,8 @@

#include <unistd.h>

#include "compat/missing.h"

#ifndef COLLECTDMON_PIDFILE
# define COLLECTDMON_PIDFILE LOCALSTATEDIR"/run/collectdmon.pid"
#endif /* ! COLLECTDMON_PIDFILE */
Expand Down Expand Up @@ -116,7 +118,6 @@ static int daemonize (void)
struct rlimit rl;

pid_t pid = 0;
int i = 0;

if (0 != chdir ("/")) {
fprintf (stderr, "Error: chdir() failed: %s\n", strerror (errno));
Expand All @@ -141,11 +142,8 @@ static int daemonize (void)

setsid ();

if (RLIM_INFINITY == rl.rlim_max)
rl.rlim_max = 1024;

for (i = 0; i < (int)rl.rlim_max; ++i)
close (i);
/* Close all file descriptors in optimized way */
closefrom(0);

errno = 0;
if (open ("/dev/null", O_RDWR) != 0) {
Expand Down
118 changes: 118 additions & 0 deletions src/compat/closefrom.c
@@ -0,0 +1,118 @@
/*
* Copyright (c) 2004-2005, 2007, 2010
* Todd C. Miller <Todd.Miller@courtesan.com>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/

#include <config.h>

#include <sys/types.h>
#include <sys/param.h>
#include <unistd.h>
#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif /* STDC_HEADERS */
#include <fcntl.h>
#ifdef HAVE_DIRENT_H
# include <dirent.h>
# define NAMLEN(dirent) strlen((dirent)->d_name)
#else
# define dirent direct
# define NAMLEN(dirent) (dirent)->d_namlen
# ifdef HAVE_SYS_NDIR_H
# include <sys/ndir.h>
# endif
# ifdef HAVE_SYS_DIR_H
# include <sys/dir.h>
# endif
# ifdef HAVE_NDIR_H
# include <ndir.h>
# endif
#endif

#include "missing.h"

#ifndef HAVE_FCNTL_CLOSEM
# ifndef HAVE_DIRFD
# define closefrom_fallback closefrom
# endif
#endif

/*
* Close all file descriptors greater than or equal to lowfd.
* This is the expensive (ballback) method.
*/
void
closefrom_fallback(int lowfd)
{
long fd, maxfd;

/*
* Fall back on sysconf() or getdtablesize(). We avoid checking
* resource limits since it is possible to open a file descriptor
* and then drop the rlimit such that it is below the open fd.
*/
#ifdef HAVE_SYSCONF
maxfd = sysconf(_SC_OPEN_MAX);
#else
maxfd = getdtablesize();
#endif /* HAVE_SYSCONF */
if (maxfd < 0)
maxfd = OPEN_MAX;

for (fd = lowfd; fd < maxfd; fd++)
(void) close((int) fd);
}

/*
* Close all file descriptors greater than or equal to lowfd.
* We try the fast way first, falling back on the slow method.
*/
#ifdef HAVE_FCNTL_CLOSEM
void
closefrom(int lowfd)
{
if (fcntl(lowfd, F_CLOSEM, 0) == -1)
closefrom_fallback(lowfd);
}
#else
# ifdef HAVE_DIRFD
void
closefrom(int lowfd)
{
struct dirent *dent;
DIR *dirp;
char *endp;
long fd;

/* Use /proc/self/fd directory if it exists. */
if ((dirp = opendir("/proc/self/fd")) != NULL) {
while ((dent = readdir(dirp)) != NULL) {
fd = strtol(dent->d_name, &endp, 10);
if (dent->d_name != endp && *endp == '\0' &&
fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp))
(void) close((int) fd);
}
(void) closedir(dirp);
} else
closefrom_fallback(lowfd);
}
#endif /* HAVE_DIRFD */
#endif /* HAVE_FCNTL_CLOSEM */
10 changes: 10 additions & 0 deletions src/compat/missing.h
@@ -0,0 +1,10 @@
/*
* Some systems lack full limit definitions.
*/
#ifndef OPEN_MAX
# define OPEN_MAX 256
#endif

#ifndef HAVE_CLOSEFROM
void closefrom(int);
#endif
21 changes: 18 additions & 3 deletions src/exec.c
Expand Up @@ -32,6 +32,8 @@
#include "utils_cmd_putval.h"
#include "utils_cmd_putnotif.h"

#include "compat/missing.h"

#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
Expand Down Expand Up @@ -99,6 +101,14 @@ static void sigchld_handler (int __attribute__((unused)) signal) /* {{{ */
} /* while (waitpid) */
} /* void sigchld_handler }}} */

static int int_max(int a, int b) {
if (a >= b) {
return a;
} else {
return b;
}
}

static int exec_config_exec (oconfig_item_t *ci) /* {{{ */
{
program_list_t *pl;
Expand Down Expand Up @@ -466,12 +476,14 @@ static int fork_child (program_list_t *pl, int *fd_in, int *fd_out, int *fd_err)
}
else if (pid == 0)
{
int fd_num;
int fd;
int fd_max_used = -1;

/* Determine the highest FD we need to keep */
fd_max_used = int_max(int_max(fd_pipe_in[0], fd_pipe_out[1]), fd_pipe_err[1]);

/* Close all file descriptors but the pipe end we need. */
fd_num = getdtablesize ();
for (fd = 0; fd < fd_num; fd++)
for (fd = 0; fd < fd_max_used; fd++)
{
if ((fd == fd_pipe_in[0])
|| (fd == fd_pipe_out[1])
Expand All @@ -480,6 +492,9 @@ static int fork_child (program_list_t *pl, int *fd_in, int *fd_out, int *fd_err)
close (fd);
}

/* Close all other file descriptors in optimized way */
closefrom(fd_max_used + 1);

/* Connect the `in' pipe to STDIN */
if (fd_pipe_in[0] != STDIN_FILENO)
{
Expand Down

0 comments on commit 3f847de

Please sign in to comment.