From 63406dc134c3aaaf4d3a3ebd09b793cc0a5efece Mon Sep 17 00:00:00 2001 From: "Costa Tsaousis (ktsaou)" Date: Sat, 4 Apr 2015 03:40:38 +0300 Subject: [PATCH] log: now is logging program name too; tc: huge optimizations; procfile: optimized initialization and added support for preventing I/O error logging - required for apps.plugin --- src/log.c | 15 +- src/log.h | 2 + src/main.c | 3 + src/plugin_tc.c | 463 ++++++++++++++++++++++++---------- src/plugins.d/apps_plugin.c | 75 +++--- src/proc_diskstats.c | 2 +- src/proc_meminfo.c | 2 +- src/proc_net_dev.c | 2 +- src/proc_net_ip_vs_stats.c | 2 +- src/proc_net_netstat.c | 2 +- src/proc_net_rpc_nfsd.c | 2 +- src/proc_net_snmp.c | 2 +- src/proc_net_stat_conntrack.c | 2 +- src/proc_stat.c | 2 +- src/proc_vmstat.c | 2 +- src/procfile.c | 70 +++-- src/procfile.h | 10 +- 17 files changed, 451 insertions(+), 207 deletions(-) diff --git a/src/log.c b/src/log.c index a2a7eb0e..f12061c8 100755 --- a/src/log.c +++ b/src/log.c @@ -10,6 +10,7 @@ // ---------------------------------------------------------------------------- // LOG +const char *program_name = ""; unsigned long long debug_flags = DEBUG; int silent = 0; @@ -43,7 +44,7 @@ void debug_int( const char *file, const char *function, const unsigned long line log_date(stdout); va_start( args, fmt ); - fprintf(stdout, "DEBUG (%04lu@%-10.10s:%-15.15s): ", line, file, function); + fprintf(stdout, "DEBUG (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name); vfprintf( stdout, fmt, args ); va_end( args ); fprintf(stdout, "\n"); @@ -62,8 +63,8 @@ void info_int( const char *file, const char *function, const unsigned long line, log_date(stderr); va_start( args, fmt ); - if(debug_flags) fprintf(stderr, "INFO (%04lu@%-10.10s:%-15.15s): ", line, file, function); - else fprintf(stderr, "INFO: "); + if(debug_flags) fprintf(stderr, "INFO (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name); + else fprintf(stderr, "INFO: %s: ", program_name); vfprintf( stderr, fmt, args ); va_end( args ); @@ -83,8 +84,8 @@ void error_int( const char *file, const char *function, const unsigned long line log_date(stderr); va_start( args, fmt ); - if(debug_flags) fprintf(stderr, "ERROR (%04lu@%-10.10s:%-15.15s): ", line, file, function); - else fprintf(stderr, "ERROR: "); + if(debug_flags) fprintf(stderr, "ERROR (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name); + else fprintf(stderr, "ERROR: %s: ", program_name); vfprintf( stderr, fmt, args ); va_end( args ); @@ -108,8 +109,8 @@ void fatal_int( const char *file, const char *function, const unsigned long line log_date(stderr); va_start( args, fmt ); - if(debug_flags) fprintf(stderr, "FATAL (%04lu@%-10.10s:%-15.15s): ", line, file, function); - else fprintf(stderr, "FATAL: "); + if(debug_flags) fprintf(stderr, "FATAL (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name); + else fprintf(stderr, "FATAL: %s: ", program_name); vfprintf( stderr, fmt, args ); va_end( args ); diff --git a/src/log.h b/src/log.h index 5c09325f..455db1d3 100755 --- a/src/log.h +++ b/src/log.h @@ -31,6 +31,8 @@ extern unsigned long long debug_flags; +extern const char *program_name; + extern int silent; extern int access_fd; diff --git a/src/main.c b/src/main.c index 1257753e..da4b7f69 100755 --- a/src/main.c +++ b/src/main.c @@ -110,6 +110,9 @@ int main(int argc, char **argv) int i; int config_loaded = 0; + // set the name for logging + program_name = "netdata"; + // parse the arguments for(i = 1; i < argc ; i++) { if(strcmp(argv[i], "-c") == 0 && (i+1) < argc) { diff --git a/src/plugin_tc.c b/src/plugin_tc.c index 018ad967..b1826c34 100755 --- a/src/plugin_tc.c +++ b/src/plugin_tc.c @@ -3,7 +3,9 @@ #include #include +#include "avl.h" #include "log.h" +#include "common.h" #include "config.h" #include "rrd.h" #include "popen.h" @@ -19,28 +21,98 @@ #define TC_LINE_MAX 1024 struct tc_class { - char id[RRD_ID_LENGTH_MAX + 1]; - char name[RRD_ID_LENGTH_MAX + 1]; + avl avl; - char leafid[RRD_ID_LENGTH_MAX + 1]; - char parentid[RRD_ID_LENGTH_MAX + 1]; + char *id; + uint32_t hash; - int hasparent; - int isleaf; + char *name; + + char *leafid; + uint32_t leaf_hash; + + char *parentid; + uint32_t parent_hash; + + char hasparent; + char isleaf; unsigned long long bytes; + char updated; + struct tc_class *next; }; struct tc_device { - char id[RRD_ID_LENGTH_MAX + 1]; - char name[RRD_ID_LENGTH_MAX + 1]; - char family[RRD_ID_LENGTH_MAX + 1]; + avl avl; + + char *id; + uint32_t hash; + + char *name; + char *family; + + avl_tree classes_index; struct tc_class *classes; }; -void tc_device_commit(struct tc_device *d) + +// ---------------------------------------------------------------------------- +// tc_device index + +static int tc_device_iterator(avl *a) { if(a) {}; return 0; } + +static int tc_device_compare(void* a, void* b) { + if(((struct tc_device *)a)->hash < ((struct tc_device *)b)->hash) return -1; + else if(((struct tc_device *)a)->hash > ((struct tc_device *)b)->hash) return 1; + else return strcmp(((struct tc_device *)a)->id, ((struct tc_device *)b)->id); +} + +avl_tree tc_device_root_index = { + NULL, + tc_device_compare +}; + +#define tc_device_index_add(st) avl_insert(&tc_device_root_index, (avl *)(st)) +#define tc_device_index_del(st) avl_remove(&tc_device_root_index, (avl *)(st)) + +static struct tc_device *tc_device_index_find(const char *id, uint32_t hash) { + struct tc_device *result = NULL, tmp; + tmp.id = (char *)id; + tmp.hash = (hash)?hash:simple_hash(tmp.id); + + avl_search(&(tc_device_root_index), (avl *)&tmp, tc_device_iterator, (avl **)&result); + return result; +} + + +// ---------------------------------------------------------------------------- +// tc_class index + +static int tc_class_iterator(avl *a) { if(a) {}; return 0; } + +static int tc_class_compare(void* a, void* b) { + if(((struct tc_class *)a)->hash < ((struct tc_class *)b)->hash) return -1; + else if(((struct tc_class *)a)->hash > ((struct tc_class *)b)->hash) return 1; + else return strcmp(((struct tc_class *)a)->id, ((struct tc_class *)b)->id); +} + +#define tc_class_index_add(st, rd) avl_insert(&((st)->classes_index), (avl *)(rd)) +#define tc_class_index_del(st, rd) avl_remove(&((st)->classes_index), (avl *)(rd)) + +static struct tc_class *tc_class_index_find(struct tc_device *st, const char *id, uint32_t hash) { + struct tc_class *result = NULL, tmp; + tmp.id = (char *)id; + tmp.hash = (hash)?hash:simple_hash(tmp.id); + + avl_search(&(st->classes_index), (avl *)&tmp, tc_class_iterator, (avl **)&result); + return result; +} + +// ---------------------------------------------------------------------------- + +static void tc_device_commit(struct tc_device *d) { static int enable_new_interfaces = -1; @@ -49,12 +121,22 @@ void tc_device_commit(struct tc_device *d) // we only need to add leaf classes struct tc_class *c, *x; - for ( c = d->classes ; c ; c = c->next) + // set them all as leafs without parent + for(c = d->classes ; c ; c = c->next) { c->isleaf = 1; + c->hasparent = 0; + } - for ( c = d->classes ; c ; c = c->next) { - for ( x = d->classes ; x ; x = x->next) { - if(x->parentid[0] && (strcmp(c->id, x->parentid) == 0 || strcmp(c->leafid, x->parentid) == 0)) { + // mark the classes as leafs and parents + for(c = d->classes ; c ; c = c->next) { + if(!c->updated) continue; + + for(x = d->classes ; x ; x = x->next) { + if(!x->updated) continue; + + if(x->parentid && ( + ( c->hash == x->parent_hash && strcmp(c->id, x->parentid) == 0) || + (c->leafid && c->leaf_hash == x->parent_hash && strcmp(c->leafid, x->parentid) == 0))) { // debug(D_TC_LOOP, "TC: In device '%s', class '%s' (leafid: '%s') has leaf the class '%s' (parentid: '%s').", d->name, c->name, c->leafid, x->name, x->parentid); c->isleaf = 0; x->hasparent = 1; @@ -70,134 +152,229 @@ void tc_device_commit(struct tc_device *d) } */ - for ( c = d->classes ; c ; c = c->next) { + // we need a device + for(c = d->classes ; c ; c = c->next) { + if(!c->updated) continue; if(c->isleaf && c->hasparent) break; } if(!c) { - debug(D_TC_LOOP, "TC: Ignoring TC device '%s'. No leaf classes.", d->name); + debug(D_TC_LOOP, "TC: Ignoring TC device '%s'. No leaf classes.", d->name?d->name:d->id); return; } - char var_name[4096 + 1]; - snprintf(var_name, 4096, "qos for %s", d->id); + char var_name[CONFIG_MAX_NAME + 1]; + snprintf(var_name, CONFIG_MAX_NAME, "qos for %s", d->id); if(config_get_boolean("plugin:tc", var_name, enable_new_interfaces)) { RRDSET *st = rrdset_find_bytype(RRD_TYPE_TC, d->id); if(!st) { - debug(D_TC_LOOP, "TC: Committing new TC device '%s'", d->name); + debug(D_TC_LOOP, "TC: Committing new TC device '%s'", d->name?d->name:d->id); + + st = rrdset_create(RRD_TYPE_TC, d->id, d->name?d->name:d->id, d->family?d->family:d->id, "Class Usage", "kilobits/s", 1000, rrd_update_every, RRDSET_TYPE_STACKED); - st = rrdset_create(RRD_TYPE_TC, d->id, d->name, d->family, "Class Usage", "kilobits/s", 1000, rrd_update_every, RRDSET_TYPE_STACKED); + for(c = d->classes ; c ; c = c->next) { + if(!c->updated) continue; - for ( c = d->classes ; c ; c = c->next) { if(c->isleaf && c->hasparent) - rrddim_add(st, c->id, c->name, 8, 1024 * rrd_update_every, RRDDIM_INCREMENTAL); + rrddim_add(st, c->id, c->name?c->name:c->id, 8, 1024 * rrd_update_every, RRDDIM_INCREMENTAL); } } else { rrdset_next_plugins(st); - if(strcmp(d->id, d->name) != 0) rrdset_set_name(st, d->name); + if(d->name && strcmp(d->id, d->name) != 0) rrdset_set_name(st, d->name); } - for ( c = d->classes ; c ; c = c->next) { + for(c = d->classes ; c ; c = c->next) { + if(!c->updated) continue; + if(c->isleaf && c->hasparent) { if(rrddim_set(st, c->id, c->bytes) != 0) { // new class, we have to add it - rrddim_add(st, c->id, c->name, 8, 1024 * rrd_update_every, RRDDIM_INCREMENTAL); + rrddim_add(st, c->id, c->name?c->name:c->id, 8, 1024 * rrd_update_every, RRDDIM_INCREMENTAL); rrddim_set(st, c->id, c->bytes); } // if it has a name, different to the id - if(strcmp(c->id, c->name) != 0) { + if(c->name) { // update the rrd dimension with the new name - RRDDIM *rd; - for(rd = st->dimensions ; rd ; rd = rd->next) { - if(strcmp(rd->id, c->id) == 0) { rrddim_set_name(st, rd, c->name); break; } - } + RRDDIM *rd = rrddim_find(st, c->id); + if(rd) rrddim_set_name(st, rd, c->name); + + free(c->name); + c->name = NULL; } } + + c->updated = 0; } rrdset_done(st); } } -void tc_device_set_class_name(struct tc_device *d, char *id, char *name) +static void tc_device_set_class_name(struct tc_device *d, char *id, char *name) { - struct tc_class *c; - for ( c = d->classes ; c ; c = c->next) { - if(strcmp(c->id, id) == 0) { - strncpy(c->name, name, RRD_ID_LENGTH_MAX); - // no need for null termination - it is already null - break; - } + struct tc_class *c = tc_class_index_find(d, id, 0); + if(c) { + if(c->name) free(c->name); + c->name = NULL; + + if(name && *name && strcmp(c->id, name) != 0) c->name = strdup(name); } } -void tc_device_set_device_name(struct tc_device *d, char *name) -{ - strncpy(d->name, name, RRD_ID_LENGTH_MAX); - // no need for null termination - it is already null +static void tc_device_set_device_name(struct tc_device *d, char *name) { + if(d->name) free(d->name); + d->name = NULL; + + if(name && *name && strcmp(d->id, name) != 0) d->name = strdup(name); } -void tc_device_set_device_family(struct tc_device *d, char *name) -{ - strncpy(d->family, name, RRD_ID_LENGTH_MAX); +static void tc_device_set_device_family(struct tc_device *d, char *family) { + if(d->family) free(d->family); + d->family = NULL; + + if(family && *family && strcmp(d->id, family) != 0) d->family = strdup(family); // no need for null termination - it is already null } -struct tc_device *tc_device_create(char *name) +static struct tc_device *tc_device_create(char *id) { - struct tc_device *d; + struct tc_device *d = tc_device_index_find(id, 0); - d = calloc(1, sizeof(struct tc_device)); if(!d) { - fatal("Cannot allocate memory for tc_device %s", name); - return NULL; - } - strncpy(d->id, name, RRD_ID_LENGTH_MAX); - strcpy(d->name, d->id); - strcpy(d->family, d->id); + d = calloc(1, sizeof(struct tc_device)); + if(!d) { + fatal("Cannot allocate memory for tc_device %s", id); + return NULL; + } + + d->id = strdup(id); + d->hash = simple_hash(d->id); - // no need for null termination on the strings, because of calloc() + d->classes_index.root = NULL; + d->classes_index.compar = tc_class_compare; + + tc_device_index_add(d); + } return(d); } -struct tc_class *tc_class_add(struct tc_device *n, char *id, char *parentid, char *leafid) +static struct tc_class *tc_class_add(struct tc_device *n, char *id, char *parentid, char *leafid) { - struct tc_class *c; + // fprintf(stderr, "Adding class id '%s', parentid '%s', leafid '%s'\n", id, parentid, leafid); - c = calloc(1, sizeof(struct tc_class)); + struct tc_class *c = tc_class_index_find(n, id, 0); if(!c) { - fatal("Cannot allocate memory for tc class"); - return NULL; - } + c = calloc(1, sizeof(struct tc_class)); + if(!c) { + fatal("Cannot allocate memory for tc class"); + return NULL; + } + + c->next = n->classes; + n->classes = c; + + c->id = strdup(id); + if(!c->id) { + free(c); + return NULL; + } + c->hash = simple_hash(c->id); - c->next = n->classes; - n->classes = c; + if(parentid && *parentid) { + c->parentid = strdup(parentid); + c->parent_hash = simple_hash(c->parentid); + } - strncpy(c->id, id, RRD_ID_LENGTH_MAX); - strcpy(c->name, c->id); - if(parentid) strncpy(c->parentid, parentid, RRD_ID_LENGTH_MAX); - if(leafid) strncpy(c->leafid, leafid, RRD_ID_LENGTH_MAX); + if(leafid && *leafid) { + c->leafid = strdup(leafid); + c->leaf_hash = simple_hash(c->leafid); + } - // no need for null termination on the strings, because of calloc() + tc_class_index_add(n, c); + } return(c); } - -void tc_class_free(struct tc_class *c) +/* +static void tc_class_free_all(struct tc_device *n, struct tc_class *c) { - if(c->next) tc_class_free(c->next); + if(c->next) tc_class_free_all(n, c->next); + tc_class_index_del(n, c); + + if(c->id) free(c->id); + if(c->name) free(c->name); + if(c->leafid) free(c->leafid); + if(c->parentid) free(c->parentid); + free(c); } -void tc_device_free(struct tc_device *n) +static void tc_device_free(struct tc_device *n) { - if(n->classes) tc_class_free(n->classes); + tc_device_index_del(n); + if(n->classes) tc_class_free_all(n, n->classes); + + if(n->id) free(n->id); + if(n->name) free(n->name); + if(n->family) free(n->family); + free(n); } +*/ + +#define MAX_WORDS 20 + +int tc_space(char c) { + switch(c) { + case ' ': + case '\t': + case '\r': + case '\n': + return 1; + + default: + return 0; + } +} + +void tc_split_words(char *str, char **words, int max_words) { + char *s = str; + int i = 0; + + // skip all white space + while(tc_space(*s)) s++; + + // store the first word + words[i++] = s; + + // while we have something + while(*s) { + // if it is a space + if(tc_space(*s)) { + + // terminate the word + *s++ = '\0'; + + // skip all white space + while(tc_space(*s)) s++; + + // if we reached the end, stop + if(!*s) break; + + // store the next word + if(i < max_words) words[i++] = s; + else break; + } + else s++; + } + + // terminate the words + while(i < max_words) words[i++] = NULL; +} pid_t tc_child_pid = 0; void *tc_main(void *ptr) @@ -211,6 +388,19 @@ void *tc_main(void *ptr) error("Cannot set pthread cancel state to ENABLE."); char buffer[TC_LINE_MAX+1] = ""; + char *words[MAX_WORDS] = { NULL }; + + uint32_t BEGIN_HASH = simple_hash("BEGIN"); + uint32_t END_HASH = simple_hash("END"); + uint32_t CLASS_HASH = simple_hash("class"); + uint32_t SENT_HASH = simple_hash("Sent"); + uint32_t SETDEVICENAME_HASH = simple_hash("SETDEVICENAME"); + uint32_t SETDEVICEGROUP_HASH = simple_hash("SETDEVICEGROUP"); + uint32_t SETCLASSNAME_HASH = simple_hash("SETCLASSNAME"); +#ifdef DETACH_PLUGINS_FROM_NETDATA + uint32_t MYPID_HASH = simple_hash("MYPID"); +#endif + uint32_t first_hash; for(;1;) { FILE *fp; @@ -228,20 +418,54 @@ void *tc_main(void *ptr) while(fgets(buffer, TC_LINE_MAX, fp) != NULL) { buffer[TC_LINE_MAX] = '\0'; - char *b = buffer, *p; // debug(D_TC_LOOP, "TC: read '%s'", buffer); - p = strsep(&b, " \n"); - while (p && (*p == ' ' || *p == '\0')) p = strsep(&b, " \n"); - if(!p) continue; + tc_split_words(buffer, words, MAX_WORDS); + if(!words[0] || !*words[0]) { + // debug(D_TC_LOOP, "empty line"); + continue; + } + // else debug(D_TC_LOOP, "First word is '%s'", words[0]); + + first_hash = simple_hash(words[0]); + + if(first_hash == CLASS_HASH && strcmp(words[0], "class") == 0 && device) { + // debug(D_TC_LOOP, "CLASS line on class id='%s', parent='%s', parentid='%s', leaf='%s', leafid='%s'", words[2], words[3], words[4], words[5], words[6]); + + if(words[1] && words[2] && words[3] && words[4] && (strcmp(words[3], "parent") == 0 || strcmp(words[3], "root") == 0)) { + // char *type = words[1]; // the class: htb, fq_codel, etc + char *id = words[2]; // the class major:minor + char *parent = words[3]; // 'parent' or 'root' + char *parentid = words[4]; // the parent's id + char *leaf = words[5]; // 'leaf' + char *leafid = words[6]; // leafid + + if(strcmp(parent, "root") == 0) { + parentid = NULL; + leafid = NULL; + } + else if(!leaf || strcmp(leaf, "leaf") != 0) + leafid = NULL; + + char leafbuf[20 + 1] = ""; + if(leafid && leafid[strlen(leafid) - 1] == ':') { + strncpy(leafbuf, leafid, 20 - 1); + strcat(leafbuf, "1"); + leafid = leafbuf; + } + + class = tc_class_add(device, id, parentid, leafid); + } + } + else if(first_hash == END_HASH && strcmp(words[0], "END") == 0) { + // debug(D_TC_LOOP, "END line"); - if(strcmp(p, "END") == 0) { if(device) { if(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL) != 0) error("Cannot set pthread cancel state to DISABLE."); tc_device_commit(device); - tc_device_free(device); + // tc_device_free(device); device = NULL; class = NULL; @@ -249,72 +473,46 @@ void *tc_main(void *ptr) error("Cannot set pthread cancel state to ENABLE."); } } - else if(strcmp(p, "BEGIN") == 0) { + else if(first_hash == BEGIN_HASH && strcmp(words[0], "BEGIN") == 0) { + // debug(D_TC_LOOP, "BEGIN line on device '%s'", words[1]); + if(device) { - tc_device_free(device); + // tc_device_free(device); device = NULL; class = NULL; } - p = strsep(&b, " \n"); - if(p && *p) { - device = tc_device_create(p); + if(words[1] && *words[1]) { + device = tc_device_create(words[1]); class = NULL; } } - else if(device && (strcmp(p, "class") == 0)) { - p = strsep(&b, " \n"); // the class: htb, fq_codel, etc - char *id = strsep(&b, " \n"); // the class major:minor - char *parent = strsep(&b, " \n"); // 'parent' or 'root' - char *parentid = strsep(&b, " \n"); // the parent's id - char *leaf = strsep(&b, " \n"); // 'leaf' - char *leafid = strsep(&b, " \n"); // leafid - - if(id && *id - && parent && *parent - && parentid && *parentid - && ( - (strcmp(parent, "parent") == 0 && parentid && *parentid) - || strcmp(parent, "root") == 0 - )) { - - if(strcmp(parent, "root") == 0) { - parentid = NULL; - leafid = NULL; - } - else if(!leaf || strcmp(leaf, "leaf") != 0) - leafid = NULL; - - char leafbuf[20 + 1] = ""; - if(leafid && leafid[strlen(leafid) - 1] == ':') { - strncpy(leafbuf, leafid, 20 - 1); - strcat(leafbuf, "1"); - leafid = leafbuf; - } - - class = tc_class_add(device, id, parentid, leafid); + else if(first_hash == SENT_HASH && strcmp(words[0], "Sent") == 0 && device && class) { + // debug(D_TC_LOOP, "SENT line '%s'", words[1]); + if(words[1] && *words[1]) { + class->bytes = atoll(words[1]); + class->updated = 1; } + else class->bytes = 0; } - else if(device && class && (strcmp(p, "Sent") == 0)) { - p = strsep(&b, " \n"); - if(p && *p) class->bytes = atoll(p); - } - else if(device && (strcmp(p, "SETDEVICENAME") == 0)) { - char *name = strsep(&b, " \n"); - if(name && *name) tc_device_set_device_name(device, name); + else if(first_hash == SETDEVICENAME_HASH && strcmp(words[0], "SETDEVICENAME") == 0 && device) { + // debug(D_TC_LOOP, "SETDEVICENAME line '%s'", words[1]); + if(words[1] && *words[1]) tc_device_set_device_name(device, words[1]); } - else if(device && (strcmp(p, "SETDEVICEGROUP") == 0)) { - char *name = strsep(&b, " \n"); - if(name && *name) tc_device_set_device_family(device, name); + else if(first_hash == SETDEVICEGROUP_HASH && strcmp(words[0], "SETDEVICEGROUP") == 0 && device) { + // debug(D_TC_LOOP, "SETDEVICEGROUP line '%s'", words[1]); + if(words[1] && *words[1]) tc_device_set_device_family(device, words[1]); } - else if(device && (strcmp(p, "SETCLASSNAME") == 0)) { - char *id = strsep(&b, " \n"); - char *path = strsep(&b, " \n"); + else if(first_hash == SETCLASSNAME_HASH && strcmp(words[0], "SETCLASSNAME") == 0 && device) { + // debug(D_TC_LOOP, "SETCLASSNAME line '%s' '%s'", words[1], words[2]); + char *id = words[1]; + char *path = words[2]; if(id && *id && path && *path) tc_device_set_class_name(device, id, path); } #ifdef DETACH_PLUGINS_FROM_NETDATA - else if((strcmp(p, "MYPID") == 0)) { - char *id = strsep(&b, " \n"); + else if(first_hash == MYPID_HASH && (strcmp(words[0], "MYPID") == 0)) { + // debug(D_TC_LOOP, "MYPID line '%s'", words[1]); + char *id = words[1]; pid_t pid = atol(id); if(pid) tc_child_pid = pid; @@ -322,11 +520,14 @@ void *tc_main(void *ptr) debug(D_TC_LOOP, "TC: Child PID is %d.", tc_child_pid); } #endif + //else { + // debug(D_TC_LOOP, "IGNORED line"); + //} } mypclose(fp); if(device) { - tc_device_free(device); + // tc_device_free(device); device = NULL; class = NULL; } diff --git a/src/plugins.d/apps_plugin.c b/src/plugins.d/apps_plugin.c index 49aa4ed7..bd320865 100755 --- a/src/plugins.d/apps_plugin.c +++ b/src/plugins.d/apps_plugin.c @@ -202,7 +202,7 @@ procfile *ff = NULL; long get_processors(void) { int processors = 0; - ff = procfile_reopen(ff, "/proc/stat", ""); + ff = procfile_reopen(ff, "/proc/stat", "", PROCFILE_FLAG_DEFAULT); if(!ff) return 1; ff = procfile_readall(ff); @@ -227,7 +227,7 @@ long get_processors(void) { long get_pid_max(void) { long mpid = 32768; - ff = procfile_reopen(ff, "/proc/sys/kernel/pid_max", ""); + ff = procfile_reopen(ff, "/proc/sys/kernel/pid_max", "", PROCFILE_FLAG_DEFAULT); if(!ff) return mpid; ff = procfile_readall(ff); @@ -260,7 +260,7 @@ unsigned long long get_hertz(void) hz = (sizeof(long)==sizeof(int) || htons(999)==999) ? 100UL : 1024UL; #endif - error("apps.plugin: ERROR: unknown HZ value. Assuming %llu.", hz); + error("Unknown HZ value. Assuming %llu.", hz); return hz; } @@ -353,7 +353,7 @@ struct target *get_target(const char *id, struct target *target) w = calloc(sizeof(struct target), 1); if(!w) { - error("apps.plugin: cannot allocate %lu bytes of memory", (unsigned long)sizeof(struct target)); + error("Cannot allocate %lu bytes of memory", (unsigned long)sizeof(struct target)); return NULL; } @@ -383,7 +383,7 @@ int read_process_groups(const char *name) if(debug) fprintf(stderr, "apps.plugin: process groups file: '%s'\n", filename); FILE *fp = fopen(filename, "r"); if(!fp) { - error("apps.plugin: ERROR: cannot open file '%s' (%s)", filename, strerror(errno)); + error("Cannot open file '%s' (%s)", filename, strerror(errno)); return 1; } @@ -444,7 +444,7 @@ int read_process_groups(const char *name) } if(w) strncpy(w->name, t, MAX_NAME); - if(!count) error("apps.plugin: ERROR: the line %ld on file '%s', for group '%s' does not state any process names.", line, filename, t); + if(!count) error("The line %ld on file '%s', for group '%s' does not state any process names.", line, filename, t); } fclose(fp); @@ -567,13 +567,13 @@ struct pid_stat *get_pid_entry(pid_t pid) all_pids[pid] = calloc(sizeof(struct pid_stat), 1); if(!all_pids[pid]) { - error("apps.plugin: ERROR: Cannot allocate %lu bytes of memory", (unsigned long)sizeof(struct pid_stat)); + error("Cannot allocate %lu bytes of memory", (unsigned long)sizeof(struct pid_stat)); return NULL; } all_pids[pid]->fds = calloc(sizeof(int), 100); if(!all_pids[pid]->fds) - error("apps.plugin: ERROR: Cannot allocate %ld bytes of memory", (unsigned long)(sizeof(int) * 100)); + error("Cannot allocate %ld bytes of memory", (unsigned long)(sizeof(int) * 100)); else all_pids[pid]->fds_size = 100; if(root_of_pids) root_of_pids->prev = all_pids[pid]; @@ -610,7 +610,7 @@ int read_proc_pid_stat(struct pid_stat *p) { snprintf(filename, FILENAME_MAX, "/proc/%d/stat", p->pid); - ff = procfile_reopen(ff, filename, ""); + ff = procfile_reopen(ff, filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO); if(!ff) return 1; ff = procfile_readall(ff); @@ -699,7 +699,7 @@ int read_proc_pid_statm(struct pid_stat *p) { snprintf(filename, FILENAME_MAX, "/proc/%d/statm", p->pid); - ff = procfile_reopen(ff, filename, ""); + ff = procfile_reopen(ff, filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO); if(!ff) return 1; ff = procfile_readall(ff); @@ -727,7 +727,7 @@ int read_proc_pid_io(struct pid_stat *p) { snprintf(filename, FILENAME_MAX, "/proc/%d/io", p->pid); - ff = procfile_reopen(ff, filename, ""); + ff = procfile_reopen(ff, filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO); if(!ff) return 1; ff = procfile_readall(ff); @@ -875,9 +875,9 @@ void file_descriptor_not_used(int id) } } else - error("apps.plugin: ERROR: request to decrease counter of fd %d (%s), while the use counter is 0", id, all_files[id].name); + error("Request to decrease counter of fd %d (%s), while the use counter is 0", id, all_files[id].name); } - else error("apps.plugin: ERROR: request to decrease counter of fd %d, which is outside the array size (1 to %d)", id, all_files_size); + else error("Request to decrease counter of fd %d, which is outside the array size (1 to %d)", id, all_files_size); } unsigned long file_descriptor_find_or_add(const char *name) @@ -940,7 +940,7 @@ unsigned long file_descriptor_find_or_add(const char *name) if(debug) fprintf(stderr, "apps.plugin: >> Examining slot %d.\n", c); if(all_files[c].magic == 0x0BADCAFE && all_files[c].name && file_descriptor_find(all_files[c].name, all_files[c].hash)) - error("apps.plugin: fd on position %d is not cleared properly. It still has %s in it.\n", c, all_files[c].name); + error("fd on position %d is not cleared properly. It still has %s in it.\n", c, all_files[c].name); if(debug) fprintf(stderr, "apps.plugin: >> %s fd position %d for %s (last name: %s)\n", all_files[c].name?"re-using":"using", c, name, all_files[c].name); if(all_files[c].name) free((void *)all_files[c].name); @@ -1042,7 +1042,9 @@ int update_from_proc(void) // /proc//stat if(read_proc_pid_stat(p)) { - error("Cannot process /proc/%d/stat", pid); + if(!count_errors++ || debug || (p->target && p->target->debug)) + error("Cannot process /proc/%d/stat", pid); + continue; } if(p->ppid < 0 || p->ppid > pid_max) p->ppid = 0; @@ -1052,7 +1054,9 @@ int update_from_proc(void) // /proc//statm if(read_proc_pid_statm(p)) { - error("Cannot process /proc/%d/statm", pid); + if(!count_errors++ || debug || (p->target && p->target->debug)) + error("Cannot process /proc/%d/statm", pid); + continue; } @@ -1061,7 +1065,9 @@ int update_from_proc(void) // /proc//io if(read_proc_pid_io(p)) { - error("Cannot process /proc/%d/io", pid); + if(!count_errors++ || debug || (p->target && p->target->debug)) + error("Cannot process /proc/%d/io", pid); + continue; } @@ -1111,7 +1117,7 @@ int update_from_proc(void) if(debug) fprintf(stderr, "apps.plugin: extending fd memory slots for %s from %d to %d\n", p->comm, p->fds_size, fdid + 100); p->fds = realloc(p->fds, (fdid + 100) * sizeof(int)); if(!p->fds) { - error("apps.plugin: ERROR: cannot re-allocate fds for %s", p->comm); + error("Cannot re-allocate fds for %s", p->comm); break; } @@ -1128,7 +1134,7 @@ int update_from_proc(void) if(l == -1) { if(debug || (p->target && p->target->debug)) { if(!count_errors++ || debug || (p->target && p->target->debug)) - error("apps.plugin: ERROR: cannot read link %s", fdname); + error("Cannot read link %s", fdname); } continue; } @@ -1161,7 +1167,7 @@ int update_from_proc(void) p->updated = 1; } if(count_errors > 1000) { - error("apps.plugin: ERROR: %ld more errors encountered\n", count_errors - 1); + error("%ld more errors encountered\n", count_errors - 1); count_errors = 0; } @@ -1199,7 +1205,7 @@ void update_statistics(void) p->parent = all_pids[p->ppid]; p->parent->childs++; } - else if(p->ppid != 0) error("apps.plugin: \t\tWRONG! pid %d %s states parent %d, but the later does not exist.", p->pid, p->comm, p->ppid); + else if(p->ppid != 0) error("pid %d %s states parent %d, but the later does not exist.", p->pid, p->comm, p->ppid); } // find all the procs with 0 childs and merge them to their parents @@ -1309,10 +1315,10 @@ void update_statistics(void) } } - if(diff_utime) error("apps.plugin: \t cannot fix up utime %llu", diff_utime); - if(diff_stime) error("apps.plugin: \t cannot fix up stime %llu", diff_stime); - if(diff_minflt) error("apps.plugin: \t cannot fix up minflt %llu", diff_minflt); - if(diff_majflt) error("apps.plugin: \t cannot fix up majflt %llu", diff_majflt); + if(diff_utime) error("Cannot fix up utime %llu", diff_utime); + if(diff_stime) error("Cannot fix up stime %llu", diff_stime); + if(diff_minflt) error("Cannot fix up minflt %llu", diff_minflt); + if(diff_majflt) error("Cannot fix up majflt %llu", diff_majflt); } #endif @@ -1324,7 +1330,7 @@ void update_statistics(void) w->fds = calloc(sizeof(int), all_files_size); if(!w->fds) - error("apps.plugin: ERROR: cannot allocate memory for fds in %s", w->name); + error("Cannot allocate memory for fds in %s", w->name); w->minflt = 0; w->majflt = 0; @@ -1362,7 +1368,7 @@ void update_statistics(void) // concentrate everything on the targets for(p = root_of_pids; p ; p = p->next) { if(!p->target) { - error("apps.plugin: ERROR: pid %d %s was left without a target!", p->pid, p->comm); + error("pid %d %s was left without a target!", p->pid, p->comm); continue; } @@ -1410,7 +1416,7 @@ void update_statistics(void) if(p->target->fds) p->target->fds[p->fds[c]]++; } else - error("apps.plugin: ERROR: invalid fd number %d", p->fds[c]); + error("Invalid fd number %d", p->fds[c]); } if(debug || p->target->debug) fprintf(stderr, "apps.plugin: \tAgregating %s pid %d on %s utime=%llu, stime=%llu, cutime=%llu, cstime=%llu, minflt=%llu, majflt=%llu, cminflt=%llu, cmajflt=%llu\n", p->comm, p->pid, p->target->name, p->utime, p->stime, p->cutime, p->cstime, p->minflt, p->majflt, p->cminflt, p->cmajflt); @@ -1876,7 +1882,7 @@ void parse_args(int argc, char **argv) continue; } - error("apps.plugin: ERROR: cannot understand option %s", argv[i]); + error("Cannot understand option %s", argv[i]); exit(1); } @@ -1884,7 +1890,7 @@ void parse_args(int argc, char **argv) if(!name) name = "groups"; if(read_process_groups(name)) { - error("apps.plugin: ERROR: cannot read process groups %s", name); + error("Cannot read process groups %s", name); exit(1); } } @@ -1893,7 +1899,10 @@ int main(int argc, char **argv) { // debug_flags = D_PROCFILE; - info("apps.plugin: starting..."); + // set the name for logging + program_name = "apps.plugin"; + + info("starting..."); procfile_adaptive_initial_allocation = 1; @@ -1906,7 +1915,7 @@ int main(int argc, char **argv) all_pids = calloc(sizeof(struct pid_stat *), pid_max); if(!all_pids) { - error("apps.plugin: ERROR: cannot allocate %lu bytes of memory.", sizeof(struct pid_stat *) * pid_max); + error("Cannot allocate %lu bytes of memory.", sizeof(struct pid_stat *) * pid_max); printf("DISABLE\n"); exit(1); } @@ -1918,7 +1927,7 @@ int main(int argc, char **argv) for(;1; counter++) { if(!update_from_proc()) { - error("apps.plugin: ERROR: cannot allocate %lu bytes of memory.", sizeof(struct pid_stat *) * pid_max); + error("Cannot allocate %lu bytes of memory.", sizeof(struct pid_stat *) * pid_max); printf("DISABLE\n"); exit(1); } diff --git a/src/proc_diskstats.c b/src/proc_diskstats.c index d29e4973..e2bb72bc 100755 --- a/src/proc_diskstats.c +++ b/src/proc_diskstats.c @@ -30,7 +30,7 @@ int do_proc_diskstats(int update_every, unsigned long long dt) { if(dt) {}; - if(!ff) ff = procfile_open("/proc/diskstats", " \t"); + if(!ff) ff = procfile_open("/proc/diskstats", " \t", PROCFILE_FLAG_DEFAULT); if(!ff) return 1; ff = procfile_readall(ff); diff --git a/src/proc_meminfo.c b/src/proc_meminfo.c index 75c30144..010767cf 100755 --- a/src/proc_meminfo.c +++ b/src/proc_meminfo.c @@ -27,7 +27,7 @@ int do_proc_meminfo(int update_every, unsigned long long dt) { if(dt) {}; - if(!ff) ff = procfile_open("/proc/meminfo", " \t:"); + if(!ff) ff = procfile_open("/proc/meminfo", " \t:", PROCFILE_FLAG_DEFAULT); if(!ff) return 1; ff = procfile_readall(ff); diff --git a/src/proc_net_dev.c b/src/proc_net_dev.c index 92f3e008..62837a91 100755 --- a/src/proc_net_dev.c +++ b/src/proc_net_dev.c @@ -14,7 +14,7 @@ int do_proc_net_dev(int update_every, unsigned long long dt) { if(dt) {}; - if(!ff) ff = procfile_open("/proc/net/dev", " \t,:|"); + if(!ff) ff = procfile_open("/proc/net/dev", " \t,:|", PROCFILE_FLAG_DEFAULT); if(!ff) return 1; ff = procfile_readall(ff); diff --git a/src/proc_net_ip_vs_stats.c b/src/proc_net_ip_vs_stats.c index d24b1df5..6b5cd6f6 100755 --- a/src/proc_net_ip_vs_stats.c +++ b/src/proc_net_ip_vs_stats.c @@ -20,7 +20,7 @@ int do_proc_net_ip_vs_stats(int update_every, unsigned long long dt) { if(dt) {}; - if(!ff) ff = procfile_open("/proc/net/ip_vs_stats", " \t,:|"); + if(!ff) ff = procfile_open("/proc/net/ip_vs_stats", " \t,:|", PROCFILE_FLAG_DEFAULT); if(!ff) return 1; ff = procfile_readall(ff); diff --git a/src/proc_net_netstat.c b/src/proc_net_netstat.c index 7615871f..5f91e7bb 100755 --- a/src/proc_net_netstat.c +++ b/src/proc_net_netstat.c @@ -22,7 +22,7 @@ int do_proc_net_netstat(int update_every, unsigned long long dt) { if(dt) {}; - if(!ff) ff = procfile_open("/proc/net/netstat", " \t:"); + if(!ff) ff = procfile_open("/proc/net/netstat", " \t:", PROCFILE_FLAG_DEFAULT); if(!ff) return 1; ff = procfile_readall(ff); diff --git a/src/proc_net_rpc_nfsd.c b/src/proc_net_rpc_nfsd.c index 634558d6..99ac0b10 100644 --- a/src/proc_net_rpc_nfsd.c +++ b/src/proc_net_rpc_nfsd.c @@ -137,7 +137,7 @@ int do_proc_net_rpc_nfsd(int update_every, unsigned long long dt) { if(dt) {}; - if(!ff) ff = procfile_open("/proc/net/rpc/nfsd", " \t"); + if(!ff) ff = procfile_open("/proc/net/rpc/nfsd", " \t", PROCFILE_FLAG_DEFAULT); if(!ff) return 1; ff = procfile_readall(ff); diff --git a/src/proc_net_snmp.c b/src/proc_net_snmp.c index 101b0582..82f2c801 100755 --- a/src/proc_net_snmp.c +++ b/src/proc_net_snmp.c @@ -31,7 +31,7 @@ int do_proc_net_snmp(int update_every, unsigned long long dt) { if(dt) {}; - if(!ff) ff = procfile_open("/proc/net/snmp", " \t:"); + if(!ff) ff = procfile_open("/proc/net/snmp", " \t:", PROCFILE_FLAG_DEFAULT); if(!ff) return 1; ff = procfile_readall(ff); diff --git a/src/proc_net_stat_conntrack.c b/src/proc_net_stat_conntrack.c index e70feef0..ebb2350b 100755 --- a/src/proc_net_stat_conntrack.c +++ b/src/proc_net_stat_conntrack.c @@ -25,7 +25,7 @@ int do_proc_net_stat_conntrack(int update_every, unsigned long long dt) { if(dt) {}; - if(!ff) ff = procfile_open("/proc/net/stat/nf_conntrack", " \t:"); + if(!ff) ff = procfile_open("/proc/net/stat/nf_conntrack", " \t:", PROCFILE_FLAG_DEFAULT); if(!ff) return 1; ff = procfile_readall(ff); diff --git a/src/proc_stat.c b/src/proc_stat.c index 4bbe4a11..a24eef24 100755 --- a/src/proc_stat.c +++ b/src/proc_stat.c @@ -25,7 +25,7 @@ int do_proc_stat(int update_every, unsigned long long dt) { if(dt) {}; - if(!ff) ff = procfile_open("/proc/stat", " \t:"); + if(!ff) ff = procfile_open("/proc/stat", " \t:", PROCFILE_FLAG_DEFAULT); if(!ff) return 1; ff = procfile_readall(ff); diff --git a/src/proc_vmstat.c b/src/proc_vmstat.c index 61c04387..7c2476ec 100755 --- a/src/proc_vmstat.c +++ b/src/proc_vmstat.c @@ -23,7 +23,7 @@ int do_proc_vmstat(int update_every, unsigned long long dt) { if(dt) {}; - if(!ff) ff = procfile_open("/proc/vmstat", " \t:"); + if(!ff) ff = procfile_open("/proc/vmstat", " \t:", PROCFILE_FLAG_DEFAULT); if(!ff) return 1; ff = procfile_readall(ff); diff --git a/src/procfile.c b/src/procfile.c index 780cd733..101da83d 100755 --- a/src/procfile.c +++ b/src/procfile.c @@ -136,9 +136,9 @@ void pflines_free(pflines *fl) { // ---------------------------------------------------------------------------- // The procfile -#define PF_CHAR_IS_SEPARATOR 0 -#define PF_CHAR_IS_NEWLINE 1 -#define PF_CHAR_IS_WORD 2 +#define PF_CHAR_IS_SEPARATOR ' ' +#define PF_CHAR_IS_NEWLINE 'N' +#define PF_CHAR_IS_WORD 'W' void procfile_close(procfile *ff) { debug(D_PROCFILE, PF_PREFIX ": Closing file '%s'", ff->filename); @@ -224,7 +224,7 @@ procfile *procfile_parser(procfile *ff) { return ff; cleanup: - error(PF_PREFIX ": Failed to parse file '%s'. Reason: %s", ff->filename, strerror(errno)); + error(PF_PREFIX ": Failed to parse file '%s'", ff->filename); procfile_close(ff); return NULL; } @@ -241,7 +241,7 @@ procfile *procfile_readall(procfile *ff) { procfile *new = realloc(ff, sizeof(procfile) + ff->size + PROCFILE_INCREMENT_BUFFER); if(!new) { - error(PF_PREFIX ": Cannot allocate memory for file '%s'. Reason: %s", ff->filename, strerror(errno)); + error(PF_PREFIX ": Cannot allocate memory for file '%s'", ff->filename); procfile_close(ff); return NULL; } @@ -253,7 +253,7 @@ procfile *procfile_readall(procfile *ff) { debug(D_PROCFILE, "Reading file '%s', from position %ld with length %ld", ff->filename, s, ff->size - s); r = read(ff->fd, &ff->data[s], ff->size - s); if(r == -1) { - error(PF_PREFIX ": Cannot read from file '%s'. Reason: %s", ff->filename, strerror(errno)); + if(!(ff->flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO)) error(PF_PREFIX ": Cannot read from file '%s'", ff->filename); procfile_close(ff); return NULL; } @@ -264,7 +264,7 @@ procfile *procfile_readall(procfile *ff) { debug(D_PROCFILE, "Rewinding file '%s'", ff->filename); if(lseek(ff->fd, 0, SEEK_SET) == -1) { - error(PF_PREFIX ": Cannot rewind on file '%s'.", ff->filename); + if(!(ff->flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO)) error(PF_PREFIX ": Cannot rewind on file '%s'.", ff->filename); procfile_close(ff); return NULL; } @@ -284,19 +284,46 @@ procfile *procfile_readall(procfile *ff) { return ff; } -procfile *procfile_open(const char *filename, const char *separators) { +static void procfile_set_separators(procfile *ff, const char *separators) { + static char def[256] = { [0 ... 255] = 0 }; + int i; + + if(!def[255]) { + // this is thread safe + // we check that the last byte is non-zero + // if it is zero, multiple threads may be executing this at the same time + // setting in def[] the exact same values + for(i = 0; i < 256 ;i++) { + if(i == '\n' || i == '\r') def[i] = PF_CHAR_IS_NEWLINE; + else if(isspace(i) || !isprint(i)) def[i] = PF_CHAR_IS_SEPARATOR; + else def[i] = PF_CHAR_IS_WORD; + } + } + + // copy the default + char *ffs = ff->separators, *ffd = def, *ffe = &def[256]; + while(ffd != ffe) *ffs++ = *ffd++; + + // set the separators + if(!separators) separators = " \t=|"; + ffs = ff->separators; + const char *s = separators; + while(*s) ffs[(int)*s++] = PF_CHAR_IS_SEPARATOR; +} + +procfile *procfile_open(const char *filename, const char *separators, uint32_t flags) { debug(D_PROCFILE, PF_PREFIX ": Opening file '%s'", filename); int fd = open(filename, O_RDONLY, 0666); if(fd == -1) { - error(PF_PREFIX ": Cannot open file '%s'. Reason: %s", filename, strerror(errno)); + if(!(flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO)) error(PF_PREFIX ": Cannot open file '%s'", filename); return NULL; } size_t size = (procfile_adaptive_initial_allocation) ? procfile_max_allocation : PROCFILE_INCREMENT_BUFFER; procfile *ff = malloc(sizeof(procfile) + size); if(!ff) { - error(PF_PREFIX ": Cannot allocate memory for file '%s'. Reason: %s", filename, strerror(errno)); + error(PF_PREFIX ": Cannot allocate memory for file '%s'", filename); close(fd); return NULL; } @@ -307,33 +334,25 @@ procfile *procfile_open(const char *filename, const char *separators) { ff->fd = fd; ff->size = size; ff->len = 0; + ff->flags = flags; ff->lines = pflines_new(); ff->words = pfwords_new(); if(!ff->lines || !ff->words) { - error(PF_PREFIX ": Cannot initialize parser for file '%s'. Reason: %s", filename, strerror(errno)); + error(PF_PREFIX ": Cannot initialize parser for file '%s'", filename); procfile_close(ff); return NULL; } - int i; - for(i = 0; i < 256 ;i++) { - if(i == '\n' || i == '\r') ff->separators[i] = PF_CHAR_IS_NEWLINE; - else if(isspace(i) || !isprint(i)) ff->separators[i] = PF_CHAR_IS_SEPARATOR; - else ff->separators[i] = PF_CHAR_IS_WORD; - } - - if(!separators) separators = " \t=|"; - const char *s = separators; - while(*s) ff->separators[(int)*s++] = PF_CHAR_IS_SEPARATOR; + procfile_set_separators(ff, separators); debug(D_PROCFILE, "File '%s' opened.", filename); return ff; } -procfile *procfile_reopen(procfile *ff, const char *filename, const char *separators) { - if(!ff) return procfile_open(filename, separators); +procfile *procfile_reopen(procfile *ff, const char *filename, const char *separators, uint32_t flags) { + if(!ff) return procfile_open(filename, separators, flags); if(ff->fd != -1) close(ff->fd); @@ -346,6 +365,11 @@ procfile *procfile_reopen(procfile *ff, const char *filename, const char *separa strncpy(ff->filename, filename, FILENAME_MAX); ff->filename[FILENAME_MAX] = '\0'; + ff->flags = flags; + + // do not do the separators again if NULL is given + if(separators) procfile_set_separators(ff, separators); + return ff; } diff --git a/src/procfile.h b/src/procfile.h index b360f444..73dfa198 100755 --- a/src/procfile.h +++ b/src/procfile.h @@ -55,8 +55,12 @@ typedef struct { // ---------------------------------------------------------------------------- // The procfile +#define PROCFILE_FLAG_DEFAULT 0x00000000 +#define PROCFILE_FLAG_NO_ERROR_ON_FILE_IO 0x00000001 + typedef struct { char filename[FILENAME_MAX + 1]; + uint32_t flags; int fd; // the file desriptor size_t len; // the bytes we have placed into data size_t size; // the bytes we have allocated for data @@ -73,11 +77,11 @@ extern void procfile_close(procfile *ff); extern procfile *procfile_readall(procfile *ff); // open a /proc or /sys file -extern procfile *procfile_open(const char *filename, const char *separators); +extern procfile *procfile_open(const char *filename, const char *separators, uint32_t flags); // re-open a file -// the separators argument is only used if ff == NULL -extern procfile *procfile_reopen(procfile *ff, const char *filename, const char *separators); +// if separators == NULL, the last separators are used +extern procfile *procfile_reopen(procfile *ff, const char *filename, const char *separators, uint32_t flags); // example walk-through a procfile parsed file extern void procfile_print(procfile *ff); -- 2.39.2