X-Git-Url: https://git.octo.it/?p=collectd.git;a=blobdiff_plain;f=src%2Fcollectdctl.c;h=2329285371281e849e5bf82994111912201d2036;hp=f697e5fd27817b2b74d600e33765b2dd38f587c6;hb=633c3966f770e4d46651a2fe219a18d8a9907a9f;hpb=5b4655df8b9d8e60d0502b0c6ecdcb05e99f7fc7 diff --git a/src/collectdctl.c b/src/collectdctl.c index f697e5fd..23292853 100644 --- a/src/collectdctl.c +++ b/src/collectdctl.c @@ -25,19 +25,47 @@ # include "config.h" #endif -#include "libcollectdclient/client.h" +#include +#include +#include +#include +#include #include - #include -#include - -#include -#include -#include - -#include +#if NAN_STATIC_DEFAULT +# include +/* #endif NAN_STATIC_DEFAULT*/ +#elif NAN_STATIC_ISOC +# ifndef __USE_ISOC99 +# define DISABLE_ISOC99 1 +# define __USE_ISOC99 1 +# endif /* !defined(__USE_ISOC99) */ +# include +# if DISABLE_ISOC99 +# undef DISABLE_ISOC99 +# undef __USE_ISOC99 +# endif /* DISABLE_ISOC99 */ +/* #endif NAN_STATIC_ISOC */ +#elif NAN_ZERO_ZERO +# include +# ifdef NAN +# undef NAN +# endif +# define NAN (0.0 / 0.0) +# ifndef isnan +# define isnan(f) ((f) != (f)) +# endif /* !defined(isnan) */ +# ifndef isfinite +# define isfinite(f) (((f) - (f)) == 0.0) +# endif +# ifndef isinf +# define isinf(f) (!isfinite(f) && !isnan(f)) +# endif +#endif /* NAN_ZERO_ZERO */ + +#include "libcollectdclient/collectd/client.h" #define DEFAULT_SOCK LOCALSTATEDIR"/run/"PACKAGE_NAME"-unixsock" @@ -59,6 +87,7 @@ static void exit_usage (const char *name, int status) { " * getval \n" " * flush [timeout=] [plugin=] [identifier=]\n" " * listval\n" + " * putval [interval=] \n" "\nIdentifiers:\n\n" @@ -69,15 +98,8 @@ static void exit_usage (const char *name, int status) { "Hostname defaults to the local hostname if omitted (e.g., uptime/uptime).\n" "No error is returned if the specified identifier does not exist.\n" - "\nExample:\n\n" - - " collectdctl flush plugin=rrdtool identifie=somehost/cpu-0/cpu-wait\n\n" - - "Flushes all CPU wait RRD values of the first CPU of the local host.\n" - "I.e., writes all pending RRD updates of that data-source to disk.\n" - "\n"PACKAGE" "VERSION", http://collectd.org/\n" - "by Florian octo Forster \n" + "by Florian octo Forster \n" "for contributions see `AUTHORS'\n" , name); exit (status); @@ -98,6 +120,23 @@ static int count_chars (const char *str, char chr) { return count; } /* count_chars */ +static int array_grow (void **array, int *array_len, size_t elem_size) +{ + void *tmp; + + assert ((array != NULL) && (array_len != NULL)); + + tmp = realloc (*array, (*array_len + 1) * elem_size); + if (tmp == NULL) { + fprintf (stderr, "ERROR: Failed to allocate memory.\n"); + return (-1); + } + + *array = tmp; + ++(*array_len); + return (0); +} /* array_grow */ + static int parse_identifier (lcc_connection_t *c, const char *value, lcc_identifier_t *ident) { @@ -182,21 +221,35 @@ static int getval (lcc_connection_t *c, int argc, char **argv) for (i = 0; i < ret_values_num; ++i) printf ("%s=%e\n", ret_values_names[i], ret_values[i]); BAIL_OUT (0); +#undef BAIL_OUT } /* getval */ static int flush (lcc_connection_t *c, int argc, char **argv) { - lcc_identifier_t ident; - lcc_identifier_t *identp = NULL; + int timeout = -1; - char *plugin = NULL; - int timeout = -1; + lcc_identifier_t *identifiers = NULL; + int identifiers_num = 0; + + char **plugins = NULL; + int plugins_num = 0; int status; int i; assert (strcasecmp (argv[0], "flush") == 0); +#define BAIL_OUT(s) \ + do { \ + if (identifiers != NULL) \ + free (identifiers); \ + identifiers_num = 0; \ + if (plugins != NULL) \ + free (plugins); \ + plugins_num = 0; \ + return (s); \ + } while (0) + for (i = 1; i < argc; ++i) { char *key, *value; @@ -205,7 +258,7 @@ static int flush (lcc_connection_t *c, int argc, char **argv) if (! value) { fprintf (stderr, "ERROR: flush: Invalid option ``%s''.\n", argv[i]); - return (-1); + BAIL_OUT (-1); } *value = '\0'; @@ -214,12 +267,12 @@ static int flush (lcc_connection_t *c, int argc, char **argv) if (strcasecmp (key, "timeout") == 0) { char *endptr = NULL; - timeout = strtol (value, &endptr, 0); + timeout = (int) strtol (value, &endptr, 0); if (endptr == value) { fprintf (stderr, "ERROR: Failed to parse timeout as number: %s.\n", value); - return (-1); + BAIL_OUT (-1); } else if ((endptr != NULL) && (*endptr != '\0')) { fprintf (stderr, "WARNING: Ignoring trailing garbage after timeout: " @@ -227,27 +280,66 @@ static int flush (lcc_connection_t *c, int argc, char **argv) } } else if (strcasecmp (key, "plugin") == 0) { - plugin = value; + status = array_grow ((void *)&plugins, &plugins_num, + sizeof (*plugins)); + if (status != 0) + BAIL_OUT (status); + + plugins[plugins_num - 1] = value; } else if (strcasecmp (key, "identifier") == 0) { - int status; + status = array_grow ((void *)&identifiers, &identifiers_num, + sizeof (*identifiers)); + if (status != 0) + BAIL_OUT (status); - memset (&ident, 0, sizeof (ident)); - status = parse_identifier (c, value, &ident); + memset (identifiers + (identifiers_num - 1), 0, sizeof (*identifiers)); + status = parse_identifier (c, value, + identifiers + (identifiers_num - 1)); if (status != 0) - return (status); - identp = &ident; + BAIL_OUT (status); + } + else { + fprintf (stderr, "ERROR: flush: Unknown option `%s'.\n", key); + BAIL_OUT (-1); } } - status = lcc_flush (c, plugin, identp, timeout); - if (status != 0) { - fprintf (stderr, "ERROR: Flushing failed: %s.\n", - lcc_strerror (c)); - return (-1); + if (plugins_num == 0) { + status = array_grow ((void *)&plugins, &plugins_num, sizeof (*plugins)); + if (status != 0) + BAIL_OUT (status); + + assert (plugins_num == 1); + plugins[0] = NULL; } - return 0; + for (i = 0; i < plugins_num; ++i) { + if (identifiers_num == 0) { + status = lcc_flush (c, plugins[i], NULL, timeout); + if (status != 0) + fprintf (stderr, "ERROR: Failed to flush plugin `%s': %s.\n", + (plugins[i] == NULL) ? "(all)" : plugins[i], lcc_strerror (c)); + } + else { + int j; + + for (j = 0; j < identifiers_num; ++j) { + status = lcc_flush (c, plugins[i], identifiers + j, timeout); + if (status != 0) { + char id[1024]; + + lcc_identifier_to_string (c, id, sizeof (id), identifiers + j); + fprintf (stderr, "ERROR: Failed to flush plugin `%s', " + "identifier `%s': %s.\n", + (plugins[i] == NULL) ? "(all)" : plugins[i], + id, lcc_strerror (c)); + } + } + } + } + + BAIL_OUT (0); #undef BAIL_OUT } /* flush */ @@ -296,6 +388,161 @@ static int listval (lcc_connection_t *c, int argc, char **argv) #undef BAIL_OUT } /* listval */ +static int putval (lcc_connection_t *c, int argc, char **argv) +{ + lcc_value_list_t vl = LCC_VALUE_LIST_INIT; + + /* 64 ought to be enough for anybody ;-) */ + value_t values[64]; + int values_types[64]; + size_t values_len = 0; + + int status; + int i; + + assert (strcasecmp (argv[0], "putval") == 0); + + if (argc < 3) { + fprintf (stderr, "ERROR: putval: Missing identifier " + "and/or value list.\n"); + return (-1); + } + + vl.values = values; + vl.values_types = values_types; + + status = parse_identifier (c, argv[1], &vl.identifier); + if (status != 0) + return (status); + + for (i = 2; i < argc; ++i) { + char *tmp; + + tmp = strchr (argv[i], (int)'='); + + if (tmp != NULL) { /* option */ + char *key = argv[i]; + char *value = tmp; + + *value = '\0'; + ++value; + + if (strcasecmp (key, "interval") == 0) { + char *endptr; + + vl.interval = strtol (value, &endptr, 0); + + if (endptr == value) { + fprintf (stderr, "ERROR: Failed to parse interval as number: %s.\n", + value); + return (-1); + } + else if ((endptr != NULL) && (*endptr != '\0')) { + fprintf (stderr, "WARNING: Ignoring trailing garbage after " + "interval: %s.\n", endptr); + } + } + else { + fprintf (stderr, "ERROR: putval: Unknown option `%s'.\n", key); + return (-1); + } + } + else { /* value list */ + char *value; + + tmp = strchr (argv[i], (int)':'); + + if (tmp == NULL) { + fprintf (stderr, "ERROR: putval: Invalid value list: %s.\n", + argv[i]); + return (-1); + } + + *tmp = '\0'; + ++tmp; + + if (strcasecmp (argv[i], "N") == 0) { + vl.time = 0; + } + else { + char *endptr; + + vl.time = strtol (argv[i], &endptr, 0); + + if (endptr == argv[i]) { + fprintf (stderr, "ERROR: Failed to parse time as number: %s.\n", + argv[i]); + return (-1); + } + else if ((endptr != NULL) && (*endptr != '\0')) { + fprintf (stderr, "ERROR: Garbage after time: %s.\n", endptr); + return (-1); + } + } + + values_len = 0; + value = tmp; + while (value != 0) { + char *dot, *endptr; + + tmp = strchr (value, (int)':'); + + if (tmp != NULL) { + *tmp = '\0'; + ++tmp; + } + + /* This is a bit of a hack, but parsing types.db just does not make + * much sense imho -- the server might have different types defined + * anyway. Also, lcc uses the type information for formatting the + * number only, so the real meaning does not matter. -tokkee */ + dot = strchr (value, (int)'.'); + endptr = NULL; + if (strcasecmp (value, "U") == 0) { + values[values_len].gauge = NAN; + values_types[values_len] = LCC_TYPE_GAUGE; + } + else if (dot) { /* floating point value */ + values[values_len].gauge = strtod (value, &endptr); + values_types[values_len] = LCC_TYPE_GAUGE; + } + else { /* integer */ + values[values_len].counter = strtol (value, &endptr, 0); + values_types[values_len] = LCC_TYPE_COUNTER; + } + ++values_len; + + if (endptr == value) { + fprintf (stderr, "ERROR: Failed to parse value as number: %s.\n", + argv[i]); + return (-1); + } + else if ((endptr != NULL) && (*endptr != '\0')) { + fprintf (stderr, "ERROR: Garbage after value: %s.\n", endptr); + return (-1); + } + + value = tmp; + } + + assert (values_len >= 1); + vl.values_len = values_len; + + status = lcc_putval (c, &vl); + if (status != 0) { + fprintf (stderr, "ERROR: %s\n", lcc_strerror (c)); + return (-1); + } + } + } + + if (values_len == 0) { + fprintf (stderr, "ERROR: putval: Missing value list(s).\n"); + return (-1); + } + return (0); +} /* putval */ + int main (int argc, char **argv) { char address[1024] = "unix:"DEFAULT_SOCK; @@ -343,6 +590,8 @@ int main (int argc, char **argv) { status = flush (c, argc - optind, argv + optind); else if (strcasecmp (argv[optind], "listval") == 0) status = listval (c, argc - optind, argv + optind); + else if (strcasecmp (argv[optind], "putval") == 0) + status = putval (c, argc - optind, argv + optind); else { fprintf (stderr, "%s: invalid command: %s\n", argv[0], argv[optind]); return (1);