X-Git-Url: https://git.verplant.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Fceph.c;h=64d87855fbb0f820ea1a8e8f6d09eeb61894154c;hb=4d370741101aeb037ae52f3529a4a0869e0dc08a;hp=d928a7ba4b5db1d71e87449f635783e44000f621;hpb=21a4ddcc2d66eea59224fd95746c7533b1b1a46d;p=collectd.git diff --git a/src/ceph.c b/src/ceph.c index d928a7ba..64d87855 100644 --- a/src/ceph.c +++ b/src/ceph.c @@ -1,6 +1,7 @@ /** * collectd - src/ceph.c * Copyright (C) 2011 New Dream Network + * Copyright (C) 2015 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 @@ -16,15 +17,17 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * Authors: - * Colin McCabe - * Dennis Zou - * Dan Ryder + * Colin McCabe + * Dennis Zou + * Dan Ryder + * Florian octo Forster **/ #define _DEFAULT_SOURCE #define _BSD_SOURCE #include "collectd.h" + #include "common.h" #include "plugin.h" @@ -35,6 +38,9 @@ #if HAVE_YAJL_YAJL_VERSION_H #include #endif +#ifdef HAVE_SYS_CAPABILITY_H +# include +#endif #include #include @@ -43,7 +49,6 @@ #include #include #include -#include #include #include #include @@ -95,7 +100,7 @@ enum ceph_dset_type_d }; /** Valid types for ceph defined in types.db */ -const char * ceph_dset_types [CEPH_DSET_TYPES_NUM] = +static const char * const ceph_dset_types [CEPH_DSET_TYPES_NUM] = {"ceph_latency", "ceph_bytes", "ceph_rate"}; /******* ceph_daemon *******/ @@ -133,11 +138,10 @@ struct yajl_struct { node_handler_t handler; void * handler_arg; - struct { - char key[DATA_MAX_NAME_LEN]; - int key_len; - } state[YAJL_MAX_DEPTH]; - int depth; + + char *key; + char *stack[YAJL_MAX_DEPTH]; + size_t depth; }; typedef struct yajl_struct yajl_struct; @@ -163,7 +167,7 @@ static int convert_special_metrics = 1; static struct ceph_daemon **g_daemons = NULL; /** Number of elements in g_daemons */ -static int g_num_daemons = 0; +static size_t g_num_daemons = 0; /** * A set of data that we build up in memory while parsing the JSON. @@ -256,68 +260,87 @@ static int ceph_cb_boolean(void *ctx, int bool_val) return CEPH_CB_CONTINUE; } +#define BUFFER_ADD(dest, src) do { \ + size_t dest_size = sizeof (dest); \ + size_t dest_len = strlen (dest); \ + if (dest_size > dest_len) { \ + sstrncpy ((dest) + dest_len, (src), dest_size - dest_len); \ + } \ + (dest)[dest_size - 1] = 0; \ +} while (0) + static int ceph_cb_number(void *ctx, const char *number_val, yajl_len_t number_len) { - yajl_struct *yajl = (yajl_struct*)ctx; + yajl_struct *state = (yajl_struct*) ctx; char buffer[number_len+1]; - int i, latency_type = 0, result; - char key[128]; + char key[2 * DATA_MAX_NAME_LEN] = { 0 }; + _Bool latency_type = 0; + int status; memcpy(buffer, number_val, number_len); - buffer[sizeof(buffer) - 1] = 0; + buffer[sizeof(buffer) - 1] = '\0'; + + for (size_t i = 0; i < state->depth; i++) + { + if (state->stack[i] == NULL) + continue; + + if (strlen (key) != 0) + BUFFER_ADD (key, "."); + BUFFER_ADD (key, state->stack[i]); + } - ssnprintf(key, yajl->state[0].key_len, "%s", yajl->state[0].key); - for(i = 1; i < yajl->depth; i++) + /* Special case for latency metrics. */ + if ((strcmp ("avgcount", state->key) == 0) + || (strcmp ("sum", state->key) == 0)) { - if((i == yajl->depth-1) && ((strcmp(yajl->state[i].key,"avgcount") == 0) - || (strcmp(yajl->state[i].key,"sum") == 0))) + latency_type = 1; + + /* depth >= 2 => (stack[-1] != NULL && stack[-2] != NULL) */ + assert ((state->depth < 2) + || ((state->stack[state->depth - 1] != NULL) + && (state->stack[state->depth - 2] != NULL))); + + /* Super-special case for filestore.journal_wr_bytes.avgcount: For + * some reason, Ceph schema encodes this as a count/sum pair while all + * other "Bytes" data (excluding used/capacity bytes for OSD space) uses + * a single "Derive" type. To spare further confusion, keep this KPI as + * the same type of other "Bytes". Instead of keeping an "average" or + * "rate", use the "sum" in the pair and assign that to the derive + * value. */ + if (convert_special_metrics && (state->depth >= 2) + && (strcmp("filestore", state->stack[state->depth - 2]) == 0) + && (strcmp("journal_wr_bytes", state->stack[state->depth - 1]) == 0) + && (strcmp("avgcount", state->key) == 0)) { - if(convert_special_metrics) - { - /** - * Special case for filestore:JournalWrBytes. For some reason, - * Ceph schema encodes this as a count/sum pair while all - * other "Bytes" data (excluding used/capacity bytes for OSD - * space) uses a single "Derive" type. To spare further - * confusion, keep this KPI as the same type of other "Bytes". - * Instead of keeping an "average" or "rate", use the "sum" in - * the pair and assign that to the derive value. - */ - if((strcmp(yajl->state[i-1].key, "journal_wr_bytes") == 0) && - (strcmp(yajl->state[i-2].key,"filestore") == 0) && - (strcmp(yajl->state[i].key,"avgcount") == 0)) - { - DEBUG("ceph plugin: Skipping avgcount for filestore.JournalWrBytes"); - yajl->depth = (yajl->depth - 1); - return CEPH_CB_CONTINUE; - } - } - //probably a avgcount/sum pair. if not - we'll try full key later - latency_type = 1; - break; + DEBUG("ceph plugin: Skipping avgcount for filestore.JournalWrBytes"); + return CEPH_CB_CONTINUE; } - strncat(key, ".", 1); - strncat(key, yajl->state[i].key, yajl->state[i].key_len+1); + } + else /* not a latency type */ + { + BUFFER_ADD (key, "."); + BUFFER_ADD (key, state->key); } - result = yajl->handler(yajl->handler_arg, buffer, key); - - if((result == RETRY_AVGCOUNT) && latency_type) + status = state->handler(state->handler_arg, buffer, key); + if((status == RETRY_AVGCOUNT) && latency_type) { - strncat(key, ".", 1); - strncat(key, yajl->state[yajl->depth-1].key, - yajl->state[yajl->depth-1].key_len+1); - result = yajl->handler(yajl->handler_arg, buffer, key); + /* Add previously skipped part of the key, either "avgcount" or "sum", + * and try again. */ + BUFFER_ADD (key, "."); + BUFFER_ADD (key, state->key); + + status = state->handler(state->handler_arg, buffer, key); } - if(result == -ENOMEM) + if (status != 0) { - ERROR("ceph plugin: memory allocation failed"); + ERROR("ceph plugin: JSON handler failed with status %d.", status); return CEPH_CB_ABORT; } - yajl->depth = (yajl->depth - 1); return CEPH_CB_CONTINUE; } @@ -329,37 +352,52 @@ static int ceph_cb_string(void *ctx, const unsigned char *string_val, static int ceph_cb_start_map(void *ctx) { + yajl_struct *state = (yajl_struct*) ctx; + + /* Push key to the stack */ + if (state->depth == YAJL_MAX_DEPTH) + return CEPH_CB_ABORT; + + state->stack[state->depth] = state->key; + state->depth++; + state->key = NULL; + return CEPH_CB_CONTINUE; } -static int -ceph_cb_map_key(void *ctx, const unsigned char *key, yajl_len_t string_len) +static int ceph_cb_end_map(void *ctx) { - yajl_struct *yajl = (yajl_struct*)ctx; + yajl_struct *state = (yajl_struct*) ctx; - if((yajl->depth+1) >= YAJL_MAX_DEPTH) - { - ERROR("ceph plugin: depth exceeds max, aborting."); + /* Pop key from the stack */ + if (state->depth == 0) return CEPH_CB_ABORT; - } - char buffer[string_len+1]; - - memcpy(buffer, key, string_len); - buffer[sizeof(buffer) - 1] = 0; - - snprintf(yajl->state[yajl->depth].key, sizeof(buffer), "%s", buffer); - yajl->state[yajl->depth].key_len = sizeof(buffer); - yajl->depth = (yajl->depth + 1); + sfree (state->key); + state->depth--; + state->key = state->stack[state->depth]; + state->stack[state->depth] = NULL; return CEPH_CB_CONTINUE; } -static int ceph_cb_end_map(void *ctx) +static int +ceph_cb_map_key(void *ctx, const unsigned char *key, yajl_len_t string_len) { - yajl_struct *yajl = (yajl_struct*)ctx; + yajl_struct *state = (yajl_struct*) ctx; + size_t sz = ((size_t) string_len) + 1; + + sfree (state->key); + state->key = malloc (sz); + if (state->key == NULL) + { + ERROR ("ceph plugin: malloc failed."); + return CEPH_CB_ABORT; + } + + memmove (state->key, key, sz - 1); + state->key[sz - 1] = 0; - yajl->depth = (yajl->depth - 1); return CEPH_CB_CONTINUE; } @@ -394,8 +432,7 @@ static void ceph_daemon_print(const struct ceph_daemon *d) static void ceph_daemons_print(void) { - int i; - for(i = 0; i < g_num_daemons; ++i) + for(size_t i = 0; i < g_num_daemons; ++i) { ceph_daemon_print(g_daemons[i]); } @@ -403,15 +440,15 @@ static void ceph_daemons_print(void) static void ceph_daemon_free(struct ceph_daemon *d) { - int i = 0; - for(; i < d->last_idx; i++) + for(int i = 0; i < d->last_idx; i++) { sfree(d->last_poll_data[i]); } sfree(d->last_poll_data); d->last_poll_data = NULL; d->last_idx = 0; - for(i = 0; i < d->ds_num; i++) + + for(int i = 0; i < d->ds_num; i++) { sfree(d->ds_names[i]); } @@ -420,140 +457,139 @@ static void ceph_daemon_free(struct ceph_daemon *d) sfree(d); } -/** - * Compact ds name by removing special characters and trimming length to - * DATA_MAX_NAME_LEN if necessary - */ -static void compact_ds_name(char *source, char *dest) +/* compact_ds_name removed the special characters ":", "_", "-" and "+" from the + * intput string. Characters following these special characters are capitalized. + * Trailing "+" and "-" characters are replaces with the strings "Plus" and + * "Minus". */ +static int compact_ds_name (char *buffer, size_t buffer_size, char const *src) { - int keys_num = 0, i; - char *save_ptr = NULL, *tmp_ptr = source; - char *keys[16]; - char len_str[3]; - char tmp[DATA_MAX_NAME_LEN]; - size_t key_chars_remaining = (DATA_MAX_NAME_LEN-1); - int reserved = 0; - int offset = 0; - memset(tmp, 0, sizeof(tmp)); - if(source == NULL || dest == NULL || source[0] == '\0' || dest[0] != '\0') - { - return; - } - size_t src_len = strlen(source); - snprintf(len_str, sizeof(len_str), "%zu", src_len); - unsigned char append_status = 0x0; - append_status |= (source[src_len - 1] == '-') ? 0x1 : 0x0; - append_status |= (source[src_len - 1] == '+') ? 0x2 : 0x0; - while ((keys[keys_num] = strtok_r(tmp_ptr, ":_-+", &save_ptr)) != NULL) - { - tmp_ptr = NULL; - /** capitalize 1st char **/ - keys[keys_num][0] = toupper(keys[keys_num][0]); - keys_num++; - if(keys_num >= 16) - { - break; - } - } - /** concatenate each part of source string **/ - for(i = 0; i < keys_num; i++) - { - strncat(tmp, keys[i], key_chars_remaining); - key_chars_remaining -= strlen(keys[i]); - } - tmp[DATA_MAX_NAME_LEN - 1] = '\0'; - /** to coordinate limitation of length of type_instance - * we will truncate ds_name - * when the its length is more than - * DATA_MAX_NAME_LEN - */ - if(strlen(tmp) > DATA_MAX_NAME_LEN - 1) + char *src_copy; + size_t src_len; + char *ptr = buffer; + size_t ptr_size = buffer_size; + _Bool append_plus = 0; + _Bool append_minus = 0; + + if ((buffer == NULL) || (buffer_size <= strlen ("Minus")) || (src == NULL)) + return EINVAL; + + src_copy = strdup (src); + src_len = strlen(src); + + /* Remove trailing "+" and "-". */ + if (src_copy[src_len - 1] == '+') { - append_status |= 0x4; - /** we should reserve space for - * len_str - */ - reserved += 2; + append_plus = 1; + src_len--; + src_copy[src_len] = 0; } - if(append_status & 0x1) + else if (src_copy[src_len - 1] == '-') { - /** we should reserve space for - * "Minus" - */ - reserved += 5; + append_minus = 1; + src_len--; + src_copy[src_len] = 0; } - if(append_status & 0x2) + + /* Split at special chars, capitalize first character, append to buffer. */ + char *dummy = src_copy; + char *token; + char *save_ptr = NULL; + while ((token = strtok_r (dummy, ":_-+", &save_ptr)) != NULL) { - /** we should reserve space for - * "Plus" - */ - reserved += 4; + size_t len; + + dummy = NULL; + + token[0] = toupper ((int) token[0]); + + assert (ptr_size > 1); + + len = strlen (token); + if (len >= ptr_size) + len = ptr_size - 1; + + assert (len > 0); + assert (len < ptr_size); + + sstrncpy (ptr, token, len + 1); + ptr += len; + ptr_size -= len; + + assert (*ptr == 0); + if (ptr_size <= 1) + break; } - snprintf(dest, DATA_MAX_NAME_LEN - reserved, "%s", tmp); - offset = strlen(dest); - switch (append_status) + + /* Append "Plus" or "Minus" if "+" or "-" has been stripped above. */ + if (append_plus || append_minus) { - case 0x1: - memcpy(dest + offset, "Minus", 5); - break; - case 0x2: - memcpy(dest + offset, "Plus", 5); - break; - case 0x4: - memcpy(dest + offset, len_str, 2); - break; - case 0x5: - memcpy(dest + offset, "Minus", 5); - memcpy(dest + offset + 5, len_str, 2); - break; - case 0x6: - memcpy(dest + offset, "Plus", 4); - memcpy(dest + offset + 4, len_str, 2); - break; - default: - break; + char const *append = "Plus"; + if (append_minus) + append = "Minus"; + + size_t offset = buffer_size - (strlen (append) + 1); + if (offset > strlen (buffer)) + offset = strlen (buffer); + + sstrncpy (buffer + offset, append, buffer_size - offset); } + + sfree (src_copy); + return 0; +} + +static _Bool has_suffix (char const *str, char const *suffix) +{ + size_t str_len = strlen (str); + size_t suffix_len = strlen (suffix); + size_t offset; + + if (suffix_len > str_len) + return 0; + offset = str_len - suffix_len; + + if (strcmp (str + offset, suffix) == 0) + return 1; + + return 0; +} + +/* count_parts returns the number of elements a "foo.bar.baz" style key has. */ +static size_t count_parts (char const *key) +{ + size_t parts_num = 0; + + for (const char *ptr = key; ptr != NULL; ptr = strchr (ptr + 1, '.')) + parts_num++; + + return parts_num; } /** * Parse key to remove "type" if this is for schema and initiate compaction */ -static int parse_keys(const char *key_str, char *ds_name) +static int parse_keys (char *buffer, size_t buffer_size, const char *key_str) { - char *ptr, *rptr; - size_t ds_name_len = 0; - /** - * allow up to 100 characters before compaction - compact_ds_name will not - * allow more than DATA_MAX_NAME_LEN chars - */ - int max_str_len = 100; - char tmp_ds_name[max_str_len]; - memset(tmp_ds_name, 0, sizeof(tmp_ds_name)); - if(ds_name == NULL || key_str == NULL || key_str[0] == '\0' || - ds_name[0] != '\0') - { - return -1; - } - if((ptr = strchr(key_str, '.')) == NULL - || (rptr = strrchr(key_str, '.')) == NULL) + char tmp[2 * buffer_size]; + + if (buffer == NULL || buffer_size == 0 || key_str == NULL || strlen (key_str) == 0) + return EINVAL; + + if ((count_parts (key_str) > 2) && has_suffix (key_str, ".type")) { - memcpy(tmp_ds_name, key_str, max_str_len - 1); - goto compact; - } + /* strip ".type" suffix iff the key has more than two parts. */ + size_t sz = strlen (key_str) - strlen (".type") + 1; - ds_name_len = (rptr - ptr) > max_str_len ? max_str_len : (rptr - ptr); - if((ds_name_len == 0) || strncmp(rptr + 1, "type", 4)) - { /** copy whole key **/ - memcpy(tmp_ds_name, key_str, max_str_len - 1); + if (sz > sizeof (tmp)) + sz = sizeof (tmp); + sstrncpy (tmp, key_str, sz); } else - {/** more than two keys **/ - memcpy(tmp_ds_name, key_str, ((rptr - key_str) > (max_str_len - 1) ? - (max_str_len - 1) : (rptr - key_str))); + { + sstrncpy (tmp, key_str, sizeof (tmp)); } - compact: compact_ds_name(tmp_ds_name, ds_name); - return 0; + return compact_ds_name (buffer, buffer_size, tmp); } /** @@ -565,7 +601,6 @@ static int ceph_daemon_add_ds_entry(struct ceph_daemon *d, const char *name, { uint32_t type; char ds_name[DATA_MAX_NAME_LEN]; - memset(ds_name, 0, sizeof(ds_name)); if(convert_special_metrics) { @@ -595,7 +630,7 @@ static int ceph_daemon_add_ds_entry(struct ceph_daemon *d, const char *name, return -ENOMEM; } - d->ds_names[d->ds_num] = malloc(sizeof(char) * DATA_MAX_NAME_LEN); + d->ds_names[d->ds_num] = malloc(DATA_MAX_NAME_LEN); if(!d->ds_names[d->ds_num]) { return -ENOMEM; @@ -605,7 +640,7 @@ static int ceph_daemon_add_ds_entry(struct ceph_daemon *d, const char *name, ((pc_type & PERFCOUNTER_LATENCY) ? DSET_LATENCY : DSET_BYTES); d->ds_types[d->ds_num] = type; - if(parse_keys(name, ds_name)) + if (parse_keys(ds_name, sizeof (ds_name), name)) { return 1; } @@ -656,10 +691,9 @@ static int cc_handle_bool(struct oconfig_item_s *item, int *dest) static int cc_add_daemon_config(oconfig_item_t *ci) { - int ret, i; - struct ceph_daemon *nd, cd; + int ret; + struct ceph_daemon *nd, cd = { 0 }; struct ceph_daemon **tmp; - memset(&cd, 0, sizeof(struct ceph_daemon)); if((ci->values_num != 1) || (ci->values[0].type != OCONFIG_TYPE_STRING)) { @@ -674,7 +708,7 @@ static int cc_add_daemon_config(oconfig_item_t *ci) return ret; } - for(i=0; i < ci->children_num; i++) + for(int i=0; i < ci->children_num; i++) { oconfig_item_t *child = ci->children + i; @@ -719,21 +753,22 @@ static int cc_add_daemon_config(oconfig_item_t *ci) } g_daemons = tmp; - nd = malloc(sizeof(*nd)); + nd = malloc(sizeof (*nd)); if(!nd) { return ENOMEM; } memcpy(nd, &cd, sizeof(*nd)); - g_daemons[g_num_daemons++] = nd; + g_daemons[g_num_daemons] = nd; + g_num_daemons++; return 0; } static int ceph_config(oconfig_item_t *ci) { - int ret, i; + int ret; - for(i = 0; i < ci->children_num; ++i) + for(int i = 0; i < ci->children_num; ++i) { oconfig_item_t *child = ci->children + i; if(strcasecmp("Daemon", child->key) == 0) @@ -817,7 +852,7 @@ node_handler_define_schema(void *arg, const char *val, const char *key) static int add_last(struct ceph_daemon *d, const char *ds_n, double cur_sum, uint64_t cur_count) { - d->last_poll_data[d->last_idx] = malloc(1 * sizeof(struct last_data)); + d->last_poll_data[d->last_idx] = malloc(sizeof (*d->last_poll_data[d->last_idx])); if(!d->last_poll_data[d->last_idx]) { return -ENOMEM; @@ -845,7 +880,7 @@ static int update_last(struct ceph_daemon *d, const char *ds_n, int index, if(!d->last_poll_data) { - d->last_poll_data = malloc(1 * sizeof(struct last_data *)); + d->last_poll_data = malloc(sizeof (*d->last_poll_data)); if(!d->last_poll_data) { return -ENOMEM; @@ -870,8 +905,7 @@ static int update_last(struct ceph_daemon *d, const char *ds_n, int index, */ static int backup_search_for_last_avg(struct ceph_daemon *d, const char *ds_n) { - int i = 0; - for(; i < d->last_idx; i++) + for(int i = 0; i < d->last_idx; i++) { if(strcmp(d->last_poll_data[i]->ds_name, ds_n) == 0) { @@ -931,12 +965,11 @@ static double get_last_avg(struct ceph_daemon *d, const char *ds_n, int index, */ static uint32_t backup_search_for_type(struct ceph_daemon *d, char *ds_name) { - int idx = 0; - for(; idx < d->ds_num; idx++) + for(int i = 0; i < d->ds_num; i++) { - if(strcmp(d->ds_names[idx], ds_name) == 0) + if(strcmp(d->ds_names[i], ds_name) == 0) { - return d->ds_types[idx]; + return d->ds_types[i]; } } return DSET_TYPE_UNFOUND; @@ -955,9 +988,8 @@ static int node_handler_fetch_data(void *arg, const char *val, const char *key) int index = vtmp->index; char ds_name[DATA_MAX_NAME_LEN]; - memset(ds_name, 0, sizeof(ds_name)); - if(parse_keys(key, ds_name)) + if (parse_keys (ds_name, sizeof (ds_name), key)) { return 1; } @@ -1058,7 +1090,7 @@ static int node_handler_fetch_data(void *arg, const char *val, const char *key) static int cconn_connect(struct cconn *io) { - struct sockaddr_un address; + struct sockaddr_un address = { 0 }; int flags, fd, err; if(io->state != CSTATE_UNCONNECTED) { @@ -1068,12 +1100,11 @@ static int cconn_connect(struct cconn *io) fd = socket(PF_UNIX, SOCK_STREAM, 0); if(fd < 0) { - int err = -errno; + err = -errno; ERROR("ceph plugin: cconn_connect: socket(PF_UNIX, SOCK_STREAM, 0) " "failed: error %d", err); return err; } - memset(&address, 0, sizeof(struct sockaddr_un)); address.sun_family = AF_UNIX; snprintf(address.sun_path, sizeof(address.sun_path), "%s", io->d->asok_path); @@ -1083,6 +1114,7 @@ static int cconn_connect(struct cconn *io) { ERROR("ceph plugin: cconn_connect: connect(%d) failed: error %d", fd, err); + close(fd); return err; } @@ -1092,6 +1124,7 @@ static int cconn_connect(struct cconn *io) err = -errno; ERROR("ceph plugin: cconn_connect: fcntl(%d, O_NONBLOCK) error %d", fd, err); + close(fd); return err; } io->asok = fd; @@ -1431,19 +1464,26 @@ static int milli_diff(const struct timeval *t1, const struct timeval *t2) */ static int cconn_main_loop(uint32_t request_type) { - int i, ret, some_unreachable = 0; + int ret, some_unreachable = 0; struct timeval end_tv; struct cconn io_array[g_num_daemons]; - DEBUG("ceph plugin: entering cconn_main_loop(request_type = %d)", request_type); + DEBUG ("ceph plugin: entering cconn_main_loop(request_type = %"PRIu32")", request_type); + + if (g_num_daemons < 1) + { + ERROR ("ceph plugin: No daemons configured. See the \"Daemon\" config option."); + return ENOENT; + } /* create cconn array */ - memset(io_array, 0, sizeof(io_array)); - for(i = 0; i < g_num_daemons; ++i) + for (size_t i = 0; i < g_num_daemons; i++) { - io_array[i].d = g_daemons[i]; - io_array[i].request_type = request_type; - io_array[i].state = CSTATE_UNCONNECTED; + io_array[i] = (struct cconn) { + .d = g_daemons[i], + .request_type = request_type, + .state = CSTATE_UNCONNECTED, + }; } /** Calculate the time at which we should give up */ @@ -1458,13 +1498,13 @@ static int cconn_main_loop(uint32_t request_type) struct pollfd fds[g_num_daemons]; memset(fds, 0, sizeof(fds)); nfds = 0; - for(i = 0; i < g_num_daemons; ++i) + for(size_t i = 0; i < g_num_daemons; ++i) { struct cconn *io = io_array + i; ret = cconn_prepare(io, fds + nfds); if(ret < 0) { - WARNING("ceph plugin: cconn_prepare(name=%s,i=%d,st=%d)=%d", + WARNING("ceph plugin: cconn_prepare(name=%s,i=%zu,st=%d)=%d", io->d->name, i, io->state, ret); cconn_close(io); io->request_type = ASOK_REQ_NONE; @@ -1496,13 +1536,14 @@ static int cconn_main_loop(uint32_t request_type) ERROR("ceph plugin: poll(2) error: %d", ret); goto done; } - for(i = 0; i < nfds; ++i) + for(int i = 0; i < nfds; ++i) { struct cconn *io = polled_io_array[i]; int revents = fds[i].revents; if(revents == 0) { /* do nothing */ + continue; } else if(cconn_validate_revents(io, revents)) { @@ -1515,7 +1556,7 @@ static int cconn_main_loop(uint32_t request_type) } else { - int ret = cconn_handle_event(io); + ret = cconn_handle_event(io); if(ret) { WARNING("ceph plugin: cconn_handle_event(name=%s," @@ -1527,7 +1568,7 @@ static int cconn_main_loop(uint32_t request_type) } } } - done: for(i = 0; i < g_num_daemons; ++i) + done: for(size_t i = 0; i < g_num_daemons; ++i) { cconn_close(io_array + i); } @@ -1550,18 +1591,35 @@ static int ceph_read(void) /******* lifecycle *******/ static int ceph_init(void) { - int ret; +#if defined(HAVE_SYS_CAPABILITY_H) && defined(CAP_DAC_OVERRIDE) + if (check_capability (CAP_DAC_OVERRIDE) != 0) + { + if (getuid () == 0) + WARNING ("ceph plugin: Running collectd as root, but the " + "CAP_DAC_OVERRIDE capability is missing. The plugin's read " + "function will probably fail. Is your init system dropping " + "capabilities?"); + else + WARNING ("ceph plugin: collectd doesn't have the CAP_DAC_OVERRIDE " + "capability. If you don't want to run collectd as root, try running " + "\"setcap cap_dac_override=ep\" on the collectd binary."); + } +#endif + ceph_daemons_print(); - ret = cconn_main_loop(ASOK_REQ_VERSION); + if (g_num_daemons < 1) + { + ERROR ("ceph plugin: No daemons configured. See the \"Daemon\" config option."); + return ENOENT; + } - return (ret) ? ret : 0; + return cconn_main_loop(ASOK_REQ_VERSION); } static int ceph_shutdown(void) { - int i; - for(i = 0; i < g_num_daemons; ++i) + for(size_t i = 0; i < g_num_daemons; ++i) { ceph_daemon_free(g_daemons[i]); } @@ -1579,3 +1637,4 @@ void module_register(void) plugin_register_read("ceph", ceph_read); plugin_register_shutdown("ceph", ceph_shutdown); } +/* vim: set sw=4 sts=4 et : */