X-Git-Url: https://git.octo.it/?p=collectd.git;a=blobdiff_plain;f=src%2Fexec.c;h=f8707d4181269d82d4a87d1afb9b496ef0914a8f;hp=e0d1f890441c7eff7c099c55d435907aa4f708bc;hb=48efd3deb4c9139fd060ff3d289896e9031bcc7c;hpb=a12cee5932f08301342cf444ebff4e5aa0d433a7 diff --git a/src/exec.c b/src/exec.c index e0d1f890..f8707d41 100644 --- a/src/exec.c +++ b/src/exec.c @@ -26,13 +26,16 @@ #define _DEFAULT_SOURCE #define _BSD_SOURCE /* For setgroups */ +/* _GNU_SOURCE is needed in Linux to use execvpe */ +#define _GNU_SOURCE + #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 @@ -43,6 +46,8 @@ #include #endif +extern char **environ; + #define PL_NORMAL 0x01 #define PL_NOTIF_ACTION 0x02 @@ -85,7 +90,7 @@ 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; /* @@ -113,26 +118,26 @@ static int exec_config_exec(oconfig_item_t *ci) /* {{{ */ if (ci->children_num != 0) { WARNING("exec plugin: The config option `%s' may not be a block.", ci->key); - return (-1); + return -1; } if (ci->values_num < 2) { WARNING("exec plugin: The config option `%s' needs at least two " "arguments.", ci->key); - return (-1); + return -1; } if ((ci->values[0].type != OCONFIG_TYPE_STRING) || (ci->values[1].type != OCONFIG_TYPE_STRING)) { WARNING("exec plugin: The first two arguments to the `%s' option must " "be string arguments.", ci->key); - return (-1); + return -1; } pl = calloc(1, sizeof(*pl)); if (pl == NULL) { ERROR("exec plugin: calloc failed."); - return (-1); + return -1; } if (strcasecmp("NotificationExec", ci->key) == 0) @@ -144,7 +149,7 @@ static int exec_config_exec(oconfig_item_t *ci) /* {{{ */ if (pl->user == NULL) { ERROR("exec plugin: strdup failed."); sfree(pl); - return (-1); + return -1; } pl->group = strchr(pl->user, ':'); @@ -158,7 +163,7 @@ static int exec_config_exec(oconfig_item_t *ci) /* {{{ */ ERROR("exec plugin: strdup failed."); sfree(pl->user); sfree(pl); - return (-1); + return -1; } pl->argv = calloc(ci->values_num, sizeof(*pl->argv)); @@ -167,7 +172,7 @@ static int exec_config_exec(oconfig_item_t *ci) /* {{{ */ sfree(pl->exec); sfree(pl->user); sfree(pl); - return (-1); + return -1; } { @@ -184,7 +189,7 @@ static int exec_config_exec(oconfig_item_t *ci) /* {{{ */ sfree(pl->exec); sfree(pl->user); sfree(pl); - return (-1); + return -1; } for (i = 1; i < (ci->values_num - 1); i++) { @@ -192,8 +197,7 @@ static int exec_config_exec(oconfig_item_t *ci) /* {{{ */ pl->argv[i] = strdup(ci->values[i + 1].value.string); } else { if (ci->values[i + 1].type == OCONFIG_TYPE_NUMBER) { - ssnprintf(buffer, sizeof(buffer), "%lf", - ci->values[i + 1].value.number); + snprintf(buffer, sizeof(buffer), "%lf", ci->values[i + 1].value.number); } else { if (ci->values[i + 1].value.boolean) sstrncpy(buffer, "true", sizeof(buffer)); @@ -218,7 +222,7 @@ static int exec_config_exec(oconfig_item_t *ci) /* {{{ */ sfree(pl->exec); sfree(pl->user); sfree(pl); - return (-1); + return -1; } for (i = 0; pl->argv[i] != NULL; i++) { @@ -228,7 +232,7 @@ static int exec_config_exec(oconfig_item_t *ci) /* {{{ */ pl->next = pl_head; pl_head = pl; - return (0); + return 0; } /* int exec_config_exec }}} */ static int exec_config(oconfig_item_t *ci) /* {{{ */ @@ -243,35 +247,14 @@ static int exec_config(oconfig_item_t *ci) /* {{{ */ } } /* for (i) */ - return (0); + return 0; } /* int exec_config }}} */ -static void set_environment(void) /* {{{ */ -{ - char buffer[1024]; - -#ifdef HAVE_SETENV - ssnprintf(buffer, sizeof(buffer), "%.3f", - CDTIME_T_TO_DOUBLE(plugin_get_interval())); - setenv("COLLECTD_INTERVAL", buffer, /* overwrite = */ 1); - - sstrncpy(buffer, hostname_g, sizeof(buffer)); - setenv("COLLECTD_HOSTNAME", buffer, /* overwrite = */ 1); -#else - ssnprintf(buffer, sizeof(buffer), "COLLECTD_INTERVAL=%.3f", - CDTIME_T_TO_DOUBLE(plugin_get_interval())); - putenv(buffer); - - ssnprintf(buffer, sizeof(buffer), "COLLECTD_HOSTNAME=%s", hostname_g); - putenv(buffer); -#endif -} /* }}} void set_environment */ - -__attribute__((noreturn)) static void exec_child(program_list_t *pl, int uid, - int gid, int egid) /* {{{ */ +__attribute__((noreturn)) static void exec_child(program_list_t *pl, + char **envp, int uid, int gid, + int egid) /* {{{ */ { int status; - char errbuf[1024]; #if HAVE_SETGROUPS if (getuid() == 0) { @@ -292,31 +275,32 @@ __attribute__((noreturn)) static void exec_child(program_list_t *pl, int uid, status = setgid(gid); if (status != 0) { - ERROR("exec plugin: setgid (%i) failed: %s", gid, - sstrerror(errno, errbuf, sizeof(errbuf))); + ERROR("exec plugin: setgid (%i) failed: %s", gid, STRERRNO); exit(-1); } if (egid != -1) { status = setegid(egid); if (status != 0) { - ERROR("exec plugin: setegid (%i) failed: %s", egid, - sstrerror(errno, errbuf, sizeof(errbuf))); + ERROR("exec plugin: setegid (%i) failed: %s", egid, STRERRNO); exit(-1); } } status = setuid(uid); if (status != 0) { - ERROR("exec plugin: setuid (%i) failed: %s", uid, - sstrerror(errno, errbuf, sizeof(errbuf))); + ERROR("exec plugin: setuid (%i) failed: %s", uid, STRERRNO); exit(-1); } +#ifdef HAVE_EXECVPE + execvpe(pl->exec, pl->argv, envp); +#else + environ = envp; execvp(pl->exec, pl->argv); +#endif - ERROR("exec plugin: Failed to execute ``%s'': %s", pl->exec, - sstrerror(errno, errbuf, sizeof(errbuf))); + ERROR("exec plugin: Failed to execute ``%s'': %s", pl->exec, STRERRNO); exit(-1); } /* void exec_child }}} */ @@ -330,14 +314,12 @@ static void reset_signal_mask(void) /* {{{ */ static int create_pipe(int fd_pipe[2]) /* {{{ */ { - char errbuf[1024]; int status; status = pipe(fd_pipe); if (status != 0) { - ERROR("exec plugin: pipe failed: %s", - sstrerror(errno, errbuf, sizeof(errbuf))); - return (-1); + ERROR("exec plugin: pipe failed: %s", STRERRNO); + return -1; } return 0; @@ -401,9 +383,7 @@ static int getegr_id(program_list_t *pl, int gid) /* {{{ */ } else if (errno == ERANGE) { grbuf_size += grbuf_size; // increment buffer size and try again } else { - char errbuf[1024]; - ERROR("exec plugin: getegr_id failed %s", - sstrerror(errno, errbuf, sizeof(errbuf))); + ERROR("exec plugin: getegr_id failed %s", STRERRNO); sfree(grbuf); return -2; } @@ -411,7 +391,7 @@ static int getegr_id(program_list_t *pl, int gid) /* {{{ */ 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), @@ -425,7 +405,6 @@ static int fork_child(program_list_t *pl, int *fd_in, int *fd_out, int fd_pipe_in[2] = {-1, -1}; int fd_pipe_out[2] = {-1, -1}; int fd_pipe_err[2] = {-1, -1}; - char errbuf[1024]; int status; int pid; @@ -437,7 +416,7 @@ static int fork_child(program_list_t *pl, int *fd_in, int *fd_out, struct passwd sp; if (pl->pid != 0) - return (-1); + return -1; long int nambuf_size = sysconf(_SC_GETPW_R_SIZE_MAX); if (nambuf_size <= 0) @@ -454,7 +433,7 @@ static int fork_child(program_list_t *pl, int *fd_in, int *fd_out, status = getpwnam_r(pl->user, &sp, nambuf, sizeof(nambuf), &sp_ptr); if (status != 0) { ERROR("exec plugin: Failed to get user information for user ``%s'': %s", - pl->user, sstrerror(status, errbuf, sizeof(errbuf))); + pl->user, STRERROR(status)); goto failed; } @@ -470,21 +449,49 @@ static int fork_child(program_list_t *pl, int *fd_in, int *fd_out, goto failed; } + /* 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 = getegr_id(pl, gid); if (egid == -2) { goto failed; } + double interval = CDTIME_T_TO_DOUBLE(plugin_get_interval()); + pid = fork(); if (pid < 0) { - ERROR("exec plugin: fork failed: %s", - sstrerror(errno, errbuf, sizeof(errbuf))); + ERROR("exec plugin: fork failed: %s", STRERRNO); goto failed; } else if (pid == 0) { - int fd_num; + char interval_buf[128]; + snprintf(interval_buf, sizeof(interval_buf), "COLLECTD_INTERVAL=%.3f", + interval); + + /* max hostname len is 255, so this should be enough */ + char hostname_buf[300]; + snprintf(hostname_buf, sizeof(hostname_buf), "COLLECTD_HOSTNAME=%s", + hostname_g); + + size_t env_size = 0; + while (environ[env_size] != NULL) { + ++env_size; + } + + /* Copy the environment variables */ + char *envp[env_size + 3]; + size_t envp_idx; + for (envp_idx = 0; environ[envp_idx] != NULL && envp_idx < env_size; + ++envp_idx) { + envp[envp_idx] = environ[envp_idx]; + } + + /* Add the collectd environment variables */ + envp[envp_idx++] = interval_buf; + envp[envp_idx++] = hostname_buf; + envp[envp_idx++] = NULL; /* Close all file descriptors but the pipe end we need. */ - fd_num = getdtablesize(); + int fd_num = getdtablesize(); for (int fd = 0; fd < fd_num; fd++) { if ((fd == fd_pipe_in[0]) || (fd == fd_pipe_out[1]) || (fd == fd_pipe_err[1])) @@ -510,12 +517,10 @@ 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(); - exec_child(pl, uid, gid, egid); + exec_child(pl, envp, uid, gid, egid); /* does not return */ } @@ -538,26 +543,26 @@ static int fork_child(program_list_t *pl, int *fd_in, int *fd_out, else close(fd_pipe_err[0]); - return (pid); + return pid; failed: close_pipe(fd_pipe_in); close_pipe(fd_pipe_out); close_pipe(fd_pipe_err); - return (-1); + return -1; } /* int fork_child }}} */ static int parse_line(char *buffer) /* {{{ */ { if (strncasecmp("PUTVAL", buffer, strlen("PUTVAL")) == 0) - return (cmd_handle_putval(stdout, buffer)); + return cmd_handle_putval(stdout, buffer); else if (strncasecmp("PUTNOTIF", buffer, strlen("PUTNOTIF")) == 0) - return (handle_putnotif(stdout, buffer)); + return handle_putnotif(stdout, buffer); else { ERROR("exec plugin: Unable to parse command, ignoring line: \"%s\"", buffer); - return (-1); + return -1; } } /* int parse_line }}} */ @@ -706,7 +711,7 @@ static void *exec_read_one(void *arg) /* {{{ */ close(fd_err); pthread_exit((void *)0); - return (NULL); + return NULL; } /* void *exec_read_one }}} */ static void *exec_notification_one(void *arg) /* {{{ */ @@ -727,9 +732,7 @@ static void *exec_notification_one(void *arg) /* {{{ */ fh = fdopen(fd, "w"); if (fh == NULL) { - char errbuf[1024]; - ERROR("exec plugin: fdopen (%i) failed: %s", fd, - sstrerror(errno, errbuf, sizeof(errbuf))); + ERROR("exec plugin: fdopen (%i) failed: %s", fd, STRERRNO); kill(pid, SIGTERM); close(fd); sfree(arg); @@ -742,8 +745,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 */ @@ -788,7 +792,7 @@ static void *exec_notification_one(void *arg) /* {{{ */ n->meta = NULL; sfree(arg); pthread_exit((void *)0); - return (NULL); + return NULL; } /* void *exec_notification_one }}} */ static int exec_init(void) /* {{{ */ @@ -814,7 +818,7 @@ static int exec_init(void) /* {{{ */ } #endif - return (0); + return 0; } /* int exec_init }}} */ static int exec_read(void) /* {{{ */ @@ -846,7 +850,7 @@ static int exec_read(void) /* {{{ */ pthread_attr_destroy(&attr); } /* for (pl) */ - return (0); + return 0; } /* int exec_read }}} */ static int exec_notification(const notification_t *n, /* {{{ */ @@ -889,7 +893,7 @@ static int exec_notification(const notification_t *n, /* {{{ */ pthread_attr_destroy(&attr); } /* for (pl) */ - return (0); + return 0; } /* }}} int exec_notification */ static int exec_shutdown(void) /* {{{ */ @@ -906,6 +910,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); @@ -913,7 +922,7 @@ static int exec_shutdown(void) /* {{{ */ } /* while (pl) */ pl_head = NULL; - return (0); + return 0; } /* int exec_shutdown }}} */ void module_register(void) { @@ -924,7 +933,3 @@ void module_register(void) { /* user_data = */ NULL); plugin_register_shutdown("exec", exec_shutdown); } /* void module_register */ - -/* - * vim:shiftwidth=2:softtabstop=2:tabstop=8:fdm=marker - */