X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fexec.c;h=c5ea155ebc53f10e4d191bc84dca0828476a953a;hb=3904b4b9fd1a53c93f31d8fec709a7b7b8300513;hp=d2b2508db209b87fb302ec35dee558016e01cabb;hpb=085a993e0f187ad73d3a28cea508ec6e56c39516;p=collectd.git diff --git a/src/exec.c b/src/exec.c index d2b2508d..c5ea155e 100644 --- a/src/exec.c +++ b/src/exec.c @@ -1,6 +1,6 @@ /** * collectd - src/exec.c - * Copyright (C) 2007-2009 Florian octo Forster + * Copyright (C) 2007-2010 Florian octo Forster * Copyright (C) 2007-2009 Sebastian Harl * Copyright (C) 2008 Peter Holik * @@ -23,6 +23,8 @@ * Peter Holik **/ +#define _BSD_SOURCE /* For setgroups */ + #include "collectd.h" #include "common.h" #include "plugin.h" @@ -91,7 +93,7 @@ static void sigchld_handler (int __attribute__((unused)) signal) /* {{{ */ program_list_t *pl; for (pl = pl_head; pl != NULL; pl = pl->next) if (pl->pid == pid) - break; + break; if (pl != NULL) pl->status = status; } /* while (waitpid) */ @@ -106,20 +108,20 @@ 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); + ci->key); return (-1); } if (ci->values_num < 2) { WARNING ("exec plugin: The config option `%s' needs at least two " - "arguments.", ci->key); + "arguments.", ci->key); 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); + "be string arguments.", ci->key); return (-1); } @@ -199,15 +201,15 @@ static int exec_config_exec (oconfig_item_t *ci) /* {{{ */ { if (ci->values[i + 1].type == OCONFIG_TYPE_NUMBER) { - ssnprintf (buffer, sizeof (buffer), "%lf", - ci->values[i + 1].value.number); + ssnprintf (buffer, sizeof (buffer), "%lf", + ci->values[i + 1].value.number); } else { - if (ci->values[i + 1].value.boolean) - sstrncpy (buffer, "true", sizeof (buffer)); - else - sstrncpy (buffer, "false", sizeof (buffer)); + if (ci->values[i + 1].value.boolean) + sstrncpy (buffer, "true", sizeof (buffer)); + else + sstrncpy (buffer, "false", sizeof (buffer)); } pl->argv[i] = strdup (buffer); @@ -252,7 +254,7 @@ static int exec_config (oconfig_item_t *ci) /* {{{ */ { oconfig_item_t *child = ci->children + i; if ((strcasecmp ("Exec", child->key) == 0) - || (strcasecmp ("NotificationExec", child->key) == 0)) + || (strcasecmp ("NotificationExec", child->key) == 0)) exec_config_exec (child); else { @@ -263,6 +265,27 @@ static int exec_config (oconfig_item_t *ci) /* {{{ */ 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 (interval_g)); + setenv ("COLLECTD_INTERVAL", buffer, /* overwrite = */ 1); + + ssnprintf (buffer, sizeof (buffer), "%s", hostname_g); + setenv ("COLLECTD_HOSTNAME", buffer, /* overwrite = */ 1); +#else + ssnprintf (buffer, sizeof (buffer), "COLLECTD_INTERVAL=%.3f", + CDTIME_T_TO_DOUBLE (interval_g)); + 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 status; @@ -279,8 +302,8 @@ static void exec_child (program_list_t *pl) /* {{{ */ status = getpwnam_r (pl->user, &sp, nambuf, sizeof (nambuf), &sp_ptr); if (status != 0) { - ERROR ("exec plugin: getpwnam_r failed: %s", - sstrerror (errno, errbuf, sizeof (errbuf))); + ERROR ("exec plugin: Failed to get user information for user ``%s'': %s", + pl->user, sstrerror (errno, errbuf, sizeof (errbuf))); exit (-1); } if (sp_ptr == NULL) @@ -309,14 +332,15 @@ static void exec_child (program_list_t *pl) /* {{{ */ status = getgrnam_r (pl->group, &gr, nambuf, sizeof (nambuf), &gr_ptr); if (0 != status) { - ERROR ("exec plugin: getgrnam_r failed: %s", - sstrerror (errno, errbuf, sizeof (errbuf))); - exit (-1); + ERROR ("exec plugin: Failed to get group information " + "for group ``%s'': %s", pl->group, + sstrerror (errno, errbuf, sizeof (errbuf))); + exit (-1); } if (NULL == gr_ptr) { - ERROR ("exec plugin: No such group: `%s'", pl->group); - exit (-1); + ERROR ("exec plugin: No such group: `%s'", pl->group); + exit (-1); } egid = gr.gr_gid; @@ -350,7 +374,7 @@ static void exec_child (program_list_t *pl) /* {{{ */ if (status != 0) { ERROR ("exec plugin: setgid (%i) failed: %s", - gid, sstrerror (errno, errbuf, sizeof (errbuf))); + gid, sstrerror (errno, errbuf, sizeof (errbuf))); exit (-1); } @@ -360,7 +384,7 @@ static void exec_child (program_list_t *pl) /* {{{ */ if (status != 0) { ERROR ("exec plugin: setegid (%i) failed: %s", - egid, sstrerror (errno, errbuf, sizeof (errbuf))); + egid, sstrerror (errno, errbuf, sizeof (errbuf))); exit (-1); } } @@ -369,17 +393,26 @@ static void exec_child (program_list_t *pl) /* {{{ */ if (status != 0) { ERROR ("exec plugin: setuid (%i) failed: %s", - uid, sstrerror (errno, errbuf, sizeof (errbuf))); + uid, sstrerror (errno, errbuf, sizeof (errbuf))); exit (-1); } status = execvp (pl->exec, pl->argv); - ERROR ("exec plugin: exec failed: %s", - sstrerror (errno, errbuf, sizeof (errbuf))); + ERROR ("exec plugin: Failed to execute ``%s'': %s", + pl->exec, sstrerror (errno, errbuf, sizeof (errbuf))); exit (-1); } /* void exec_child }}} */ +static void reset_signal_mask (void) /* {{{ */ +{ + sigset_t ss; + + memset (&ss, 0, sizeof (ss)); + sigemptyset (&ss); + sigprocmask (SIG_SETMASK, &ss, /* old mask = */ NULL); +} /* }}} void reset_signal_mask */ + /* * 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 @@ -402,7 +435,7 @@ static int fork_child (program_list_t *pl, int *fd_in, int *fd_out, int *fd_err) if (status != 0) { ERROR ("exec plugin: pipe failed: %s", - sstrerror (errno, errbuf, sizeof (errbuf))); + sstrerror (errno, errbuf, sizeof (errbuf))); return (-1); } @@ -410,7 +443,7 @@ static int fork_child (program_list_t *pl, int *fd_in, int *fd_out, int *fd_err) if (status != 0) { ERROR ("exec plugin: pipe failed: %s", - sstrerror (errno, errbuf, sizeof (errbuf))); + sstrerror (errno, errbuf, sizeof (errbuf))); return (-1); } @@ -418,7 +451,7 @@ static int fork_child (program_list_t *pl, int *fd_in, int *fd_out, int *fd_err) if (status != 0) { ERROR ("exec plugin: pipe failed: %s", - sstrerror (errno, errbuf, sizeof (errbuf))); + sstrerror (errno, errbuf, sizeof (errbuf))); return (-1); } @@ -426,7 +459,7 @@ static int fork_child (program_list_t *pl, int *fd_in, int *fd_out, int *fd_err) if (pid < 0) { ERROR ("exec plugin: fork failed: %s", - sstrerror (errno, errbuf, sizeof (errbuf))); + sstrerror (errno, errbuf, sizeof (errbuf))); return (-1); } else if (pid == 0) @@ -439,9 +472,9 @@ static int fork_child (program_list_t *pl, int *fd_in, int *fd_out, int *fd_err) for (fd = 0; fd < fd_num; fd++) { if ((fd == fd_pipe_in[0]) - || (fd == fd_pipe_out[1]) - || (fd == fd_pipe_err[1])) - continue; + || (fd == fd_pipe_out[1]) + || (fd == fd_pipe_err[1])) + continue; close (fd); } @@ -466,6 +499,11 @@ static int fork_child (program_list_t *pl, int *fd_in, int *fd_out, int *fd_err) close (fd_pipe_err[1]); } + set_environment (); + + /* Unblock all signals */ + reset_signal_mask (); + exec_child (pl); /* does not return */ } @@ -500,12 +538,9 @@ static int parse_line (char *buffer) /* {{{ */ return (handle_putnotif (stdout, buffer)); else { - /* For backwards compatibility */ - char tmp[1220]; - /* Let's annoy the user a bit.. */ - INFO ("exec plugin: Prepending `PUTVAL' to this line: %s", buffer); - ssnprintf (tmp, sizeof (tmp), "PUTVAL %s", buffer); - return (handle_putval (stdout, tmp)); + ERROR ("exec plugin: Unable to parse command, ignoring line: \"%s\"", + buffer); + return (-1); } } /* int parse_line }}} */ @@ -522,7 +557,13 @@ static void *exec_read_one (void *arg) /* {{{ */ status = fork_child (pl, NULL, &fd, &fd_err); if (status < 0) + { + /* Reset the "running" flag */ + pthread_mutex_lock (&pl_lock); + pl->flags &= ~PL_RUNNING; + pthread_mutex_unlock (&pl_lock); pthread_exit ((void *) 1); + } pl->pid = status; assert (pl->pid != 0); @@ -537,10 +578,18 @@ static void *exec_read_one (void *arg) /* {{{ */ /* We use a copy of fdset, as select modifies it */ copy = fdset; - while (select(highest_fd + 1, ©, NULL, NULL, NULL ) > 0) + while (1) { int len; + status = select (highest_fd + 1, ©, NULL, NULL, NULL); + if (status < 0) + { + if (errno == EINTR) + continue; + break; + } + if (FD_ISSET(fd, ©)) { char *pnl; @@ -591,14 +640,14 @@ static void *exec_read_one (void *arg) /* {{{ */ } else if (len == 0) { - /* We've reached EOF */ - NOTICE ("exec plugin: Program `%s' has closed STDERR.", - pl->exec); - close (fd_err); - FD_CLR (fd_err, &fdset); - highest_fd = fd; - fd_err = -1; - continue; + /* We've reached EOF */ + NOTICE ("exec plugin: Program `%s' has closed STDERR.", + pl->exec); + close (fd_err); + FD_CLR (fd_err, &fdset); + highest_fd = fd; + fd_err = -1; + continue; } pbuffer_err[len] = '\0'; @@ -672,7 +721,7 @@ static void *exec_notification_one (void *arg) /* {{{ */ { char errbuf[1024]; ERROR ("exec plugin: fdopen (%i) failed: %s", fd, - sstrerror (errno, errbuf, sizeof (errbuf))); + sstrerror (errno, errbuf, sizeof (errbuf))); kill (pl->pid, SIGTERM); pl->pid = 0; close (fd); @@ -688,8 +737,8 @@ static void *exec_notification_one (void *arg) /* {{{ */ fprintf (fh, "Severity: %s\n" - "Time: %u\n", - severity, (unsigned int) n->time); + "Time: %.3f\n", + severity, CDTIME_T_TO_DOUBLE (n->time)); /* Print the optional fields */ if (strlen (n->host) > 0) @@ -715,7 +764,7 @@ static void *exec_notification_one (void *arg) /* {{{ */ fprintf (fh, "%s: %e\n", meta->name, meta->nm_value.nm_double); else if (meta->type == NM_TYPE_BOOLEAN) fprintf (fh, "%s: %s\n", meta->name, - meta->nm_value.nm_boolean ? "true" : "false"); + meta->nm_value.nm_boolean ? "true" : "false"); } fprintf (fh, "\n%s\n", n->message); @@ -728,7 +777,8 @@ static void *exec_notification_one (void *arg) /* {{{ */ DEBUG ("exec plugin: Child %i exited with status %i.", pid, status); - plugin_notification_meta_free (n->meta); + if (n->meta != NULL) + plugin_notification_meta_free (n->meta); n->meta = NULL; sfree (arg); pthread_exit ((void *) 0); @@ -777,7 +827,7 @@ static int exec_read (void) /* {{{ */ return (0); } /* int exec_read }}} */ -static int exec_notification (const notification_t *n, +static int exec_notification (const notification_t *n, /* {{{ */ user_data_t __attribute__((unused)) *user_data) { program_list_t *pl; @@ -797,7 +847,7 @@ static int exec_notification (const notification_t *n, continue; pln = (program_list_and_notification_t *) malloc (sizeof - (program_list_and_notification_t)); + (program_list_and_notification_t)); if (pln == NULL) { ERROR ("exec plugin: malloc failed.");