X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fcommon.c;h=c6a651dc56248050ccc0b7a50c7aca68e4f2c3f9;hb=902f7621661d97dac0c7bc83f39acbf76a3b947b;hp=c4994a2c2e017e44ae7c2108ed29550698b71f0e;hpb=aec55dfa7f94fd4ff99cec0767e6ffed93a21339;p=collectd.git diff --git a/src/common.c b/src/common.c index c4994a2c..c6a651dc 100644 --- a/src/common.c +++ b/src/common.c @@ -1,6 +1,6 @@ /** * collectd - src/common.c - * Copyright (C) 2005-2008 Florian octo Forster + * Copyright (C) 2005-2009 Florian octo Forster * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -18,6 +18,8 @@ * Authors: * Florian octo Forster * Niki W. Waibel + * Sebastian Harl + * Michał Mirosław **/ #if HAVE_CONFIG_H @@ -41,6 +43,15 @@ # include #endif +/* for getaddrinfo */ +#include +#include +#include + +#if HAVE_NETINET_IN_H +# include +#endif + #ifdef HAVE_LIBKSTAT extern kstat_ctl_t *kc; #endif @@ -251,7 +262,7 @@ int strsplit (char *string, char **fields, size_t size) break; } - return (i); + return ((int) i); } int strjoin (char *dst, size_t dst_len, @@ -315,6 +326,40 @@ int strsubstitute (char *str, char c_from, char c_to) return (ret); } /* int strsubstitute */ +int strunescape (char *buf, size_t buf_len) +{ + size_t i; + + for (i = 0; (i < buf_len) && (buf[i] != '\0'); ++i) + { + if (buf[i] != '\\') + continue; + + if ((i >= buf_len) || (buf[i + 1] == '\0')) { + ERROR ("string unescape: backslash found at end of string."); + return (-1); + } + + switch (buf[i + 1]) { + case 't': + buf[i] = '\t'; + break; + case 'n': + buf[i] = '\n'; + break; + case 'r': + buf[i] = '\r'; + break; + default: + buf[i] = buf[i + 1]; + break; + } + + memmove (buf + i + 1, buf + i + 2, buf_len - i - 2); + } + return (0); +} /* int strunescape */ + int escape_slashes (char *buf, int buf_len) { int i; @@ -480,7 +525,8 @@ int check_create_dir (const char *file_orig) */ if (fields[i][0] == '.') { - ERROR ("Cowardly refusing to create a directory that begins with a `.' (dot): `%s'", file_orig); + ERROR ("Cowardly refusing to create a directory that " + "begins with a `.' (dot): `%s'", file_orig); return (-2); } @@ -495,32 +541,42 @@ int check_create_dir (const char *file_orig) return (-1); } - if (stat (dir, &statbuf) == -1) - { - if (errno == ENOENT) + while (42) { + if (stat (dir, &statbuf) == -1) { - if (mkdir (dir, 0755) == -1) + if (errno == ENOENT) { + if (mkdir (dir, 0755) == 0) + break; + + /* this might happen, if a different thread created + * the directory in the meantime + * => call stat() again to check for S_ISDIR() */ + if (EEXIST == errno) + continue; + char errbuf[1024]; ERROR ("check_create_dir: mkdir (%s): %s", dir, sstrerror (errno, errbuf, sizeof (errbuf))); return (-1); } + else + { + char errbuf[1024]; + ERROR ("check_create_dir: stat (%s): %s", dir, + sstrerror (errno, errbuf, + sizeof (errbuf))); + return (-1); + } } - else + else if (!S_ISDIR (statbuf.st_mode)) { - char errbuf[1024]; - ERROR ("stat (%s): %s", dir, - sstrerror (errno, errbuf, - sizeof (errbuf))); + ERROR ("check_create_dir: `%s' exists but is not " + "a directory!", dir); return (-1); } - } - else if (!S_ISDIR (statbuf.st_mode)) - { - ERROR ("stat (%s): Not a directory!", dir); - return (-1); + break; } } @@ -531,26 +587,26 @@ int check_create_dir (const char *file_orig) int get_kstat (kstat_t **ksp_ptr, char *module, int instance, char *name) { char ident[128]; + + *ksp_ptr = NULL; if (kc == NULL) return (-1); ssnprintf (ident, sizeof (ident), "%s,%i,%s", module, instance, name); + *ksp_ptr = kstat_lookup (kc, module, instance, name); if (*ksp_ptr == NULL) { - if ((*ksp_ptr = kstat_lookup (kc, module, instance, name)) == NULL) - { - ERROR ("Cound not find kstat %s", ident); - return (-1); - } + ERROR ("get_kstat: Cound not find kstat %s", ident); + return (-1); + } - if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED) - { - WARNING ("kstat %s has wrong type", ident); - *ksp_ptr = NULL; - return (-1); - } + if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED) + { + ERROR ("get_kstat: kstat %s has wrong type", ident); + *ksp_ptr = NULL; + return (-1); } #ifdef assert @@ -560,13 +616,13 @@ int get_kstat (kstat_t **ksp_ptr, char *module, int instance, char *name) if (kstat_read (kc, *ksp_ptr, NULL) == -1) { - WARNING ("kstat %s could not be read", ident); + ERROR ("get_kstat: kstat %s could not be read", ident); return (-1); } if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED) { - WARNING ("kstat %s has wrong type", ident); + ERROR ("get_kstat: kstat %s has wrong type", ident); return (-1); } @@ -790,28 +846,41 @@ int parse_identifier (char *str, char **ret_host, return (0); } /* int parse_identifier */ -int parse_value (const char *value, value_t *ret_value, const data_source_t ds) +int parse_value (const char *value, value_t *ret_value, int ds_type) { - char *endptr = NULL; - - if (DS_TYPE_COUNTER == ds.type) - ret_value->counter = (counter_t)strtoll (value, &endptr, 0); - else if (DS_TYPE_GAUGE == ds.type) - ret_value->gauge = (gauge_t)strtod (value, &endptr); - else { - ERROR ("parse_value: Invalid data source \"%s\" " - "(type = %i).", ds.name, ds.type); - return -1; - } - - if (value == endptr) { - ERROR ("parse_value: Failed to parse string as number: %s.", value); - return -1; - } - else if ((NULL != endptr) && ('\0' != *endptr)) - WARNING ("parse_value: Ignoring trailing garbage after number: %s.", - endptr); - return 0; + char *endptr = NULL; + + switch (ds_type) + { + case DS_TYPE_COUNTER: + ret_value->counter = (counter_t) strtoull (value, &endptr, 0); + break; + + case DS_TYPE_GAUGE: + ret_value->gauge = (gauge_t) strtod (value, &endptr); + break; + + case DS_TYPE_DERIVE: + ret_value->counter = (derive_t) strtoll (value, &endptr, 0); + break; + + case DS_TYPE_ABSOLUTE: + ret_value->counter = (absolute_t) strtoull (value, &endptr, 0); + break; + + default: + ERROR ("parse_value: Invalid data source type: %i.", ds_type); + return -1; + } + + if (value == endptr) { + ERROR ("parse_value: Failed to parse string as number: %s.", value); + return -1; + } + else if ((NULL != endptr) && ('\0' != *endptr)) + WARNING ("parse_value: Ignoring trailing garbage after number: %s.", + endptr); + return 0; } /* int parse_value */ int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds) @@ -829,7 +898,11 @@ int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds) dummy = NULL; if (i >= vl->values_len) + { + /* Make sure i is invalid. */ + i = vl->values_len + 1; break; + } if (i == -1) { @@ -842,7 +915,7 @@ int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds) { if ((strcmp ("U", ptr) == 0) && (ds->ds[i].type == DS_TYPE_GAUGE)) vl->values[i].gauge = NAN; - else if (0 != parse_value (ptr, &vl->values[i], ds->ds[i])) + else if (0 != parse_value (ptr, &vl->values[i], ds->ds[i].type)) return -1; } @@ -1007,3 +1080,56 @@ counter_t counter_diff (counter_t old_value, counter_t new_value) return (diff); } /* counter_t counter_to_gauge */ + +int service_name_to_port_number (const char *service_name) +{ + struct addrinfo *ai_list; + struct addrinfo *ai_ptr; + struct addrinfo ai_hints; + int status; + int service_number; + + if (service_name == NULL) + return (-1); + + ai_list = NULL; + memset (&ai_hints, 0, sizeof (ai_hints)); + ai_hints.ai_family = AF_UNSPEC; + + status = getaddrinfo (/* node = */ NULL, service_name, + &ai_hints, &ai_list); + if (status != 0) + { + ERROR ("service_name_to_port_number: getaddrinfo failed: %s", + gai_strerror (status)); + return (-1); + } + + service_number = -1; + for (ai_ptr = ai_list; ai_ptr != NULL; ai_ptr = ai_ptr->ai_next) + { + if (ai_ptr->ai_family == AF_INET) + { + struct sockaddr_in *sa; + + sa = (void *) ai_ptr->ai_addr; + service_number = (int) ntohs (sa->sin_port); + } + else if (ai_ptr->ai_family == AF_INET6) + { + struct sockaddr_in6 *sa; + + sa = (void *) ai_ptr->ai_addr; + service_number = (int) ntohs (sa->sin6_port); + } + + if ((service_number > 0) && (service_number <= 65535)) + break; + } + + freeaddrinfo (ai_list); + + if ((service_number > 0) && (service_number <= 65535)) + return (service_number); + return (-1); +} /* int service_name_to_port_number */