X-Git-Url: https://git.octo.it/?p=collectd.git;a=blobdiff_plain;f=src%2Fexec.c;h=a0e534c7d5fdfa03950b97ed9b9b9809b5a9ec6d;hp=36f2d4da19021eae2a63d9684058422881a9d888;hb=2d62935910e0bbb871705113aed6f19d9ae205f2;hpb=109aa67e9a982321af6547b92b5b2b6c8ae2c244 diff --git a/src/exec.c b/src/exec.c index 36f2d4da..a0e534c7 100644 --- a/src/exec.c +++ b/src/exec.c @@ -28,11 +28,11 @@ #include "collectd.h" -#include "common.h" #include "plugin.h" +#include "utils/common/common.h" -#include "utils_cmd_putnotif.h" -#include "utils_cmd_putval.h" +#include "utils/cmds/putnotif.h" +#include "utils/cmds/putval.h" #include #include @@ -78,9 +78,14 @@ typedef struct program_list_and_notification_s { } program_list_and_notification_t; /* + * constants + */ +const long int MAX_GRBUF_SIZE = 65536; + +/* * Private variables */ -static program_list_t *pl_head = NULL; +static program_list_t *pl_head; static pthread_mutex_t pl_lock = PTHREAD_MUTEX_INITIALIZER; /* @@ -240,11 +245,17 @@ static int exec_config(oconfig_item_t *ci) /* {{{ */ return 0; } /* int exec_config }}} */ +#if !defined(HAVE_SETENV) +static char env_interval[64]; +// max hostname len is 255, so this should be enough +static char env_hostname[300]; +#endif + static void set_environment(void) /* {{{ */ { +#ifdef HAVE_SETENV char buffer[1024]; -#ifdef HAVE_SETENV snprintf(buffer, sizeof(buffer), "%.3f", CDTIME_T_TO_DOUBLE(plugin_get_interval())); setenv("COLLECTD_INTERVAL", buffer, /* overwrite = */ 1); @@ -252,15 +263,29 @@ static void set_environment(void) /* {{{ */ sstrncpy(buffer, hostname_g, sizeof(buffer)); setenv("COLLECTD_HOSTNAME", buffer, /* overwrite = */ 1); #else - snprintf(buffer, sizeof(buffer), "COLLECTD_INTERVAL=%.3f", + snprintf(env_interval, sizeof(env_interval), "COLLECTD_INTERVAL=%.3f", CDTIME_T_TO_DOUBLE(plugin_get_interval())); - putenv(buffer); + putenv(env_interval); - snprintf(buffer, sizeof(buffer), "COLLECTD_HOSTNAME=%s", hostname_g); - putenv(buffer); + snprintf(env_hostname, sizeof(env_hostname), "COLLECTD_HOSTNAME=%s", + hostname_g); + putenv(env_hostname); #endif } /* }}} void set_environment */ +static void unset_environment(void) /* {{{ */ +{ +#ifdef HAVE_SETENV + unsetenv("COLLECTD_INTERVAL"); + unsetenv("COLLECTD_HOSTNAME"); +#else + snprintf(env_interval, sizeof(env_interval), "COLLECTD_INTERVAL"); + putenv(env_interval); + snprintf(env_hostname, sizeof(env_hostname), "COLLECTD_HOSTNAME"); + putenv(env_hostname); +#endif +} /* }}} void unset_environment */ + __attribute__((noreturn)) static void exec_child(program_list_t *pl, int uid, int gid, int egid) /* {{{ */ { @@ -340,6 +365,65 @@ static void close_pipe(int fd_pipe[2]) /* {{{ */ } /* }}} void close_pipe */ /* + * Get effective group ID from group name. + * Input arguments: + * pl :program list struct with group name + * gid :group id to fallback in case egid cannot be determined. + * Returns: + * egid effective group id if successfull, + * -1 if group is not defined/not found. + * -2 for any buffer allocation error. + */ +static int getegr_id(program_list_t *pl, int gid) /* {{{ */ +{ + if (pl->group == NULL) { + return -1; + } + if (strcmp(pl->group, "") == 0) { + return gid; + } + struct group *gr_ptr = NULL; + struct group gr; + + long int grbuf_size = sysconf(_SC_GETGR_R_SIZE_MAX); + if (grbuf_size <= 0) + grbuf_size = sysconf(_SC_PAGESIZE); + if (grbuf_size <= 0) + grbuf_size = 4096; + + char *temp = NULL; + char *grbuf = NULL; + + do { + temp = realloc(grbuf, grbuf_size); + if (temp == NULL) { + ERROR("exec plugin: getegr_id for %s: realloc buffer[%ld] failed ", + pl->group, grbuf_size); + sfree(grbuf); + return -2; + } + grbuf = temp; + if (getgrnam_r(pl->group, &gr, grbuf, grbuf_size, &gr_ptr) == 0) { + sfree(grbuf); + if (gr_ptr == NULL) { + ERROR("exec plugin: No such group: `%s'", pl->group); + return -1; + } + return gr.gr_gid; + } else if (errno == ERANGE) { + grbuf_size += grbuf_size; // increment buffer size and try again + } else { + ERROR("exec plugin: getegr_id failed %s", STRERRNO); + sfree(grbuf); + return -2; + } + } while (grbuf_size <= MAX_GRBUF_SIZE); + ERROR("exec plugin: getegr_id Max grbuf size reached for %s", pl->group); + sfree(grbuf); + return -2; +} + +/* * Creates three pipes (one for reading, one for writing and one for errors), * forks a child, sets up the pipes so that fd_in is connected to STDIN of * the child and fd_out is connected to STDOUT and fd_err is connected to STDERR @@ -397,36 +481,12 @@ static int fork_child(program_list_t *pl, int *fd_in, int *fd_out, /* The group configured in the configfile is set as effective group, because * this way the forked process can (re-)gain the user's primary group. */ - egid = -1; - if (pl->group != NULL) { - if (*pl->group != '\0') { - struct group *gr_ptr = NULL; - struct group gr; - - long int grbuf_size = sysconf(_SC_GETGR_R_SIZE_MAX); - if (grbuf_size <= 0) - grbuf_size = sysconf(_SC_PAGESIZE); - if (grbuf_size <= 0) - grbuf_size = 4096; - char grbuf[grbuf_size]; - - status = getgrnam_r(pl->group, &gr, grbuf, sizeof(grbuf), &gr_ptr); - if (status != 0) { - ERROR("exec plugin: Failed to get group information " - "for group ``%s'': %s", - pl->group, STRERROR(status)); - goto failed; - } - if (gr_ptr == NULL) { - ERROR("exec plugin: No such group: `%s'", pl->group); - goto failed; - } + egid = getegr_id(pl, gid); + if (egid == -2) { + goto failed; + } - egid = gr.gr_gid; - } else { - egid = gid; - } - } /* if (pl->group == NULL) */ + set_environment(); pid = fork(); if (pid < 0) { @@ -462,8 +522,6 @@ static int fork_child(program_list_t *pl, int *fd_in, int *fd_out, close(fd_pipe_err[1]); } - set_environment(); - /* Unblock all signals */ reset_signal_mask(); @@ -471,6 +529,8 @@ static int fork_child(program_list_t *pl, int *fd_in, int *fd_out, /* does not return */ } + unset_environment(); + close(fd_pipe_in[0]); close(fd_pipe_out[1]); close(fd_pipe_err[1]); @@ -493,6 +553,8 @@ static int fork_child(program_list_t *pl, int *fd_in, int *fd_out, return pid; failed: + unset_environment(); + close_pipe(fd_pipe_in); close_pipe(fd_pipe_out); close_pipe(fd_pipe_err); @@ -692,8 +754,9 @@ static void *exec_notification_one(void *arg) /* {{{ */ else if (n->severity == NOTIF_OKAY) severity = "OKAY"; - fprintf(fh, "Severity: %s\n" - "Time: %.3f\n", + fprintf(fh, + "Severity: %s\n" + "Time: %.3f\n", severity, CDTIME_T_TO_DOUBLE(n->time)); /* Print the optional fields */ @@ -856,6 +919,11 @@ static int exec_shutdown(void) /* {{{ */ INFO("exec plugin: Sent SIGTERM to %hu", (unsigned short int)pl->pid); } + for (int i = 0; pl->argv[i] != NULL; i++) { + sfree(pl->argv[i]); + } + sfree(pl->argv); + sfree(pl->exec); sfree(pl->user); sfree(pl);