X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fdaemon%2Fcommon.c;h=7ead55d12a411b62ad1831c9618a1f87ecaa3d6e;hb=7b8851b26928b609ce850e78c1eabb50ff319244;hp=f54cb40d74a0737e8dc35e20224fe6086a50db1d;hpb=3933d0a0e2a8887b40c77ac0a92c1cac79f9b4a1;p=collectd.git diff --git a/src/daemon/common.c b/src/daemon/common.c index f54cb40d..3ec56a12 100644 --- a/src/daemon/common.c +++ b/src/daemon/common.c @@ -28,36 +28,36 @@ **/ #if HAVE_CONFIG_H -# include "config.h" +#include "config.h" #endif #include "collectd.h" + #include "common.h" #include "plugin.h" #include "utils_cache.h" -#if HAVE_PTHREAD_H -# include -#endif - -#ifdef HAVE_MATH_H -# include -#endif - /* for getaddrinfo */ -#include -#include #include +#include #include #if HAVE_NETINET_IN_H -# include +#include +#endif + +#if HAVE_NETINET_TCP_H +#include #endif /* for ntohl and htonl */ #if HAVE_ARPA_INET_H -# include +#include +#endif + +#if HAVE_CAPABILITY +#include #endif #ifdef HAVE_LIBKSTAT @@ -66,7 +66,7 @@ extern kstat_ctl_t *kc; /* AIX doesn't have MSG_DONTWAIT */ #ifndef MSG_DONTWAIT -# define MSG_DONTWAIT MSG_NONBLOCK +#define MSG_DONTWAIT MSG_NONBLOCK #endif #if !HAVE_GETPWNAM_R @@ -77,148 +77,126 @@ static pthread_mutex_t getpwnam_r_lock = PTHREAD_MUTEX_INITIALIZER; static pthread_mutex_t strerror_r_lock = PTHREAD_MUTEX_INITIALIZER; #endif -char *sstrncpy (char *dest, const char *src, size_t n) -{ - strncpy (dest, src, n); - dest[n - 1] = '\0'; +char *sstrncpy(char *dest, const char *src, size_t n) { + strncpy(dest, src, n); + dest[n - 1] = '\0'; - return (dest); + return dest; } /* char *sstrncpy */ -int ssnprintf (char *dest, size_t n, const char *format, ...) +char *ssnprintf_alloc(char const *format, ...) /* {{{ */ { - int ret = 0; - va_list ap; + char static_buffer[1024] = ""; + char *alloc_buffer; + size_t alloc_buffer_size; + int status; + va_list ap; + + /* Try printing into the static buffer. In many cases it will be + * sufficiently large and we can simply return a strdup() of this + * buffer. */ + va_start(ap, format); + status = vsnprintf(static_buffer, sizeof(static_buffer), format, ap); + va_end(ap); + if (status < 0) + return NULL; + + /* "status" does not include the null byte. */ + alloc_buffer_size = (size_t)(status + 1); + if (alloc_buffer_size <= sizeof(static_buffer)) + return strdup(static_buffer); + + /* Allocate a buffer large enough to hold the string. */ + alloc_buffer = calloc(1, alloc_buffer_size); + if (alloc_buffer == NULL) + return NULL; + + /* Print again into this new buffer. */ + va_start(ap, format); + status = vsnprintf(alloc_buffer, alloc_buffer_size, format, ap); + va_end(ap); + if (status < 0) { + sfree(alloc_buffer); + return NULL; + } - va_start (ap, format); - ret = vsnprintf (dest, n, format, ap); - dest[n - 1] = '\0'; - va_end (ap); + return alloc_buffer; +} /* }}} char *ssnprintf_alloc */ - return (ret); -} /* int ssnprintf */ +char *sstrdup(const char *s) { + char *r; + size_t sz; -char *ssnprintf_alloc (char const *format, ...) /* {{{ */ -{ - char static_buffer[1024] = ""; - char *alloc_buffer; - size_t alloc_buffer_size; - int status; - va_list ap; - - /* Try printing into the static buffer. In many cases it will be - * sufficiently large and we can simply return a strdup() of this - * buffer. */ - va_start (ap, format); - status = vsnprintf (static_buffer, sizeof (static_buffer), format, ap); - va_end (ap); - if (status < 0) - return (NULL); - - /* "status" does not include the null byte. */ - alloc_buffer_size = (size_t) (status + 1); - if (alloc_buffer_size <= sizeof (static_buffer)) - return (strdup (static_buffer)); - - /* Allocate a buffer large enough to hold the string. */ - alloc_buffer = malloc (alloc_buffer_size); - if (alloc_buffer == NULL) - return (NULL); - memset (alloc_buffer, 0, alloc_buffer_size); - - /* Print again into this new buffer. */ - va_start (ap, format); - status = vsnprintf (alloc_buffer, alloc_buffer_size, format, ap); - va_end (ap); - if (status < 0) - { - sfree (alloc_buffer); - return (NULL); - } - - return (alloc_buffer); -} /* }}} char *ssnprintf_alloc */ + if (s == NULL) + return NULL; -char *sstrdup (const char *s) -{ - char *r; - size_t sz; - - if (s == NULL) - return (NULL); - - /* Do not use `strdup' here, because it's not specified in POSIX. It's - * ``only'' an XSI extension. */ - sz = strlen (s) + 1; - r = (char *) malloc (sizeof (char) * sz); - if (r == NULL) - { - ERROR ("sstrdup: Out of memory."); - exit (3); - } - memcpy (r, s, sizeof (char) * sz); - - return (r); + /* Do not use `strdup' here, because it's not specified in POSIX. It's + * ``only'' an XSI extension. */ + sz = strlen(s) + 1; + r = malloc(sz); + if (r == NULL) { + ERROR("sstrdup: Out of memory."); + exit(3); + } + memcpy(r, s, sz); + + return r; } /* char *sstrdup */ /* Even though Posix requires "strerror_r" to return an "int", * some systems (e.g. the GNU libc) return a "char *" _and_ * ignore the second argument ... -tokkee */ -char *sstrerror (int errnum, char *buf, size_t buflen) -{ - buf[0] = '\0'; +char *sstrerror(int errnum, char *buf, size_t buflen) { + buf[0] = '\0'; #if !HAVE_STRERROR_R - { - char *temp; + { + char *temp; - pthread_mutex_lock (&strerror_r_lock); + pthread_mutex_lock(&strerror_r_lock); - temp = strerror (errnum); - sstrncpy (buf, temp, buflen); + temp = strerror(errnum); + sstrncpy(buf, temp, buflen); - pthread_mutex_unlock (&strerror_r_lock); - } + pthread_mutex_unlock(&strerror_r_lock); + } /* #endif !HAVE_STRERROR_R */ #elif STRERROR_R_CHAR_P - { - char *temp; - temp = strerror_r (errnum, buf, buflen); - if (buf[0] == '\0') - { - if ((temp != NULL) && (temp != buf) && (temp[0] != '\0')) - sstrncpy (buf, temp, buflen); - else - sstrncpy (buf, "strerror_r did not return " - "an error message", buflen); - } - } + { + char *temp; + temp = strerror_r(errnum, buf, buflen); + if (buf[0] == '\0') { + if ((temp != NULL) && (temp != buf) && (temp[0] != '\0')) + sstrncpy(buf, temp, buflen); + else + sstrncpy(buf, "strerror_r did not return " + "an error message", + buflen); + } + } /* #endif STRERROR_R_CHAR_P */ #else - if (strerror_r (errnum, buf, buflen) != 0) - { - ssnprintf (buf, buflen, "Error #%i; " - "Additionally, strerror_r failed.", - errnum); - } + if (strerror_r(errnum, buf, buflen) != 0) { + snprintf(buf, buflen, "Error #%i; " + "Additionally, strerror_r failed.", + errnum); + } #endif /* STRERROR_R_CHAR_P */ - return (buf); + return buf; } /* char *sstrerror */ -void *smalloc (size_t size) -{ - void *r; +void *smalloc(size_t size) { + void *r; - if ((r = malloc (size)) == NULL) - { - ERROR ("Not enough memory."); - exit (3); - } + if ((r = malloc(size)) == NULL) { + ERROR("Not enough memory."); + exit(3); + } - return (r); + return r; } /* void *smalloc */ #if 0 @@ -234,211 +212,185 @@ void sfree (void **ptr) } #endif -ssize_t sread (int fd, void *buf, size_t count) -{ - char *ptr; - size_t nleft; - ssize_t status; +int sread(int fd, void *buf, size_t count) { + char *ptr; + size_t nleft; + ssize_t status; - ptr = (char *) buf; - nleft = count; + ptr = (char *)buf; + nleft = count; - while (nleft > 0) - { - status = read (fd, (void *) ptr, nleft); + while (nleft > 0) { + status = read(fd, (void *)ptr, nleft); - if ((status < 0) && ((errno == EAGAIN) || (errno == EINTR))) - continue; + if ((status < 0) && ((errno == EAGAIN) || (errno == EINTR))) + continue; - if (status < 0) - return (status); + if (status < 0) + return status; - if (status == 0) - { - DEBUG ("Received EOF from fd %i. " - "Closing fd and returning error.", - fd); - close (fd); - return (-1); - } + if (status == 0) { + DEBUG("Received EOF from fd %i. ", fd); + return -1; + } - assert ((0 > status) || (nleft >= (size_t)status)); + assert((0 > status) || (nleft >= (size_t)status)); - nleft = nleft - status; - ptr = ptr + status; - } + nleft = nleft - ((size_t)status); + ptr = ptr + ((size_t)status); + } - return (0); + return 0; } +int swrite(int fd, const void *buf, size_t count) { + const char *ptr; + size_t nleft; + ssize_t status; + struct pollfd pfd; -ssize_t swrite (int fd, const void *buf, size_t count) -{ - const char *ptr; - size_t nleft; - ssize_t status; - struct pollfd pfd; - - ptr = (const char *) buf; - nleft = count; - - /* checking for closed peer connection */ - pfd.fd = fd; - pfd.events = POLLIN | POLLHUP; - pfd.revents = 0; - if (poll(&pfd, 1, 0) > 0) { - char buffer[32]; - if (recv(fd, buffer, sizeof(buffer), MSG_PEEK | MSG_DONTWAIT) == 0) { - // if recv returns zero (even though poll() said there is data to be read), - // that means the connection has been closed - return -1; - } - } - - while (nleft > 0) - { - status = write (fd, (const void *) ptr, nleft); - - if ((status < 0) && ((errno == EAGAIN) || (errno == EINTR))) - continue; - - if (status < 0) - return (status); - - nleft = nleft - status; - ptr = ptr + status; - } - - return (0); + ptr = (const char *)buf; + nleft = count; + + if (fd < 0) { + errno = EINVAL; + return errno; + } + + /* checking for closed peer connection */ + pfd.fd = fd; + pfd.events = POLLIN | POLLHUP; + pfd.revents = 0; + if (poll(&pfd, 1, 0) > 0) { + char buffer[32]; + if (recv(fd, buffer, sizeof(buffer), MSG_PEEK | MSG_DONTWAIT) == 0) { + /* if recv returns zero (even though poll() said there is data to be + * read), that means the connection has been closed */ + errno = ECONNRESET; + return -1; + } + } + + while (nleft > 0) { + status = write(fd, (const void *)ptr, nleft); + + if ((status < 0) && ((errno == EAGAIN) || (errno == EINTR))) + continue; + + if (status < 0) + return errno ? errno : status; + + nleft = nleft - ((size_t)status); + ptr = ptr + ((size_t)status); + } + + return 0; } -int strsplit (char *string, char **fields, size_t size) -{ - size_t i; - char *ptr; - char *saveptr; - - i = 0; - ptr = string; - saveptr = NULL; - while ((fields[i] = strtok_r (ptr, " \t\r\n", &saveptr)) != NULL) - { - ptr = NULL; - i++; - - if (i >= size) - break; - } - - return ((int) i); +int strsplit(char *string, char **fields, size_t size) { + size_t i; + char *ptr; + char *saveptr; + + i = 0; + ptr = string; + saveptr = NULL; + while ((fields[i] = strtok_r(ptr, " \t\r\n", &saveptr)) != NULL) { + ptr = NULL; + i++; + + if (i >= size) + break; + } + + return (int)i; } -int strjoin (char *buffer, size_t buffer_size, - char **fields, size_t fields_num, - const char *sep) -{ - size_t avail; - char *ptr; - size_t sep_len; - size_t i; - - if ((buffer_size < 1) || (fields_num <= 0)) - return (-1); - - memset (buffer, 0, buffer_size); - ptr = buffer; - avail = buffer_size - 1; - - sep_len = 0; - if (sep != NULL) - sep_len = strlen (sep); - - for (i = 0; i < fields_num; i++) - { - size_t field_len; - - if ((i > 0) && (sep_len > 0)) - { - if (avail < sep_len) - return (-1); - - memcpy (ptr, sep, sep_len); - ptr += sep_len; - avail -= sep_len; - } - - field_len = strlen (fields[i]); - if (avail < field_len) - return (-1); - - memcpy (ptr, fields[i], field_len); - ptr += field_len; - avail -= field_len; - } - - assert (buffer[buffer_size - 1] == 0); - return (strlen (buffer)); +int strjoin(char *buffer, size_t buffer_size, char **fields, size_t fields_num, + const char *sep) { + size_t avail = 0; + char *ptr = buffer; + size_t sep_len = 0; + + size_t buffer_req = 0; + + if (((fields_num != 0) && (fields == NULL)) || + ((buffer_size != 0) && (buffer == NULL))) + return -EINVAL; + + if (buffer != NULL) + buffer[0] = 0; + + if (buffer_size != 0) + avail = buffer_size - 1; + + if (sep != NULL) + sep_len = strlen(sep); + + for (size_t i = 0; i < fields_num; i++) { + size_t field_len = strlen(fields[i]); + + if (i != 0) + buffer_req += sep_len; + buffer_req += field_len; + + if ((i != 0) && (sep_len > 0)) { + if (sep_len >= avail) { + /* prevent subsequent iterations from writing to the + * buffer. */ + avail = 0; + continue; + } + + memcpy(ptr, sep, sep_len); + + ptr += sep_len; + avail -= sep_len; + } + + if (field_len > avail) + field_len = avail; + + memcpy(ptr, fields[i], field_len); + ptr += field_len; + + avail -= field_len; + if (ptr != NULL) + *ptr = 0; + } + + return (int)buffer_req; } -int strsubstitute (char *str, char c_from, char c_to) -{ - int ret; - - if (str == NULL) - return (-1); - - ret = 0; - while (*str != '\0') - { - if (*str == c_from) - { - *str = c_to; - ret++; - } - str++; - } - - return (ret); -} /* int strsubstitute */ - -int escape_string (char *buffer, size_t buffer_size) -{ +int escape_string(char *buffer, size_t buffer_size) { char *temp; - size_t i; size_t j; /* Check if we need to escape at all first */ - temp = strpbrk (buffer, " \t\"\\"); + temp = strpbrk(buffer, " \t\"\\"); if (temp == NULL) - return (0); + return 0; if (buffer_size < 3) - return (EINVAL); + return EINVAL; - temp = (char *) malloc (buffer_size); + temp = calloc(1, buffer_size); if (temp == NULL) - return (ENOMEM); - memset (temp, 0, buffer_size); + return ENOMEM; temp[0] = '"'; j = 1; - for (i = 0; i < buffer_size; i++) - { - if (buffer[i] == 0) - { + for (size_t i = 0; i < buffer_size; i++) { + if (buffer[i] == 0) { break; - } - else if ((buffer[i] == '"') || (buffer[i] == '\\')) - { + } else if ((buffer[i] == '"') || (buffer[i] == '\\')) { if (j > (buffer_size - 4)) break; temp[j] = '\\'; temp[j + 1] = buffer[i]; j += 2; - } - else - { + } else { if (j > (buffer_size - 3)) break; temp[j] = buffer[i]; @@ -446,396 +398,349 @@ int escape_string (char *buffer, size_t buffer_size) } } - assert ((j + 1) < buffer_size); + assert((j + 1) < buffer_size); temp[j] = '"'; temp[j + 1] = 0; - sstrncpy (buffer, temp, buffer_size); - sfree (temp); - return (0); + sstrncpy(buffer, temp, buffer_size); + sfree(temp); + return 0; } /* int escape_string */ -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 + 1) >= buf_len) || (buf[i + 1] == 0)) { - ERROR ("string unescape: backslash found at end of string."); - /* Ensure null-byte at the end of the buffer. */ - buf[i] = 0; - 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; - } - - /* Move everything after the position one position to the left. - * Add a null-byte as last character in the buffer. */ - memmove (buf + i + 1, buf + i + 2, buf_len - i - 2); - buf[buf_len - 1] = 0; - } - return (0); +int strunescape(char *buf, size_t buf_len) { + for (size_t i = 0; (i < buf_len) && (buf[i] != '\0'); ++i) { + if (buf[i] != '\\') + continue; + + if (((i + 1) >= buf_len) || (buf[i + 1] == 0)) { + ERROR("string unescape: backslash found at end of string."); + /* Ensure null-byte at the end of the buffer. */ + buf[i] = 0; + 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; + } + + /* Move everything after the position one position to the left. + * Add a null-byte as last character in the buffer. */ + memmove(buf + i + 1, buf + i + 2, buf_len - i - 2); + buf[buf_len - 1] = 0; + } + return 0; } /* int strunescape */ -size_t strstripnewline (char *buffer) -{ - size_t buffer_len = strlen (buffer); - - while (buffer_len > 0) - { - if ((buffer[buffer_len - 1] != '\n') - && (buffer[buffer_len - 1] != '\r')) - break; - buffer_len--; - buffer[buffer_len] = 0; - } - - return (buffer_len); +size_t strstripnewline(char *buffer) { + size_t buffer_len = strlen(buffer); + + while (buffer_len > 0) { + if ((buffer[buffer_len - 1] != '\n') && (buffer[buffer_len - 1] != '\r')) + break; + buffer_len--; + buffer[buffer_len] = 0; + } + + return buffer_len; } /* size_t strstripnewline */ -int escape_slashes (char *buffer, size_t buffer_size) -{ - int i; - size_t buffer_len; - - buffer_len = strlen (buffer); - - if (buffer_len <= 1) - { - if (strcmp ("/", buffer) == 0) - { - if (buffer_size < 5) - return (-1); - sstrncpy (buffer, "root", buffer_size); - } - return (0); - } - - /* Move one to the left */ - if (buffer[0] == '/') - { - memmove (buffer, buffer + 1, buffer_len); - buffer_len--; - } - - for (i = 0; i < buffer_len; i++) - { - if (buffer[i] == '/') - buffer[i] = '_'; - } - - return (0); +int escape_slashes(char *buffer, size_t buffer_size) { + size_t buffer_len; + + buffer_len = strlen(buffer); + + if (buffer_len <= 1) { + if (strcmp("/", buffer) == 0) { + if (buffer_size < 5) + return -1; + sstrncpy(buffer, "root", buffer_size); + } + return 0; + } + + /* Move one to the left */ + if (buffer[0] == '/') { + memmove(buffer, buffer + 1, buffer_len); + buffer_len--; + } + + for (size_t i = 0; i < buffer_len; i++) { + if (buffer[i] == '/') + buffer[i] = '_'; + } + + return 0; } /* int escape_slashes */ -void replace_special (char *buffer, size_t buffer_size) -{ - size_t i; - - for (i = 0; i < buffer_size; i++) - { - if (buffer[i] == 0) - return; - if ((!isalnum ((int) buffer[i])) && (buffer[i] != '-')) - buffer[i] = '_'; - } +void replace_special(char *buffer, size_t buffer_size) { + for (size_t i = 0; i < buffer_size; i++) { + if (buffer[i] == 0) + return; + if ((!isalnum((int)buffer[i])) && (buffer[i] != '-')) + buffer[i] = '_'; + } } /* void replace_special */ -int timeval_cmp (struct timeval tv0, struct timeval tv1, struct timeval *delta) -{ - struct timeval *larger; - struct timeval *smaller; - - int status; - - NORMALIZE_TIMEVAL (tv0); - NORMALIZE_TIMEVAL (tv1); - - if ((tv0.tv_sec == tv1.tv_sec) && (tv0.tv_usec == tv1.tv_usec)) - { - if (delta != NULL) { - delta->tv_sec = 0; - delta->tv_usec = 0; - } - return (0); - } - - if ((tv0.tv_sec < tv1.tv_sec) - || ((tv0.tv_sec == tv1.tv_sec) && (tv0.tv_usec < tv1.tv_usec))) - { - larger = &tv1; - smaller = &tv0; - status = -1; - } - else - { - larger = &tv0; - smaller = &tv1; - status = 1; - } - - if (delta != NULL) { - delta->tv_sec = larger->tv_sec - smaller->tv_sec; - - if (smaller->tv_usec <= larger->tv_usec) - delta->tv_usec = larger->tv_usec - smaller->tv_usec; - else - { - --delta->tv_sec; - delta->tv_usec = 1000000 + larger->tv_usec - smaller->tv_usec; - } - } - - assert ((delta == NULL) - || ((0 <= delta->tv_usec) && (delta->tv_usec < 1000000))); - - return (status); +int timeval_cmp(struct timeval tv0, struct timeval tv1, struct timeval *delta) { + struct timeval *larger; + struct timeval *smaller; + + int status; + + NORMALIZE_TIMEVAL(tv0); + NORMALIZE_TIMEVAL(tv1); + + if ((tv0.tv_sec == tv1.tv_sec) && (tv0.tv_usec == tv1.tv_usec)) { + if (delta != NULL) { + delta->tv_sec = 0; + delta->tv_usec = 0; + } + return 0; + } + + if ((tv0.tv_sec < tv1.tv_sec) || + ((tv0.tv_sec == tv1.tv_sec) && (tv0.tv_usec < tv1.tv_usec))) { + larger = &tv1; + smaller = &tv0; + status = -1; + } else { + larger = &tv0; + smaller = &tv1; + status = 1; + } + + if (delta != NULL) { + delta->tv_sec = larger->tv_sec - smaller->tv_sec; + + if (smaller->tv_usec <= larger->tv_usec) + delta->tv_usec = larger->tv_usec - smaller->tv_usec; + else { + --delta->tv_sec; + delta->tv_usec = 1000000 + larger->tv_usec - smaller->tv_usec; + } + } + + assert((delta == NULL) || + ((0 <= delta->tv_usec) && (delta->tv_usec < 1000000))); + + return status; } /* int timeval_cmp */ -int check_create_dir (const char *file_orig) -{ - struct stat statbuf; - - char file_copy[512]; - char dir[512]; - int dir_len = 512; - char *fields[16]; - int fields_num; - char *ptr; - char *saveptr; - int last_is_file = 1; - int path_is_absolute = 0; - size_t len; - int i; - - /* - * Sanity checks first - */ - if (file_orig == NULL) - return (-1); - - if ((len = strlen (file_orig)) < 1) - return (-1); - else if (len >= sizeof (file_copy)) - return (-1); - - /* - * If `file_orig' ends in a slash the last component is a directory, - * otherwise it's a file. Act accordingly.. - */ - if (file_orig[len - 1] == '/') - last_is_file = 0; - if (file_orig[0] == '/') - path_is_absolute = 1; - - /* - * Create a copy for `strtok_r' to destroy - */ - sstrncpy (file_copy, file_orig, sizeof (file_copy)); - - /* - * Break into components. This will eat up several slashes in a row and - * remove leading and trailing slashes.. - */ - ptr = file_copy; - saveptr = NULL; - fields_num = 0; - while ((fields[fields_num] = strtok_r (ptr, "/", &saveptr)) != NULL) - { - ptr = NULL; - fields_num++; - - if (fields_num >= 16) - break; - } - - /* - * For each component, do.. - */ - for (i = 0; i < (fields_num - last_is_file); i++) - { - /* - * Do not create directories that start with a dot. This - * prevents `../../' attacks and other likely malicious - * behavior. - */ - if (fields[i][0] == '.') - { - ERROR ("Cowardly refusing to create a directory that " - "begins with a `.' (dot): `%s'", file_orig); - return (-2); - } - - /* - * Join the components together again - */ - dir[0] = '/'; - if (strjoin (dir + path_is_absolute, dir_len - path_is_absolute, - fields, i + 1, "/") < 0) - { - ERROR ("strjoin failed: `%s', component #%i", file_orig, i); - return (-1); - } - - while (42) { - if ((stat (dir, &statbuf) == -1) - && (lstat (dir, &statbuf) == -1)) - { - if (errno == ENOENT) - { - if (mkdir (dir, S_IRWXU | S_IRWXG | S_IRWXO) == 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 if (!S_ISDIR (statbuf.st_mode)) - { - ERROR ("check_create_dir: `%s' exists but is not " - "a directory!", dir); - return (-1); - } - break; - } - } - - return (0); +int check_create_dir(const char *file_orig) { + struct stat statbuf; + + char file_copy[512]; + char dir[512]; + int dir_len = 512; + char *fields[16]; + int fields_num; + char *ptr; + char *saveptr; + int last_is_file = 1; + int path_is_absolute = 0; + size_t len; + + /* + * Sanity checks first + */ + if (file_orig == NULL) + return -1; + + if ((len = strlen(file_orig)) < 1) + return -1; + else if (len >= sizeof(file_copy)) + return -1; + + /* + * If `file_orig' ends in a slash the last component is a directory, + * otherwise it's a file. Act accordingly.. + */ + if (file_orig[len - 1] == '/') + last_is_file = 0; + if (file_orig[0] == '/') + path_is_absolute = 1; + + /* + * Create a copy for `strtok_r' to destroy + */ + sstrncpy(file_copy, file_orig, sizeof(file_copy)); + + /* + * Break into components. This will eat up several slashes in a row and + * remove leading and trailing slashes.. + */ + ptr = file_copy; + saveptr = NULL; + fields_num = 0; + while ((fields[fields_num] = strtok_r(ptr, "/", &saveptr)) != NULL) { + ptr = NULL; + fields_num++; + + if (fields_num >= 16) + break; + } + + /* + * For each component, do.. + */ + for (int i = 0; i < (fields_num - last_is_file); i++) { + /* + * Do not create directories that start with a dot. This + * prevents `../../' attacks and other likely malicious + * behavior. + */ + if (fields[i][0] == '.') { + ERROR("Cowardly refusing to create a directory that " + "begins with a `.' (dot): `%s'", + file_orig); + return -2; + } + + /* + * Join the components together again + */ + dir[0] = '/'; + if (strjoin(dir + path_is_absolute, (size_t)(dir_len - path_is_absolute), + fields, (size_t)(i + 1), "/") < 0) { + ERROR("strjoin failed: `%s', component #%i", file_orig, i); + return -1; + } + + while (42) { + if ((stat(dir, &statbuf) == -1) && (lstat(dir, &statbuf) == -1)) { + if (errno == ENOENT) { + if (mkdir(dir, S_IRWXU | S_IRWXG | S_IRWXO) == 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 if (!S_ISDIR(statbuf.st_mode)) { + ERROR("check_create_dir: `%s' exists but is not " + "a directory!", + dir); + return -1; + } + break; + } + } + + return 0; } /* check_create_dir */ #ifdef HAVE_LIBKSTAT -int get_kstat (kstat_t **ksp_ptr, char *module, int instance, char *name) -{ - char ident[128]; +int get_kstat(kstat_t **ksp_ptr, char *module, int instance, char *name) { + char ident[128]; - *ksp_ptr = NULL; + *ksp_ptr = NULL; - if (kc == NULL) - return (-1); + if (kc == NULL) + return -1; - ssnprintf (ident, sizeof (ident), "%s,%i,%s", module, instance, name); + snprintf(ident, sizeof(ident), "%s,%i,%s", module, instance, name); - *ksp_ptr = kstat_lookup (kc, module, instance, name); - if (*ksp_ptr == NULL) - { - ERROR ("get_kstat: Cound not find kstat %s", ident); - return (-1); - } + *ksp_ptr = kstat_lookup(kc, module, instance, name); + if (*ksp_ptr == NULL) { + ERROR("get_kstat: Cound not find kstat %s", ident); + return -1; + } - if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED) - { - ERROR ("get_kstat: 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 - assert (*ksp_ptr != NULL); - assert ((*ksp_ptr)->ks_type == KSTAT_TYPE_NAMED); + assert(*ksp_ptr != NULL); + assert((*ksp_ptr)->ks_type == KSTAT_TYPE_NAMED); #endif - if (kstat_read (kc, *ksp_ptr, NULL) == -1) - { - ERROR ("get_kstat: kstat %s could not be read", ident); - return (-1); - } + if (kstat_read(kc, *ksp_ptr, NULL) == -1) { + ERROR("get_kstat: kstat %s could not be read", ident); + return -1; + } - if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED) - { - ERROR ("get_kstat: kstat %s has wrong type", ident); - return (-1); - } + if ((*ksp_ptr)->ks_type != KSTAT_TYPE_NAMED) { + ERROR("get_kstat: kstat %s has wrong type", ident); + return -1; + } - return (0); + return 0; } -long long get_kstat_value (kstat_t *ksp, char *name) -{ - kstat_named_t *kn; - long long retval = -1LL; - - if (ksp == NULL) - { - ERROR ("get_kstat_value (\"%s\"): ksp is NULL.", name); - return (-1LL); - } - else if (ksp->ks_type != KSTAT_TYPE_NAMED) - { - ERROR ("get_kstat_value (\"%s\"): ksp->ks_type (%#x) " - "is not KSTAT_TYPE_NAMED (%#x).", - name, - (unsigned int) ksp->ks_type, - (unsigned int) KSTAT_TYPE_NAMED); - return (-1LL); - } - - if ((kn = (kstat_named_t *) kstat_data_lookup (ksp, name)) == NULL) - return (-1LL); - - if (kn->data_type == KSTAT_DATA_INT32) - retval = (long long) kn->value.i32; - else if (kn->data_type == KSTAT_DATA_UINT32) - retval = (long long) kn->value.ui32; - else if (kn->data_type == KSTAT_DATA_INT64) - retval = (long long) kn->value.i64; /* According to ANSI C99 `long long' must hold at least 64 bits */ - else if (kn->data_type == KSTAT_DATA_UINT64) - retval = (long long) kn->value.ui64; /* XXX: Might overflow! */ - else - WARNING ("get_kstat_value: Not a numeric value: %s", name); - - return (retval); +long long get_kstat_value(kstat_t *ksp, char *name) { + kstat_named_t *kn; + long long retval = -1LL; + + if (ksp == NULL) { + ERROR("get_kstat_value (\"%s\"): ksp is NULL.", name); + return -1LL; + } else if (ksp->ks_type != KSTAT_TYPE_NAMED) { + ERROR("get_kstat_value (\"%s\"): ksp->ks_type (%#x) " + "is not KSTAT_TYPE_NAMED (%#x).", + name, (unsigned int)ksp->ks_type, (unsigned int)KSTAT_TYPE_NAMED); + return -1LL; + } + + if ((kn = (kstat_named_t *)kstat_data_lookup(ksp, name)) == NULL) + return -1LL; + + if (kn->data_type == KSTAT_DATA_INT32) + retval = (long long)kn->value.i32; + else if (kn->data_type == KSTAT_DATA_UINT32) + retval = (long long)kn->value.ui32; + else if (kn->data_type == KSTAT_DATA_INT64) + retval = + (long long)kn->value.i64; /* According to ANSI C99 `long long' must hold + at least 64 bits */ + else if (kn->data_type == KSTAT_DATA_UINT64) + retval = (long long)kn->value.ui64; /* XXX: Might overflow! */ + else + WARNING("get_kstat_value: Not a numeric value: %s", name); + + return retval; } #endif /* HAVE_LIBKSTAT */ #ifndef HAVE_HTONLL -unsigned long long ntohll (unsigned long long n) -{ +unsigned long long ntohll(unsigned long long n) { #if BYTE_ORDER == BIG_ENDIAN - return (n); + return n; #else - return (((unsigned long long) ntohl (n)) << 32) + ntohl (n >> 32); + return (((unsigned long long)ntohl(n)) << 32) + ntohl(n >> 32); #endif } /* unsigned long long ntohll */ -unsigned long long htonll (unsigned long long n) -{ +unsigned long long htonll(unsigned long long n) { #if BYTE_ORDER == BIG_ENDIAN - return (n); + return n; #else - return (((unsigned long long) htonl (n)) << 32) + htonl (n >> 32); + return (((unsigned long long)htonl(n)) << 32) + htonl(n >> 32); #endif } /* unsigned long long htonll */ #endif /* HAVE_HTONLL */ @@ -845,836 +750,832 @@ unsigned long long htonll (unsigned long long n) /* #endif FP_LAYOUT_NEED_NOTHING */ #elif FP_LAYOUT_NEED_ENDIANFLIP || FP_LAYOUT_NEED_INTSWAP -# if FP_LAYOUT_NEED_ENDIANFLIP -# define FP_CONVERT(A) ((((uint64_t)(A) & 0xff00000000000000LL) >> 56) | \ - (((uint64_t)(A) & 0x00ff000000000000LL) >> 40) | \ - (((uint64_t)(A) & 0x0000ff0000000000LL) >> 24) | \ - (((uint64_t)(A) & 0x000000ff00000000LL) >> 8) | \ - (((uint64_t)(A) & 0x00000000ff000000LL) << 8) | \ - (((uint64_t)(A) & 0x0000000000ff0000LL) << 24) | \ - (((uint64_t)(A) & 0x000000000000ff00LL) << 40) | \ - (((uint64_t)(A) & 0x00000000000000ffLL) << 56)) -# else -# define FP_CONVERT(A) ((((uint64_t)(A) & 0xffffffff00000000LL) >> 32) | \ - (((uint64_t)(A) & 0x00000000ffffffffLL) << 32)) -# endif - -double ntohd (double d) -{ - union - { - uint8_t byte[8]; - uint64_t integer; - double floating; - } ret; - - ret.floating = d; - - /* NAN in x86 byte order */ - if ((ret.byte[0] == 0x00) && (ret.byte[1] == 0x00) - && (ret.byte[2] == 0x00) && (ret.byte[3] == 0x00) - && (ret.byte[4] == 0x00) && (ret.byte[5] == 0x00) - && (ret.byte[6] == 0xf8) && (ret.byte[7] == 0x7f)) - { - return (NAN); - } - else - { - uint64_t tmp; - - tmp = ret.integer; - ret.integer = FP_CONVERT (tmp); - return (ret.floating); - } +#if FP_LAYOUT_NEED_ENDIANFLIP +#define FP_CONVERT(A) \ + ((((uint64_t)(A)&0xff00000000000000LL) >> 56) | \ + (((uint64_t)(A)&0x00ff000000000000LL) >> 40) | \ + (((uint64_t)(A)&0x0000ff0000000000LL) >> 24) | \ + (((uint64_t)(A)&0x000000ff00000000LL) >> 8) | \ + (((uint64_t)(A)&0x00000000ff000000LL) << 8) | \ + (((uint64_t)(A)&0x0000000000ff0000LL) << 24) | \ + (((uint64_t)(A)&0x000000000000ff00LL) << 40) | \ + (((uint64_t)(A)&0x00000000000000ffLL) << 56)) +#else +#define FP_CONVERT(A) \ + ((((uint64_t)(A)&0xffffffff00000000LL) >> 32) | \ + (((uint64_t)(A)&0x00000000ffffffffLL) << 32)) +#endif + +double ntohd(double d) { + union { + uint8_t byte[8]; + uint64_t integer; + double floating; + } ret; + + ret.floating = d; + + /* NAN in x86 byte order */ + if ((ret.byte[0] == 0x00) && (ret.byte[1] == 0x00) && (ret.byte[2] == 0x00) && + (ret.byte[3] == 0x00) && (ret.byte[4] == 0x00) && (ret.byte[5] == 0x00) && + (ret.byte[6] == 0xf8) && (ret.byte[7] == 0x7f)) { + return NAN; + } else { + uint64_t tmp; + + tmp = ret.integer; + ret.integer = FP_CONVERT(tmp); + return ret.floating; + } } /* double ntohd */ -double htond (double d) -{ - union - { - uint8_t byte[8]; - uint64_t integer; - double floating; - } ret; - - if (isnan (d)) - { - ret.byte[0] = ret.byte[1] = ret.byte[2] = ret.byte[3] = 0x00; - ret.byte[4] = ret.byte[5] = 0x00; - ret.byte[6] = 0xf8; - ret.byte[7] = 0x7f; - return (ret.floating); - } - else - { - uint64_t tmp; - - ret.floating = d; - tmp = FP_CONVERT (ret.integer); - ret.integer = tmp; - return (ret.floating); - } +double htond(double d) { + union { + uint8_t byte[8]; + uint64_t integer; + double floating; + } ret; + + if (isnan(d)) { + ret.byte[0] = ret.byte[1] = ret.byte[2] = ret.byte[3] = 0x00; + ret.byte[4] = ret.byte[5] = 0x00; + ret.byte[6] = 0xf8; + ret.byte[7] = 0x7f; + return ret.floating; + } else { + uint64_t tmp; + + ret.floating = d; + tmp = FP_CONVERT(ret.integer); + ret.integer = tmp; + return ret.floating; + } } /* double htond */ #endif /* FP_LAYOUT_NEED_ENDIANFLIP || FP_LAYOUT_NEED_INTSWAP */ -int format_name (char *ret, int ret_len, - const char *hostname, - const char *plugin, const char *plugin_instance, - const char *type, const char *type_instance) -{ +int format_name(char *ret, int ret_len, const char *hostname, + const char *plugin, const char *plugin_instance, + const char *type, const char *type_instance) { char *buffer; size_t buffer_size; buffer = ret; - buffer_size = (size_t) ret_len; - -#define APPEND(str) do { \ - size_t l = strlen (str); \ - if (l >= buffer_size) \ - return (ENOBUFS); \ - memcpy (buffer, (str), l); \ - buffer += l; buffer_size -= l; \ -} while (0) - - assert (plugin != NULL); - assert (type != NULL); - - APPEND (hostname); - APPEND ("/"); - APPEND (plugin); - if ((plugin_instance != NULL) && (plugin_instance[0] != 0)) - { - APPEND ("-"); - APPEND (plugin_instance); + buffer_size = (size_t)ret_len; + +#define APPEND(str) \ + do { \ + size_t l = strlen(str); \ + if (l >= buffer_size) \ + return ENOBUFS; \ + memcpy(buffer, (str), l); \ + buffer += l; \ + buffer_size -= l; \ + } while (0) + + assert(plugin != NULL); + assert(type != NULL); + + APPEND(hostname); + APPEND("/"); + APPEND(plugin); + if ((plugin_instance != NULL) && (plugin_instance[0] != 0)) { + APPEND("-"); + APPEND(plugin_instance); } - APPEND ("/"); - APPEND (type); - if ((type_instance != NULL) && (type_instance[0] != 0)) - { - APPEND ("-"); - APPEND (type_instance); + APPEND("/"); + APPEND(type); + if ((type_instance != NULL) && (type_instance[0] != 0)) { + APPEND("-"); + APPEND(type_instance); } - assert (buffer_size > 0); + assert(buffer_size > 0); buffer[0] = 0; #undef APPEND - return (0); + return 0; } /* int format_name */ -int format_values (char *ret, size_t ret_len, /* {{{ */ - const data_set_t *ds, const value_list_t *vl, - _Bool store_rates) -{ - size_t offset = 0; - int status; - int i; - gauge_t *rates = NULL; - - assert (0 == strcmp (ds->type, vl->type)); - - memset (ret, 0, ret_len); - -#define BUFFER_ADD(...) do { \ - status = ssnprintf (ret + offset, ret_len - offset, \ - __VA_ARGS__); \ - if (status < 1) \ - { \ - sfree (rates); \ - return (-1); \ - } \ - else if (((size_t) status) >= (ret_len - offset)) \ - { \ - sfree (rates); \ - return (-1); \ - } \ - else \ - offset += ((size_t) status); \ -} while (0) - - BUFFER_ADD ("%.3f", CDTIME_T_TO_DOUBLE (vl->time)); - - for (i = 0; i < ds->ds_num; i++) - { - if (ds->ds[i].type == DS_TYPE_GAUGE) - BUFFER_ADD (":"GAUGE_FORMAT, vl->values[i].gauge); - else if (store_rates) - { - if (rates == NULL) - rates = uc_get_rate (ds, vl); - if (rates == NULL) - { - WARNING ("format_values: uc_get_rate failed."); - return (-1); - } - BUFFER_ADD (":"GAUGE_FORMAT, rates[i]); - } - else if (ds->ds[i].type == DS_TYPE_COUNTER) - BUFFER_ADD (":%llu", vl->values[i].counter); - else if (ds->ds[i].type == DS_TYPE_DERIVE) - BUFFER_ADD (":%"PRIi64, vl->values[i].derive); - else if (ds->ds[i].type == DS_TYPE_ABSOLUTE) - BUFFER_ADD (":%"PRIu64, vl->values[i].absolute); - else - { - ERROR ("format_values: Unknown data source type: %i", - ds->ds[i].type); - sfree (rates); - return (-1); - } - } /* for ds->ds_num */ +int format_values(char *ret, size_t ret_len, /* {{{ */ + const data_set_t *ds, const value_list_t *vl, + _Bool store_rates) { + size_t offset = 0; + int status; + gauge_t *rates = NULL; + + assert(0 == strcmp(ds->type, vl->type)); + + memset(ret, 0, ret_len); + +#define BUFFER_ADD(...) \ + do { \ + status = snprintf(ret + offset, ret_len - offset, __VA_ARGS__); \ + if (status < 1) { \ + sfree(rates); \ + return -1; \ + } else if (((size_t)status) >= (ret_len - offset)) { \ + sfree(rates); \ + return -1; \ + } else \ + offset += ((size_t)status); \ + } while (0) + + BUFFER_ADD("%.3f", CDTIME_T_TO_DOUBLE(vl->time)); + + for (size_t i = 0; i < ds->ds_num; i++) { + if (ds->ds[i].type == DS_TYPE_GAUGE) + BUFFER_ADD(":" GAUGE_FORMAT, vl->values[i].gauge); + else if (store_rates) { + if (rates == NULL) + rates = uc_get_rate(ds, vl); + if (rates == NULL) { + WARNING("format_values: uc_get_rate failed."); + return -1; + } + BUFFER_ADD(":" GAUGE_FORMAT, rates[i]); + } else if (ds->ds[i].type == DS_TYPE_COUNTER) + BUFFER_ADD(":%" PRIu64, (uint64_t)vl->values[i].counter); + else if (ds->ds[i].type == DS_TYPE_DERIVE) + BUFFER_ADD(":%" PRIi64, vl->values[i].derive); + else if (ds->ds[i].type == DS_TYPE_ABSOLUTE) + BUFFER_ADD(":%" PRIu64, vl->values[i].absolute); + else { + ERROR("format_values: Unknown data source type: %i", ds->ds[i].type); + sfree(rates); + return -1; + } + } /* for ds->ds_num */ #undef BUFFER_ADD - sfree (rates); - return (0); + sfree(rates); + return 0; } /* }}} int format_values */ -int parse_identifier (char *str, char **ret_host, - char **ret_plugin, char **ret_plugin_instance, - char **ret_type, char **ret_type_instance) -{ - char *hostname = NULL; - char *plugin = NULL; - char *plugin_instance = NULL; - char *type = NULL; - char *type_instance = NULL; - - hostname = str; - if (hostname == NULL) - return (-1); - - plugin = strchr (hostname, '/'); - if (plugin == NULL) - return (-1); - *plugin = '\0'; plugin++; - - type = strchr (plugin, '/'); - if (type == NULL) - return (-1); - *type = '\0'; type++; - - plugin_instance = strchr (plugin, '-'); - if (plugin_instance != NULL) - { - *plugin_instance = '\0'; - plugin_instance++; - } - - type_instance = strchr (type, '-'); - if (type_instance != NULL) - { - *type_instance = '\0'; - type_instance++; - } - - *ret_host = hostname; - *ret_plugin = plugin; - *ret_plugin_instance = plugin_instance; - *ret_type = type; - *ret_type_instance = type_instance; - return (0); +int parse_identifier(char *str, char **ret_host, char **ret_plugin, + char **ret_plugin_instance, char **ret_type, + char **ret_type_instance, char *default_host) { + char *hostname = NULL; + char *plugin = NULL; + char *plugin_instance = NULL; + char *type = NULL; + char *type_instance = NULL; + + hostname = str; + if (hostname == NULL) + return -1; + + plugin = strchr(hostname, '/'); + if (plugin == NULL) + return -1; + *plugin = '\0'; + plugin++; + + type = strchr(plugin, '/'); + if (type == NULL) { + if (default_host == NULL) + return -1; + /* else: no host specified; use default */ + type = plugin; + plugin = hostname; + hostname = default_host; + } else { + *type = '\0'; + type++; + } + + plugin_instance = strchr(plugin, '-'); + if (plugin_instance != NULL) { + *plugin_instance = '\0'; + plugin_instance++; + } + + type_instance = strchr(type, '-'); + if (type_instance != NULL) { + *type_instance = '\0'; + type_instance++; + } + + *ret_host = hostname; + *ret_plugin = plugin; + *ret_plugin_instance = plugin_instance; + *ret_type = type; + *ret_type_instance = type_instance; + return 0; } /* int parse_identifier */ -int parse_identifier_vl (const char *str, value_list_t *vl) /* {{{ */ +int parse_identifier_vl(const char *str, value_list_t *vl) /* {{{ */ { - char str_copy[6 * DATA_MAX_NAME_LEN]; - char *host = NULL; - char *plugin = NULL; - char *plugin_instance = NULL; - char *type = NULL; - char *type_instance = NULL; - int status; - - if ((str == NULL) || (vl == NULL)) - return (EINVAL); - - sstrncpy (str_copy, str, sizeof (str_copy)); - - status = parse_identifier (str_copy, &host, - &plugin, &plugin_instance, - &type, &type_instance); - if (status != 0) - return (status); - - sstrncpy (vl->host, host, sizeof (vl->host)); - sstrncpy (vl->plugin, plugin, sizeof (vl->plugin)); - sstrncpy (vl->plugin_instance, - (plugin_instance != NULL) ? plugin_instance : "", - sizeof (vl->plugin_instance)); - sstrncpy (vl->type, type, sizeof (vl->type)); - sstrncpy (vl->type_instance, - (type_instance != NULL) ? type_instance : "", - sizeof (vl->type_instance)); - - return (0); + char str_copy[6 * DATA_MAX_NAME_LEN]; + char *host = NULL; + char *plugin = NULL; + char *plugin_instance = NULL; + char *type = NULL; + char *type_instance = NULL; + int status; + + if ((str == NULL) || (vl == NULL)) + return EINVAL; + + sstrncpy(str_copy, str, sizeof(str_copy)); + + status = parse_identifier(str_copy, &host, &plugin, &plugin_instance, &type, + &type_instance, + /* default_host = */ NULL); + if (status != 0) + return status; + + sstrncpy(vl->host, host, sizeof(vl->host)); + sstrncpy(vl->plugin, plugin, sizeof(vl->plugin)); + sstrncpy(vl->plugin_instance, + (plugin_instance != NULL) ? plugin_instance : "", + sizeof(vl->plugin_instance)); + sstrncpy(vl->type, type, sizeof(vl->type)); + sstrncpy(vl->type_instance, (type_instance != NULL) ? type_instance : "", + sizeof(vl->type_instance)); + + return 0; } /* }}} int parse_identifier_vl */ -int parse_value (const char *value_orig, value_t *ret_value, int ds_type) -{ +int parse_value(const char *value_orig, value_t *ret_value, int ds_type) { char *value; char *endptr = NULL; size_t value_len; if (value_orig == NULL) - return (EINVAL); + return EINVAL; - value = strdup (value_orig); + value = strdup(value_orig); if (value == NULL) - return (ENOMEM); - value_len = strlen (value); + return ENOMEM; + value_len = strlen(value); - while ((value_len > 0) && isspace ((int) value[value_len - 1])) - { + while ((value_len > 0) && isspace((int)value[value_len - 1])) { value[value_len - 1] = 0; value_len--; } - switch (ds_type) - { - case DS_TYPE_COUNTER: - ret_value->counter = (counter_t) strtoull (value, &endptr, 0); - break; + 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_GAUGE: + ret_value->gauge = (gauge_t)strtod(value, &endptr); + break; - case DS_TYPE_DERIVE: - ret_value->derive = (derive_t) strtoll (value, &endptr, 0); - break; + case DS_TYPE_DERIVE: + ret_value->derive = (derive_t)strtoll(value, &endptr, 0); + break; - case DS_TYPE_ABSOLUTE: - ret_value->absolute = (absolute_t) strtoull (value, &endptr, 0); - break; + case DS_TYPE_ABSOLUTE: + ret_value->absolute = (absolute_t)strtoull(value, &endptr, 0); + break; - default: - sfree (value); - ERROR ("parse_value: Invalid data source type: %i.", ds_type); - return -1; + default: + sfree(value); + ERROR("parse_value: Invalid data source type: %i.", ds_type); + return -1; } if (value == endptr) { - ERROR ("parse_value: Failed to parse string as %s: \"%s\".", - DS_TYPE_TO_STRING (ds_type), value); - sfree (value); + ERROR("parse_value: Failed to parse string as %s: \"%s\".", + DS_TYPE_TO_STRING(ds_type), value); + sfree(value); return -1; - } - else if ((NULL != endptr) && ('\0' != *endptr)) - INFO ("parse_value: Ignoring trailing garbage \"%s\" after %s value. " - "Input string was \"%s\".", - endptr, DS_TYPE_TO_STRING (ds_type), value_orig); + } else if ((NULL != endptr) && ('\0' != *endptr)) + INFO("parse_value: Ignoring trailing garbage \"%s\" after %s value. " + "Input string was \"%s\".", + endptr, DS_TYPE_TO_STRING(ds_type), value_orig); - sfree (value); + sfree(value); return 0; } /* int parse_value */ -int parse_values (char *buffer, value_list_t *vl, const data_set_t *ds) -{ - int i; - char *dummy; - char *ptr; - char *saveptr; - - if ((buffer == NULL) || (vl == NULL) || (ds == NULL)) - return EINVAL; - - i = -1; - dummy = buffer; - saveptr = NULL; - while ((ptr = strtok_r (dummy, ":", &saveptr)) != NULL) - { - dummy = NULL; - - if (i >= vl->values_len) - { - /* Make sure i is invalid. */ - i = vl->values_len + 1; - break; - } - - if (i == -1) - { - if (strcmp ("N", ptr) == 0) - vl->time = cdtime (); - else - { - char *endptr = NULL; - double tmp; - - errno = 0; - tmp = strtod (ptr, &endptr); - if ((errno != 0) /* Overflow */ - || (endptr == ptr) /* Invalid string */ - || (endptr == NULL) /* This should not happen */ - || (*endptr != 0)) /* Trailing chars */ - return (-1); - - vl->time = DOUBLE_TO_CDTIME_T (tmp); - } - } - else - { - 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].type)) - return -1; - } - - i++; - } /* while (strtok_r) */ - - if ((ptr != NULL) || (i != vl->values_len)) - return (-1); - return (0); +int parse_values(char *buffer, value_list_t *vl, const data_set_t *ds) { + size_t i; + char *dummy; + char *ptr; + char *saveptr; + + if ((buffer == NULL) || (vl == NULL) || (ds == NULL)) + return EINVAL; + + i = 0; + dummy = buffer; + saveptr = NULL; + vl->time = 0; + while ((ptr = strtok_r(dummy, ":", &saveptr)) != NULL) { + dummy = NULL; + + if (i >= vl->values_len) { + /* Make sure i is invalid. */ + i = 0; + break; + } + + if (vl->time == 0) { + if (strcmp("N", ptr) == 0) + vl->time = cdtime(); + else { + char *endptr = NULL; + double tmp; + + errno = 0; + tmp = strtod(ptr, &endptr); + if ((errno != 0) /* Overflow */ + || (endptr == ptr) /* Invalid string */ + || (endptr == NULL) /* This should not happen */ + || (*endptr != 0)) /* Trailing chars */ + return -1; + + vl->time = DOUBLE_TO_CDTIME_T(tmp); + } + + continue; + } + + 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].type)) + return -1; + + i++; + } /* while (strtok_r) */ + + if ((ptr != NULL) || (i == 0)) + return -1; + return 0; } /* int parse_values */ +int parse_value_file(char const *path, value_t *ret_value, int ds_type) { + FILE *fh; + char buffer[256]; + + fh = fopen(path, "r"); + if (fh == NULL) + return -1; + + if (fgets(buffer, sizeof(buffer), fh) == NULL) { + fclose(fh); + return -1; + } + + fclose(fh); + + strstripnewline(buffer); + + return parse_value(buffer, ret_value, ds_type); +} /* int parse_value_file */ + #if !HAVE_GETPWNAM_R -int getpwnam_r (const char *name, struct passwd *pwbuf, char *buf, - size_t buflen, struct passwd **pwbufp) -{ - int status = 0; - struct passwd *pw; - - memset (pwbuf, '\0', sizeof (struct passwd)); - - pthread_mutex_lock (&getpwnam_r_lock); - - do - { - pw = getpwnam (name); - if (pw == NULL) - { - status = (errno != 0) ? errno : ENOENT; - break; - } - -#define GETPWNAM_COPY_MEMBER(member) \ - if (pw->member != NULL) \ - { \ - int len = strlen (pw->member); \ - if (len >= buflen) \ - { \ - status = ENOMEM; \ - break; \ - } \ - sstrncpy (buf, pw->member, buflen); \ - pwbuf->member = buf; \ - buf += (len + 1); \ - buflen -= (len + 1); \ - } - GETPWNAM_COPY_MEMBER(pw_name); - GETPWNAM_COPY_MEMBER(pw_passwd); - GETPWNAM_COPY_MEMBER(pw_gecos); - GETPWNAM_COPY_MEMBER(pw_dir); - GETPWNAM_COPY_MEMBER(pw_shell); - - pwbuf->pw_uid = pw->pw_uid; - pwbuf->pw_gid = pw->pw_gid; - - if (pwbufp != NULL) - *pwbufp = pwbuf; - } while (0); - - pthread_mutex_unlock (&getpwnam_r_lock); - - return (status); +int getpwnam_r(const char *name, struct passwd *pwbuf, char *buf, size_t buflen, + struct passwd **pwbufp) { + int status = 0; + struct passwd *pw; + + memset(pwbuf, '\0', sizeof(struct passwd)); + + pthread_mutex_lock(&getpwnam_r_lock); + + do { + pw = getpwnam(name); + if (pw == NULL) { + status = (errno != 0) ? errno : ENOENT; + break; + } + +#define GETPWNAM_COPY_MEMBER(member) \ + if (pw->member != NULL) { \ + int len = strlen(pw->member); \ + if (len >= buflen) { \ + status = ENOMEM; \ + break; \ + } \ + sstrncpy(buf, pw->member, buflen); \ + pwbuf->member = buf; \ + buf += (len + 1); \ + buflen -= (len + 1); \ + } + GETPWNAM_COPY_MEMBER(pw_name); + GETPWNAM_COPY_MEMBER(pw_passwd); + GETPWNAM_COPY_MEMBER(pw_gecos); + GETPWNAM_COPY_MEMBER(pw_dir); + GETPWNAM_COPY_MEMBER(pw_shell); + + pwbuf->pw_uid = pw->pw_uid; + pwbuf->pw_gid = pw->pw_gid; + + if (pwbufp != NULL) + *pwbufp = pwbuf; + } while (0); + + pthread_mutex_unlock(&getpwnam_r_lock); + + return status; } /* int getpwnam_r */ #endif /* !HAVE_GETPWNAM_R */ -int notification_init (notification_t *n, int severity, const char *message, - const char *host, - const char *plugin, const char *plugin_instance, - const char *type, const char *type_instance) -{ - memset (n, '\0', sizeof (notification_t)); - - n->severity = severity; - - if (message != NULL) - sstrncpy (n->message, message, sizeof (n->message)); - if (host != NULL) - sstrncpy (n->host, host, sizeof (n->host)); - if (plugin != NULL) - sstrncpy (n->plugin, plugin, sizeof (n->plugin)); - if (plugin_instance != NULL) - sstrncpy (n->plugin_instance, plugin_instance, - sizeof (n->plugin_instance)); - if (type != NULL) - sstrncpy (n->type, type, sizeof (n->type)); - if (type_instance != NULL) - sstrncpy (n->type_instance, type_instance, - sizeof (n->type_instance)); - - return (0); +int notification_init(notification_t *n, int severity, const char *message, + const char *host, const char *plugin, + const char *plugin_instance, const char *type, + const char *type_instance) { + memset(n, '\0', sizeof(notification_t)); + + n->severity = severity; + + if (message != NULL) + sstrncpy(n->message, message, sizeof(n->message)); + if (host != NULL) + sstrncpy(n->host, host, sizeof(n->host)); + if (plugin != NULL) + sstrncpy(n->plugin, plugin, sizeof(n->plugin)); + if (plugin_instance != NULL) + sstrncpy(n->plugin_instance, plugin_instance, sizeof(n->plugin_instance)); + if (type != NULL) + sstrncpy(n->type, type, sizeof(n->type)); + if (type_instance != NULL) + sstrncpy(n->type_instance, type_instance, sizeof(n->type_instance)); + + return 0; } /* int notification_init */ -int walk_directory (const char *dir, dirwalk_callback_f callback, - void *user_data, int include_hidden) -{ - struct dirent *ent; - DIR *dh; - int success; - int failure; - - success = 0; - failure = 0; - - if ((dh = opendir (dir)) == NULL) - { - char errbuf[1024]; - ERROR ("walk_directory: Cannot open '%s': %s", dir, - sstrerror (errno, errbuf, sizeof (errbuf))); - return -1; - } - - while ((ent = readdir (dh)) != NULL) - { - int status; - - if (include_hidden) - { - if ((strcmp (".", ent->d_name) == 0) - || (strcmp ("..", ent->d_name) == 0)) - continue; - } - else /* if (!include_hidden) */ - { - if (ent->d_name[0]=='.') - continue; - } - - status = (*callback) (dir, ent->d_name, user_data); - if (status != 0) - failure++; - else - success++; - } - - closedir (dh); - - if ((success == 0) && (failure > 0)) - return (-1); - return (0); +int walk_directory(const char *dir, dirwalk_callback_f callback, + void *user_data, int include_hidden) { + struct dirent *ent; + DIR *dh; + int success; + int failure; + + success = 0; + failure = 0; + + if ((dh = opendir(dir)) == NULL) { + char errbuf[1024]; + ERROR("walk_directory: Cannot open '%s': %s", dir, + sstrerror(errno, errbuf, sizeof(errbuf))); + return -1; + } + + while ((ent = readdir(dh)) != NULL) { + int status; + + if (include_hidden) { + if ((strcmp(".", ent->d_name) == 0) || (strcmp("..", ent->d_name) == 0)) + continue; + } else /* if (!include_hidden) */ + { + if (ent->d_name[0] == '.') + continue; + } + + status = (*callback)(dir, ent->d_name, user_data); + if (status != 0) + failure++; + else + success++; + } + + closedir(dh); + + if ((success == 0) && (failure > 0)) + return -1; + return 0; } -ssize_t read_file_contents (const char *filename, char *buf, size_t bufsize) -{ - FILE *fh; - ssize_t ret; - - fh = fopen (filename, "r"); - if (fh == NULL) - return (-1); - - ret = (ssize_t) fread (buf, 1, bufsize, fh); - if ((ret == 0) && (ferror (fh) != 0)) - { - ERROR ("read_file_contents: Reading file \"%s\" failed.", - filename); - ret = -1; - } - - fclose(fh); - return (ret); +ssize_t read_file_contents(const char *filename, char *buf, size_t bufsize) { + FILE *fh; + ssize_t ret; + + fh = fopen(filename, "r"); + if (fh == NULL) + return -1; + + ret = (ssize_t)fread(buf, 1, bufsize, fh); + if ((ret == 0) && (ferror(fh) != 0)) { + ERROR("read_file_contents: Reading file \"%s\" failed.", filename); + ret = -1; + } + + fclose(fh); + return ret; } -counter_t counter_diff (counter_t old_value, counter_t new_value) -{ - counter_t diff; - - if (old_value > new_value) - { - if (old_value <= 4294967295U) - diff = (4294967295U - old_value) + new_value; - else - diff = (18446744073709551615ULL - old_value) - + new_value; - } - else - { - diff = new_value - old_value; - } - - return (diff); +counter_t counter_diff(counter_t old_value, counter_t new_value) { + counter_t diff; + + if (old_value > new_value) { + if (old_value <= 4294967295U) + diff = (4294967295U - old_value) + new_value + 1; + else + diff = (18446744073709551615ULL - old_value) + new_value + 1; + } else { + diff = new_value - old_value; + } + + return diff; } /* counter_t counter_diff */ -int rate_to_value (value_t *ret_value, gauge_t rate, /* {{{ */ - rate_to_value_state_t *state, - int ds_type, cdtime_t t) -{ - gauge_t delta_gauge; - cdtime_t delta_t; - - if (ds_type == DS_TYPE_GAUGE) - { - state->last_value.gauge = rate; - state->last_time = t; - - *ret_value = state->last_value; - return (0); - } - - /* Counter and absolute can't handle negative rates. Reset "last time" - * to zero, so that the next valid rate will re-initialize the - * structure. */ - if ((rate < 0.0) - && ((ds_type == DS_TYPE_COUNTER) - || (ds_type == DS_TYPE_ABSOLUTE))) - { - memset (state, 0, sizeof (*state)); - return (EINVAL); - } - - /* Another invalid state: The time is not increasing. */ - if (t <= state->last_time) - { - memset (state, 0, sizeof (*state)); - return (EINVAL); - } - - delta_t = t - state->last_time; - delta_gauge = (rate * CDTIME_T_TO_DOUBLE (delta_t)) + state->residual; - - /* Previous value is invalid. */ - if (state->last_time == 0) /* {{{ */ - { - if (ds_type == DS_TYPE_DERIVE) - { - state->last_value.derive = (derive_t) rate; - state->residual = rate - ((gauge_t) state->last_value.derive); - } - else if (ds_type == DS_TYPE_COUNTER) - { - state->last_value.counter = (counter_t) rate; - state->residual = rate - ((gauge_t) state->last_value.counter); - } - else if (ds_type == DS_TYPE_ABSOLUTE) - { - state->last_value.absolute = (absolute_t) rate; - state->residual = rate - ((gauge_t) state->last_value.absolute); - } - else - { - assert (23 == 42); - } - - state->last_time = t; - return (EAGAIN); - } /* }}} */ - - if (ds_type == DS_TYPE_DERIVE) - { - derive_t delta_derive = (derive_t) delta_gauge; - - state->last_value.derive += delta_derive; - state->residual = delta_gauge - ((gauge_t) delta_derive); - } - else if (ds_type == DS_TYPE_COUNTER) - { - counter_t delta_counter = (counter_t) delta_gauge; - - state->last_value.counter += delta_counter; - state->residual = delta_gauge - ((gauge_t) delta_counter); - } - else if (ds_type == DS_TYPE_ABSOLUTE) - { - absolute_t delta_absolute = (absolute_t) delta_gauge; - - state->last_value.absolute = delta_absolute; - state->residual = delta_gauge - ((gauge_t) delta_absolute); - } - else - { - assert (23 == 42); - } - - state->last_time = t; - *ret_value = state->last_value; - return (0); +int rate_to_value(value_t *ret_value, gauge_t rate, /* {{{ */ + rate_to_value_state_t *state, int ds_type, cdtime_t t) { + gauge_t delta_gauge; + cdtime_t delta_t; + + if (ds_type == DS_TYPE_GAUGE) { + state->last_value.gauge = rate; + state->last_time = t; + + *ret_value = state->last_value; + return 0; + } + + /* Counter and absolute can't handle negative rates. Reset "last time" + * to zero, so that the next valid rate will re-initialize the + * structure. */ + if ((rate < 0.0) && + ((ds_type == DS_TYPE_COUNTER) || (ds_type == DS_TYPE_ABSOLUTE))) { + memset(state, 0, sizeof(*state)); + return EINVAL; + } + + /* Another invalid state: The time is not increasing. */ + if (t <= state->last_time) { + memset(state, 0, sizeof(*state)); + return EINVAL; + } + + delta_t = t - state->last_time; + delta_gauge = (rate * CDTIME_T_TO_DOUBLE(delta_t)) + state->residual; + + /* Previous value is invalid. */ + if (state->last_time == 0) /* {{{ */ + { + if (ds_type == DS_TYPE_DERIVE) { + state->last_value.derive = (derive_t)rate; + state->residual = rate - ((gauge_t)state->last_value.derive); + } else if (ds_type == DS_TYPE_COUNTER) { + state->last_value.counter = (counter_t)rate; + state->residual = rate - ((gauge_t)state->last_value.counter); + } else if (ds_type == DS_TYPE_ABSOLUTE) { + state->last_value.absolute = (absolute_t)rate; + state->residual = rate - ((gauge_t)state->last_value.absolute); + } else { + assert(23 == 42); + } + + state->last_time = t; + return EAGAIN; + } /* }}} */ + + if (ds_type == DS_TYPE_DERIVE) { + derive_t delta_derive = (derive_t)delta_gauge; + + state->last_value.derive += delta_derive; + state->residual = delta_gauge - ((gauge_t)delta_derive); + } else if (ds_type == DS_TYPE_COUNTER) { + counter_t delta_counter = (counter_t)delta_gauge; + + state->last_value.counter += delta_counter; + state->residual = delta_gauge - ((gauge_t)delta_counter); + } else if (ds_type == DS_TYPE_ABSOLUTE) { + absolute_t delta_absolute = (absolute_t)delta_gauge; + + state->last_value.absolute = delta_absolute; + state->residual = delta_gauge - ((gauge_t)delta_absolute); + } else { + assert(23 == 42); + } + + state->last_time = t; + *ret_value = state->last_value; + return 0; } /* }}} value_t rate_to_value */ -int value_to_rate (value_t *ret_rate, derive_t value, /* {{{ */ - value_to_rate_state_t *state, - int ds_type, cdtime_t t) -{ - double interval; - - /* Another invalid state: The time is not increasing. */ - if (t <= state->last_time) - { - memset (state, 0, sizeof (*state)); - return (EINVAL); - } - - interval = CDTIME_T_TO_DOUBLE(t - state->last_time); - - /* Previous value is invalid. */ - if (state->last_time == 0) /* {{{ */ - { - if (ds_type == DS_TYPE_DERIVE) - { - state->last_value.derive = value; - } - else if (ds_type == DS_TYPE_COUNTER) - { - state->last_value.counter = (counter_t) value; - } - else if (ds_type == DS_TYPE_ABSOLUTE) - { - state->last_value.absolute = (absolute_t) value; - } - else - { - assert (23 == 42); - } - - state->last_time = t; - return (EAGAIN); - } /* }}} */ - - if (ds_type == DS_TYPE_DERIVE) - { - ret_rate->gauge = (value - state->last_value.derive) / interval; - state->last_value.derive = value; - } - else if (ds_type == DS_TYPE_COUNTER) - { - ret_rate->gauge = (((counter_t)value) - state->last_value.counter) / interval; - state->last_value.counter = (counter_t) value; - } - else if (ds_type == DS_TYPE_ABSOLUTE) - { - ret_rate->gauge = (((absolute_t)value) - state->last_value.absolute) / interval; - state->last_value.absolute = (absolute_t) value; - } - else - { - assert (23 == 42); - } - - state->last_time = t; - return (0); +int value_to_rate(gauge_t *ret_rate, /* {{{ */ + value_t value, int ds_type, cdtime_t t, + value_to_rate_state_t *state) { + gauge_t interval; + + /* Another invalid state: The time is not increasing. */ + if (t <= state->last_time) { + memset(state, 0, sizeof(*state)); + return EINVAL; + } + + interval = CDTIME_T_TO_DOUBLE(t - state->last_time); + + /* Previous value is invalid. */ + if (state->last_time == 0) { + state->last_value = value; + state->last_time = t; + return EAGAIN; + } + + switch (ds_type) { + case DS_TYPE_DERIVE: { + derive_t diff = value.derive - state->last_value.derive; + *ret_rate = ((gauge_t)diff) / ((gauge_t)interval); + break; + } + case DS_TYPE_GAUGE: { + *ret_rate = value.gauge; + break; + } + case DS_TYPE_COUNTER: { + counter_t diff = counter_diff(state->last_value.counter, value.counter); + *ret_rate = ((gauge_t)diff) / ((gauge_t)interval); + break; + } + case DS_TYPE_ABSOLUTE: { + absolute_t diff = value.absolute; + *ret_rate = ((gauge_t)diff) / ((gauge_t)interval); + break; + } + default: + return EINVAL; + } + + state->last_value = value; + state->last_time = t; + return 0; } /* }}} value_t rate_to_value */ -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(const char *service_name) { + struct addrinfo *ai_list; + int status; + int service_number; + + if (service_name == NULL) + return -1; + + struct addrinfo 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 (struct addrinfo *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 */ -int strtoderive (const char *string, derive_t *ret_value) /* {{{ */ +void set_sock_opts(int sockfd) /* {{{ */ { - derive_t tmp; - char *endptr; + int status; + int socktype; + + status = getsockopt(sockfd, SOL_SOCKET, SO_TYPE, &socktype, + &(socklen_t){sizeof(socktype)}); + if (status != 0) { + WARNING("set_sock_opts: failed to determine socket type"); + return; + } - if ((string == NULL) || (ret_value == NULL)) - return (EINVAL); + if (socktype == SOCK_STREAM) { + status = + setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &(int){1}, sizeof(int)); + if (status != 0) + WARNING("set_sock_opts: failed to set socket keepalive flag"); + +#ifdef TCP_KEEPIDLE + int tcp_keepidle = ((CDTIME_T_TO_MS(plugin_get_interval()) - 1) / 100 + 1); + status = setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, &tcp_keepidle, + sizeof(tcp_keepidle)); + if (status != 0) + WARNING("set_sock_opts: failed to set socket tcp keepalive time"); +#endif - errno = 0; - endptr = NULL; - tmp = (derive_t) strtoll (string, &endptr, /* base = */ 0); - if ((endptr == string) || (errno != 0)) - return (-1); +#ifdef TCP_KEEPINTVL + int tcp_keepintvl = + ((CDTIME_T_TO_MS(plugin_get_interval()) - 1) / 1000 + 1); + status = setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL, &tcp_keepintvl, + sizeof(tcp_keepintvl)); + if (status != 0) + WARNING("set_sock_opts: failed to set socket tcp keepalive interval"); +#endif + } +} /* }}} void set_sock_opts */ - *ret_value = tmp; - return (0); +int strtoderive(const char *string, derive_t *ret_value) /* {{{ */ +{ + derive_t tmp; + char *endptr; + + if ((string == NULL) || (ret_value == NULL)) + return EINVAL; + + errno = 0; + endptr = NULL; + tmp = (derive_t)strtoll(string, &endptr, /* base = */ 0); + if ((endptr == string) || (errno != 0)) + return -1; + + *ret_value = tmp; + return 0; } /* }}} int strtoderive */ -int strtogauge (const char *string, gauge_t *ret_value) /* {{{ */ +int strtogauge(const char *string, gauge_t *ret_value) /* {{{ */ { - gauge_t tmp; - char *endptr = NULL; - - if ((string == NULL) || (ret_value == NULL)) - return (EINVAL); - - errno = 0; - endptr = NULL; - tmp = (gauge_t) strtod (string, &endptr); - if (errno != 0) - return (errno); - else if ((endptr == NULL) || (*endptr != 0)) - return (EINVAL); - - *ret_value = tmp; - return (0); + gauge_t tmp; + char *endptr = NULL; + + if ((string == NULL) || (ret_value == NULL)) + return EINVAL; + + errno = 0; + endptr = NULL; + tmp = (gauge_t)strtod(string, &endptr); + if (errno != 0) + return errno; + else if ((endptr == NULL) || (*endptr != 0)) + return EINVAL; + + *ret_value = tmp; + return 0; } /* }}} int strtogauge */ -int strarray_add (char ***ret_array, size_t *ret_array_len, char const *str) /* {{{ */ +int strarray_add(char ***ret_array, size_t *ret_array_len, + char const *str) /* {{{ */ { - char **array; - size_t array_len = *ret_array_len; + char **array; + size_t array_len = *ret_array_len; - if (str == NULL) - return (EINVAL); + if (str == NULL) + return EINVAL; - array = realloc (*ret_array, - (array_len + 1) * sizeof (*array)); - if (array == NULL) - return (ENOMEM); - *ret_array = array; + array = realloc(*ret_array, (array_len + 1) * sizeof(*array)); + if (array == NULL) + return ENOMEM; + *ret_array = array; - array[array_len] = strdup (str); - if (array[array_len] == NULL) - return (ENOMEM); + array[array_len] = strdup(str); + if (array[array_len] == NULL) + return ENOMEM; - array_len++; - *ret_array_len = array_len; - return (0); + array_len++; + *ret_array_len = array_len; + return 0; } /* }}} int strarray_add */ -void strarray_free (char **array, size_t array_len) /* {{{ */ +void strarray_free(char **array, size_t array_len) /* {{{ */ { - size_t i; - - for (i = 0; i < array_len; i++) - sfree (array[i]); - sfree (array); + for (size_t i = 0; i < array_len; i++) + sfree(array[i]); + sfree(array); } /* }}} void strarray_free */ + +#if HAVE_CAPABILITY +int check_capability(int arg) /* {{{ */ +{ + cap_value_t cap_value = (cap_value_t)arg; + cap_t cap; + cap_flag_value_t cap_flag_value; + + if (!CAP_IS_SUPPORTED(cap_value)) + return -1; + + if (!(cap = cap_get_proc())) { + ERROR("check_capability: cap_get_proc failed."); + return -1; + } + + if (cap_get_flag(cap, cap_value, CAP_EFFECTIVE, &cap_flag_value) < 0) { + ERROR("check_capability: cap_get_flag failed."); + cap_free(cap); + return -1; + } + cap_free(cap); + + return cap_flag_value != CAP_SET; +} /* }}} int check_capability */ +#else +int check_capability(__attribute__((unused)) int arg) /* {{{ */ +{ + WARNING("check_capability: unsupported capability implementation. " + "Some plugin(s) may require elevated privileges to work properly."); + return 0; +} /* }}} int check_capability */ +#endif /* HAVE_CAPABILITY */