@cryptotaxi247 / netdata-1 / commits / 63406dc13

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

Costa Tsaousis (ktsaou) committed Apr 4, 2015 at 03:40 UTC 63406dc134c3aaaf4d3a3ebd09b793cc0a5efece
17 files changed +451 -207
src/log.c
+8 -7
@@ -10,6 +10,7 @@
10 // ----------------------------------------------------------------------------
11 // LOG
12
13 +const char *program_name = "";
14 unsigned long long debug_flags = DEBUG;
15
16 int silent = 0;
@@ -43,7 +44,7 @@ void debug_int( const char *file, const char *function, const unsigned long line
44
45 log_date(stdout);
46 va_start( args, fmt );
46 - fprintf(stdout, "DEBUG (%04lu@%-10.10s:%-15.15s): ", line, file, function);
47 + fprintf(stdout, "DEBUG (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name);
48 vfprintf( stdout, fmt, args );
49 va_end( args );
50 fprintf(stdout, "\n");
@@ -62,8 +63,8 @@ void info_int( const char *file, const char *function, const unsigned long line,
63 log_date(stderr);
64
65 va_start( args, fmt );
65 - if(debug_flags) fprintf(stderr, "INFO (%04lu@%-10.10s:%-15.15s): ", line, file, function);
66 - else fprintf(stderr, "INFO: ");
66 + if(debug_flags) fprintf(stderr, "INFO (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name);
67 + else fprintf(stderr, "INFO: %s: ", program_name);
68 vfprintf( stderr, fmt, args );
69 va_end( args );
70
@@ -83,8 +84,8 @@ void error_int( const char *file, const char *function, const unsigned long line
84 log_date(stderr);
85
86 va_start( args, fmt );
86 - if(debug_flags) fprintf(stderr, "ERROR (%04lu@%-10.10s:%-15.15s): ", line, file, function);
87 - else fprintf(stderr, "ERROR: ");
87 + if(debug_flags) fprintf(stderr, "ERROR (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name);
88 + else fprintf(stderr, "ERROR: %s: ", program_name);
89 vfprintf( stderr, fmt, args );
90 va_end( args );
91
@@ -108,8 +109,8 @@ void fatal_int( const char *file, const char *function, const unsigned long line
109 log_date(stderr);
110
111 va_start( args, fmt );
111 - if(debug_flags) fprintf(stderr, "FATAL (%04lu@%-10.10s:%-15.15s): ", line, file, function);
112 - else fprintf(stderr, "FATAL: ");
112 + if(debug_flags) fprintf(stderr, "FATAL (%04lu@%-10.10s:%-15.15s): %s: ", line, file, function, program_name);
113 + else fprintf(stderr, "FATAL: %s: ", program_name);
114 vfprintf( stderr, fmt, args );
115 va_end( args );
116
src/log.h
+2
@@ -31,6 +31,8 @@
31
32 extern unsigned long long debug_flags;
33
34 +extern const char *program_name;
35 +
36 extern int silent;
37
38 extern int access_fd;
src/main.c
+3
@@ -110,6 +110,9 @@ int main(int argc, char **argv)
110 int i;
111 int config_loaded = 0;
112
113 + // set the name for logging
114 + program_name = "netdata";
115 +
116 // parse the arguments
117 for(i = 1; i < argc ; i++) {
118 if(strcmp(argv[i], "-c") == 0 && (i+1) < argc) {
src/plugin_tc.c
+332 -131
@@ -3,7 +3,9 @@
3 #include <stdlib.h>
4 #include <string.h>
5
6 +#include "avl.h"
7 #include "log.h"
8 +#include "common.h"
9 #include "config.h"
10 #include "rrd.h"
11 #include "popen.h"
@@ -19,28 +21,98 @@
21 #define TC_LINE_MAX 1024
22
23 struct tc_class {
22 - char id[RRD_ID_LENGTH_MAX + 1];
23 - char name[RRD_ID_LENGTH_MAX + 1];
24 + avl avl;
25
25 - char leafid[RRD_ID_LENGTH_MAX + 1];
26 - char parentid[RRD_ID_LENGTH_MAX + 1];
26 + char *id;
27 + uint32_t hash;
28
28 - int hasparent;
29 - int isleaf;
29 + char *name;
30 +
31 + char *leafid;
32 + uint32_t leaf_hash;
33 +
34 + char *parentid;
35 + uint32_t parent_hash;
36 +
37 + char hasparent;
38 + char isleaf;
39 unsigned long long bytes;
40
41 + char updated;
42 +
43 struct tc_class *next;
44 };
45
46 struct tc_device {
36 - char id[RRD_ID_LENGTH_MAX + 1];
37 - char name[RRD_ID_LENGTH_MAX + 1];
38 - char family[RRD_ID_LENGTH_MAX + 1];
47 + avl avl;
48 +
49 + char *id;
50 + uint32_t hash;
51 +
52 + char *name;
53 + char *family;
54 +
55 + avl_tree classes_index;
56
57 struct tc_class *classes;
58 };
59
43 -void tc_device_commit(struct tc_device *d)
60 +
61 +// ----------------------------------------------------------------------------
62 +// tc_device index
63 +
64 +static int tc_device_iterator(avl *a) { if(a) {}; return 0; }
65 +
66 +static int tc_device_compare(void* a, void* b) {
67 + if(((struct tc_device *)a)->hash < ((struct tc_device *)b)->hash) return -1;
68 + else if(((struct tc_device *)a)->hash > ((struct tc_device *)b)->hash) return 1;
69 + else return strcmp(((struct tc_device *)a)->id, ((struct tc_device *)b)->id);
70 +}
71 +
72 +avl_tree tc_device_root_index = {
73 + NULL,
74 + tc_device_compare
75 +};
76 +
77 +#define tc_device_index_add(st) avl_insert(&tc_device_root_index, (avl *)(st))
78 +#define tc_device_index_del(st) avl_remove(&tc_device_root_index, (avl *)(st))
79 +
80 +static struct tc_device *tc_device_index_find(const char *id, uint32_t hash) {
81 + struct tc_device *result = NULL, tmp;
82 + tmp.id = (char *)id;
83 + tmp.hash = (hash)?hash:simple_hash(tmp.id);
84 +
85 + avl_search(&(tc_device_root_index), (avl *)&tmp, tc_device_iterator, (avl **)&result);
86 + return result;
87 +}
88 +
89 +
90 +// ----------------------------------------------------------------------------
91 +// tc_class index
92 +
93 +static int tc_class_iterator(avl *a) { if(a) {}; return 0; }
94 +
95 +static int tc_class_compare(void* a, void* b) {
96 + if(((struct tc_class *)a)->hash < ((struct tc_class *)b)->hash) return -1;
97 + else if(((struct tc_class *)a)->hash > ((struct tc_class *)b)->hash) return 1;
98 + else return strcmp(((struct tc_class *)a)->id, ((struct tc_class *)b)->id);
99 +}
100 +
101 +#define tc_class_index_add(st, rd) avl_insert(&((st)->classes_index), (avl *)(rd))
102 +#define tc_class_index_del(st, rd) avl_remove(&((st)->classes_index), (avl *)(rd))
103 +
104 +static struct tc_class *tc_class_index_find(struct tc_device *st, const char *id, uint32_t hash) {
105 + struct tc_class *result = NULL, tmp;
106 + tmp.id = (char *)id;
107 + tmp.hash = (hash)?hash:simple_hash(tmp.id);
108 +
109 + avl_search(&(st->classes_index), (avl *)&tmp, tc_class_iterator, (avl **)&result);
110 + return result;
111 +}
112 +
113 +// ----------------------------------------------------------------------------
114 +
115 +static void tc_device_commit(struct tc_device *d)
116 {
117 static int enable_new_interfaces = -1;
118
@@ -49,12 +121,22 @@ void tc_device_commit(struct tc_device *d)
121 // we only need to add leaf classes
122 struct tc_class *c, *x;
123
52 - for ( c = d->classes ; c ; c = c->next)
124 + // set them all as leafs without parent
125 + for(c = d->classes ; c ; c = c->next) {
126 c->isleaf = 1;
127 + c->hasparent = 0;
128 + }
129
55 - for ( c = d->classes ; c ; c = c->next) {
56 - for ( x = d->classes ; x ; x = x->next) {
57 - if(x->parentid[0] && (strcmp(c->id, x->parentid) == 0 || strcmp(c->leafid, x->parentid) == 0)) {
130 + // mark the classes as leafs and parents
131 + for(c = d->classes ; c ; c = c->next) {
132 + if(!c->updated) continue;
133 +
134 + for(x = d->classes ; x ; x = x->next) {
135 + if(!x->updated) continue;
136 +
137 + if(x->parentid && (
138 + ( c->hash == x->parent_hash && strcmp(c->id, x->parentid) == 0) ||
139 + (c->leafid && c->leaf_hash == x->parent_hash && strcmp(c->leafid, x->parentid) == 0))) {
140 // 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);
141 c->isleaf = 0;
142 x->hasparent = 1;
@@ -70,134 +152,229 @@ void tc_device_commit(struct tc_device *d)
152 }
153 */
154
73 - for ( c = d->classes ; c ; c = c->next) {
155 + // we need a device
156 + for(c = d->classes ; c ; c = c->next) {
157 + if(!c->updated) continue;
158 if(c->isleaf && c->hasparent) break;
159 }
160 if(!c) {
77 - debug(D_TC_LOOP, "TC: Ignoring TC device '%s'. No leaf classes.", d->name);
161 + debug(D_TC_LOOP, "TC: Ignoring TC device '%s'. No leaf classes.", d->name?d->name:d->id);
162 return;
163 }
164
81 - char var_name[4096 + 1];
82 - snprintf(var_name, 4096, "qos for %s", d->id);
165 + char var_name[CONFIG_MAX_NAME + 1];
166 + snprintf(var_name, CONFIG_MAX_NAME, "qos for %s", d->id);
167 if(config_get_boolean("plugin:tc", var_name, enable_new_interfaces)) {
168 RRDSET *st = rrdset_find_bytype(RRD_TYPE_TC, d->id);
169 if(!st) {
86 - debug(D_TC_LOOP, "TC: Committing new TC device '%s'", d->name);
170 + debug(D_TC_LOOP, "TC: Committing new TC device '%s'", d->name?d->name:d->id);
171 +
172 + 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);
173
88 - st = rrdset_create(RRD_TYPE_TC, d->id, d->name, d->family, "Class Usage", "kilobits/s", 1000, rrd_update_every, RRDSET_TYPE_STACKED);
174 + for(c = d->classes ; c ; c = c->next) {
175 + if(!c->updated) continue;
176
90 - for ( c = d->classes ; c ; c = c->next) {
177 if(c->isleaf && c->hasparent)
92 - rrddim_add(st, c->id, c->name, 8, 1024 * rrd_update_every, RRDDIM_INCREMENTAL);
178 + rrddim_add(st, c->id, c->name?c->name:c->id, 8, 1024 * rrd_update_every, RRDDIM_INCREMENTAL);
179 }
180 }
181 else {
182 rrdset_next_plugins(st);
183
98 - if(strcmp(d->id, d->name) != 0) rrdset_set_name(st, d->name);
184 + if(d->name && strcmp(d->id, d->name) != 0) rrdset_set_name(st, d->name);
185 }
186
101 - for ( c = d->classes ; c ; c = c->next) {
187 + for(c = d->classes ; c ; c = c->next) {
188 + if(!c->updated) continue;
189 +
190 if(c->isleaf && c->hasparent) {
191 if(rrddim_set(st, c->id, c->bytes) != 0) {
192
193 // new class, we have to add it
106 - rrddim_add(st, c->id, c->name, 8, 1024 * rrd_update_every, RRDDIM_INCREMENTAL);
194 + rrddim_add(st, c->id, c->name?c->name:c->id, 8, 1024 * rrd_update_every, RRDDIM_INCREMENTAL);
195 rrddim_set(st, c->id, c->bytes);
196 }
197
198 // if it has a name, different to the id
111 - if(strcmp(c->id, c->name) != 0) {
199 + if(c->name) {
200 // update the rrd dimension with the new name
113 - RRDDIM *rd;
114 - for(rd = st->dimensions ; rd ; rd = rd->next) {
115 - if(strcmp(rd->id, c->id) == 0) { rrddim_set_name(st, rd, c->name); break; }
116 - }
201 + RRDDIM *rd = rrddim_find(st, c->id);
202 + if(rd) rrddim_set_name(st, rd, c->name);
203 +
204 + free(c->name);
205 + c->name = NULL;
206 }
207 }
208 +
209 + c->updated = 0;
210 }
211 rrdset_done(st);
212 }
213 }
214
124 -void tc_device_set_class_name(struct tc_device *d, char *id, char *name)
215 +static void tc_device_set_class_name(struct tc_device *d, char *id, char *name)
216 {
126 - struct tc_class *c;
127 - for ( c = d->classes ; c ; c = c->next) {
128 - if(strcmp(c->id, id) == 0) {
129 - strncpy(c->name, name, RRD_ID_LENGTH_MAX);
130 - // no need for null termination - it is already null
131 - break;
132 - }
217 + struct tc_class *c = tc_class_index_find(d, id, 0);
218 + if(c) {
219 + if(c->name) free(c->name);
220 + c->name = NULL;
221 +
222 + if(name && *name && strcmp(c->id, name) != 0) c->name = strdup(name);
223 }
224 }
225
136 -void tc_device_set_device_name(struct tc_device *d, char *name)
137 -{
138 - strncpy(d->name, name, RRD_ID_LENGTH_MAX);
139 - // no need for null termination - it is already null
226 +static void tc_device_set_device_name(struct tc_device *d, char *name) {
227 + if(d->name) free(d->name);
228 + d->name = NULL;
229 +
230 + if(name && *name && strcmp(d->id, name) != 0) d->name = strdup(name);
231 }
232
142 -void tc_device_set_device_family(struct tc_device *d, char *name)
143 -{
144 - strncpy(d->family, name, RRD_ID_LENGTH_MAX);
233 +static void tc_device_set_device_family(struct tc_device *d, char *family) {
234 + if(d->family) free(d->family);
235 + d->family = NULL;
236 +
237 + if(family && *family && strcmp(d->id, family) != 0) d->family = strdup(family);
238 // no need for null termination - it is already null
239 }
240
148 -struct tc_device *tc_device_create(char *name)
241 +static struct tc_device *tc_device_create(char *id)
242 {
150 - struct tc_device *d;
243 + struct tc_device *d = tc_device_index_find(id, 0);
244
152 - d = calloc(1, sizeof(struct tc_device));
245 if(!d) {
154 - fatal("Cannot allocate memory for tc_device %s", name);
155 - return NULL;
156 - }
246
158 - strncpy(d->id, name, RRD_ID_LENGTH_MAX);
159 - strcpy(d->name, d->id);
160 - strcpy(d->family, d->id);
247 + d = calloc(1, sizeof(struct tc_device));
248 + if(!d) {
249 + fatal("Cannot allocate memory for tc_device %s", id);
250 + return NULL;
251 + }
252 +
253 + d->id = strdup(id);
254 + d->hash = simple_hash(d->id);
255
162 - // no need for null termination on the strings, because of calloc()
256 + d->classes_index.root = NULL;
257 + d->classes_index.compar = tc_class_compare;
258 +
259 + tc_device_index_add(d);
260 + }
261
262 return(d);
263 }
264
167 -struct tc_class *tc_class_add(struct tc_device *n, char *id, char *parentid, char *leafid)
265 +static struct tc_class *tc_class_add(struct tc_device *n, char *id, char *parentid, char *leafid)
266 {
169 - struct tc_class *c;
267 + // fprintf(stderr, "Adding class id '%s', parentid '%s', leafid '%s'\n", id, parentid, leafid);
268
171 - c = calloc(1, sizeof(struct tc_class));
269 + struct tc_class *c = tc_class_index_find(n, id, 0);
270 if(!c) {
173 - fatal("Cannot allocate memory for tc class");
174 - return NULL;
175 - }
271 + c = calloc(1, sizeof(struct tc_class));
272 + if(!c) {
273 + fatal("Cannot allocate memory for tc class");
274 + return NULL;
275 + }
276 +
277 + c->next = n->classes;
278 + n->classes = c;
279 +
280 + c->id = strdup(id);
281 + if(!c->id) {
282 + free(c);
283 + return NULL;
284 + }
285 + c->hash = simple_hash(c->id);
286
177 - c->next = n->classes;
178 - n->classes = c;
287 + if(parentid && *parentid) {
288 + c->parentid = strdup(parentid);
289 + c->parent_hash = simple_hash(c->parentid);
290 + }
291
180 - strncpy(c->id, id, RRD_ID_LENGTH_MAX);
181 - strcpy(c->name, c->id);
182 - if(parentid) strncpy(c->parentid, parentid, RRD_ID_LENGTH_MAX);
183 - if(leafid) strncpy(c->leafid, leafid, RRD_ID_LENGTH_MAX);
292 + if(leafid && *leafid) {
293 + c->leafid = strdup(leafid);
294 + c->leaf_hash = simple_hash(c->leafid);
295 + }
296
185 - // no need for null termination on the strings, because of calloc()
297 + tc_class_index_add(n, c);
298 + }
299
300 return(c);
301 }
189 -
190 -void tc_class_free(struct tc_class *c)
302 +/*
303 +static void tc_class_free_all(struct tc_device *n, struct tc_class *c)
304 {
192 - if(c->next) tc_class_free(c->next);
305 + if(c->next) tc_class_free_all(n, c->next);
306 + tc_class_index_del(n, c);
307 +
308 + if(c->id) free(c->id);
309 + if(c->name) free(c->name);
310 + if(c->leafid) free(c->leafid);
311 + if(c->parentid) free(c->parentid);
312 +
313 free(c);
314 }
315
196 -void tc_device_free(struct tc_device *n)
316 +static void tc_device_free(struct tc_device *n)
317 {
198 - if(n->classes) tc_class_free(n->classes);
318 + tc_device_index_del(n);
319 + if(n->classes) tc_class_free_all(n, n->classes);
320 +
321 + if(n->id) free(n->id);
322 + if(n->name) free(n->name);
323 + if(n->family) free(n->family);
324 +
325 free(n);
326 }
327 +*/
328 +
329 +#define MAX_WORDS 20
330 +
331 +int tc_space(char c) {
332 + switch(c) {
333 + case ' ':
334 + case '\t':
335 + case '\r':
336 + case '\n':
337 + return 1;
338 +
339 + default:
340 + return 0;
341 + }
342 +}
343 +
344 +void tc_split_words(char *str, char **words, int max_words) {
345 + char *s = str;
346 + int i = 0;
347 +
348 + // skip all white space
349 + while(tc_space(*s)) s++;
350 +
351 + // store the first word
352 + words[i++] = s;
353 +
354 + // while we have something
355 + while(*s) {
356 + // if it is a space
357 + if(tc_space(*s)) {
358 +
359 + // terminate the word
360 + *s++ = '\0';
361 +
362 + // skip all white space
363 + while(tc_space(*s)) s++;
364 +
365 + // if we reached the end, stop
366 + if(!*s) break;
367 +
368 + // store the next word
369 + if(i < max_words) words[i++] = s;
370 + else break;
371 + }
372 + else s++;
373 + }
374 +
375 + // terminate the words
376 + while(i < max_words) words[i++] = NULL;
377 +}
378
379 pid_t tc_child_pid = 0;
380 void *tc_main(void *ptr)
@@ -211,6 +388,19 @@ void *tc_main(void *ptr)
388 error("Cannot set pthread cancel state to ENABLE.");
389
390 char buffer[TC_LINE_MAX+1] = "";
391 + char *words[MAX_WORDS] = { NULL };
392 +
393 + uint32_t BEGIN_HASH = simple_hash("BEGIN");
394 + uint32_t END_HASH = simple_hash("END");
395 + uint32_t CLASS_HASH = simple_hash("class");
396 + uint32_t SENT_HASH = simple_hash("Sent");
397 + uint32_t SETDEVICENAME_HASH = simple_hash("SETDEVICENAME");
398 + uint32_t SETDEVICEGROUP_HASH = simple_hash("SETDEVICEGROUP");
399 + uint32_t SETCLASSNAME_HASH = simple_hash("SETCLASSNAME");
400 +#ifdef DETACH_PLUGINS_FROM_NETDATA
401 + uint32_t MYPID_HASH = simple_hash("MYPID");
402 +#endif
403 + uint32_t first_hash;
404
405 for(;1;) {
406 FILE *fp;
@@ -228,20 +418,54 @@ void *tc_main(void *ptr)
418
419 while(fgets(buffer, TC_LINE_MAX, fp) != NULL) {
420 buffer[TC_LINE_MAX] = '\0';
231 - char *b = buffer, *p;
421 // debug(D_TC_LOOP, "TC: read '%s'", buffer);
422
234 - p = strsep(&b, " \n");
235 - while (p && (*p == ' ' || *p == '\0')) p = strsep(&b, " \n");
236 - if(!p) continue;
423 + tc_split_words(buffer, words, MAX_WORDS);
424 + if(!words[0] || !*words[0]) {
425 + // debug(D_TC_LOOP, "empty line");
426 + continue;
427 + }
428 + // else debug(D_TC_LOOP, "First word is '%s'", words[0]);
429 +
430 + first_hash = simple_hash(words[0]);
431 +
432 + if(first_hash == CLASS_HASH && strcmp(words[0], "class") == 0 && device) {
433 + // 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]);
434 +
435 + if(words[1] && words[2] && words[3] && words[4] && (strcmp(words[3], "parent") == 0 || strcmp(words[3], "root") == 0)) {
436 + // char *type = words[1]; // the class: htb, fq_codel, etc
437 + char *id = words[2]; // the class major:minor
438 + char *parent = words[3]; // 'parent' or 'root'
439 + char *parentid = words[4]; // the parent's id
440 + char *leaf = words[5]; // 'leaf'
441 + char *leafid = words[6]; // leafid
442 +
443 + if(strcmp(parent, "root") == 0) {
444 + parentid = NULL;
445 + leafid = NULL;
446 + }
447 + else if(!leaf || strcmp(leaf, "leaf") != 0)
448 + leafid = NULL;
449 +
450 + char leafbuf[20 + 1] = "";
451 + if(leafid && leafid[strlen(leafid) - 1] == ':') {
452 + strncpy(leafbuf, leafid, 20 - 1);
453 + strcat(leafbuf, "1");
454 + leafid = leafbuf;
455 + }
456 +
457 + class = tc_class_add(device, id, parentid, leafid);
458 + }
459 + }
460 + else if(first_hash == END_HASH && strcmp(words[0], "END") == 0) {
461 + // debug(D_TC_LOOP, "END line");
462
238 - if(strcmp(p, "END") == 0) {
463 if(device) {
464 if(pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL) != 0)
465 error("Cannot set pthread cancel state to DISABLE.");
466
467 tc_device_commit(device);
244 - tc_device_free(device);
468 + // tc_device_free(device);
469 device = NULL;
470 class = NULL;
471
@@ -249,72 +473,46 @@ void *tc_main(void *ptr)
473 error("Cannot set pthread cancel state to ENABLE.");
474 }
475 }
252 - else if(strcmp(p, "BEGIN") == 0) {
476 + else if(first_hash == BEGIN_HASH && strcmp(words[0], "BEGIN") == 0) {
477 + // debug(D_TC_LOOP, "BEGIN line on device '%s'", words[1]);
478 +
479 if(device) {
254 - tc_device_free(device);
480 + // tc_device_free(device);
481 device = NULL;
482 class = NULL;
483 }
484
259 - p = strsep(&b, " \n");
260 - if(p && *p) {
261 - device = tc_device_create(p);
485 + if(words[1] && *words[1]) {
486 + device = tc_device_create(words[1]);
487 class = NULL;
488 }
489 }
265 - else if(device && (strcmp(p, "class") == 0)) {
266 - p = strsep(&b, " \n"); // the class: htb, fq_codel, etc
267 - char *id = strsep(&b, " \n"); // the class major:minor
268 - char *parent = strsep(&b, " \n"); // 'parent' or 'root'
269 - char *parentid = strsep(&b, " \n"); // the parent's id
270 - char *leaf = strsep(&b, " \n"); // 'leaf'
271 - char *leafid = strsep(&b, " \n"); // leafid
272 -
273 - if(id && *id
274 - && parent && *parent
275 - && parentid && *parentid
276 - && (
277 - (strcmp(parent, "parent") == 0 && parentid && *parentid)
278 - || strcmp(parent, "root") == 0
279 - )) {
280 -
281 - if(strcmp(parent, "root") == 0) {
282 - parentid = NULL;
283 - leafid = NULL;
284 - }
285 - else if(!leaf || strcmp(leaf, "leaf") != 0)
286 - leafid = NULL;
287 -
288 - char leafbuf[20 + 1] = "";
289 - if(leafid && leafid[strlen(leafid) - 1] == ':') {
290 - strncpy(leafbuf, leafid, 20 - 1);
291 - strcat(leafbuf, "1");
292 - leafid = leafbuf;
293 - }
294 -
295 - class = tc_class_add(device, id, parentid, leafid);
490 + else if(first_hash == SENT_HASH && strcmp(words[0], "Sent") == 0 && device && class) {
491 + // debug(D_TC_LOOP, "SENT line '%s'", words[1]);
492 + if(words[1] && *words[1]) {
493 + class->bytes = atoll(words[1]);
494 + class->updated = 1;
495 }
496 + else class->bytes = 0;
497 }
298 - else if(device && class && (strcmp(p, "Sent") == 0)) {
299 - p = strsep(&b, " \n");
300 - if(p && *p) class->bytes = atoll(p);
301 - }
302 - else if(device && (strcmp(p, "SETDEVICENAME") == 0)) {
303 - char *name = strsep(&b, " \n");
304 - if(name && *name) tc_device_set_device_name(device, name);
498 + else if(first_hash == SETDEVICENAME_HASH && strcmp(words[0], "SETDEVICENAME") == 0 && device) {
499 + // debug(D_TC_LOOP, "SETDEVICENAME line '%s'", words[1]);
500 + if(words[1] && *words[1]) tc_device_set_device_name(device, words[1]);
501 }
306 - else if(device && (strcmp(p, "SETDEVICEGROUP") == 0)) {
307 - char *name = strsep(&b, " \n");
308 - if(name && *name) tc_device_set_device_family(device, name);
502 + else if(first_hash == SETDEVICEGROUP_HASH && strcmp(words[0], "SETDEVICEGROUP") == 0 && device) {
503 + // debug(D_TC_LOOP, "SETDEVICEGROUP line '%s'", words[1]);
504 + if(words[1] && *words[1]) tc_device_set_device_family(device, words[1]);
505 }
310 - else if(device && (strcmp(p, "SETCLASSNAME") == 0)) {
311 - char *id = strsep(&b, " \n");
312 - char *path = strsep(&b, " \n");
506 + else if(first_hash == SETCLASSNAME_HASH && strcmp(words[0], "SETCLASSNAME") == 0 && device) {
507 + // debug(D_TC_LOOP, "SETCLASSNAME line '%s' '%s'", words[1], words[2]);
508 + char *id = words[1];
509 + char *path = words[2];
510 if(id && *id && path && *path) tc_device_set_class_name(device, id, path);
511 }
512 #ifdef DETACH_PLUGINS_FROM_NETDATA
316 - else if((strcmp(p, "MYPID") == 0)) {
317 - char *id = strsep(&b, " \n");
513 + else if(first_hash == MYPID_HASH && (strcmp(words[0], "MYPID") == 0)) {
514 + // debug(D_TC_LOOP, "MYPID line '%s'", words[1]);
515 + char *id = words[1];
516 pid_t pid = atol(id);
517
518 if(pid) tc_child_pid = pid;
@@ -322,11 +520,14 @@ void *tc_main(void *ptr)
520 debug(D_TC_LOOP, "TC: Child PID is %d.", tc_child_pid);
521 }
522 #endif
523 + //else {
524 + // debug(D_TC_LOOP, "IGNORED line");
525 + //}
526 }
527 mypclose(fp);
528
529 if(device) {
329 - tc_device_free(device);
530 + // tc_device_free(device);
531 device = NULL;
532 class = NULL;
533 }
src/plugins.d/apps_plugin.c
+42 -33
@@ -202,7 +202,7 @@ procfile *ff = NULL;
202 long get_processors(void) {
203 int processors = 0;
204
205 - ff = procfile_reopen(ff, "/proc/stat", "");
205 + ff = procfile_reopen(ff, "/proc/stat", "", PROCFILE_FLAG_DEFAULT);
206 if(!ff) return 1;
207
208 ff = procfile_readall(ff);
@@ -227,7 +227,7 @@ long get_processors(void) {
227 long get_pid_max(void) {
228 long mpid = 32768;
229
230 - ff = procfile_reopen(ff, "/proc/sys/kernel/pid_max", "");
230 + ff = procfile_reopen(ff, "/proc/sys/kernel/pid_max", "", PROCFILE_FLAG_DEFAULT);
231 if(!ff) return mpid;
232
233 ff = procfile_readall(ff);
@@ -260,7 +260,7 @@ unsigned long long get_hertz(void)
260 hz = (sizeof(long)==sizeof(int) || htons(999)==999) ? 100UL : 1024UL;
261 #endif
262
263 - error("apps.plugin: ERROR: unknown HZ value. Assuming %llu.", hz);
263 + error("Unknown HZ value. Assuming %llu.", hz);
264 return hz;
265 }
266
@@ -353,7 +353,7 @@ struct target *get_target(const char *id, struct target *target)
353
354 w = calloc(sizeof(struct target), 1);
355 if(!w) {
356 - error("apps.plugin: cannot allocate %lu bytes of memory", (unsigned long)sizeof(struct target));
356 + error("Cannot allocate %lu bytes of memory", (unsigned long)sizeof(struct target));
357 return NULL;
358 }
359
@@ -383,7 +383,7 @@ int read_process_groups(const char *name)
383 if(debug) fprintf(stderr, "apps.plugin: process groups file: '%s'\n", filename);
384 FILE *fp = fopen(filename, "r");
385 if(!fp) {
386 - error("apps.plugin: ERROR: cannot open file '%s' (%s)", filename, strerror(errno));
386 + error("Cannot open file '%s' (%s)", filename, strerror(errno));
387 return 1;
388 }
389
@@ -444,7 +444,7 @@ int read_process_groups(const char *name)
444 }
445
446 if(w) strncpy(w->name, t, MAX_NAME);
447 - if(!count) error("apps.plugin: ERROR: the line %ld on file '%s', for group '%s' does not state any process names.", line, filename, t);
447 + if(!count) error("The line %ld on file '%s', for group '%s' does not state any process names.", line, filename, t);
448 }
449 fclose(fp);
450
@@ -567,13 +567,13 @@ struct pid_stat *get_pid_entry(pid_t pid)
567
568 all_pids[pid] = calloc(sizeof(struct pid_stat), 1);
569 if(!all_pids[pid]) {
570 - error("apps.plugin: ERROR: Cannot allocate %lu bytes of memory", (unsigned long)sizeof(struct pid_stat));
570 + error("Cannot allocate %lu bytes of memory", (unsigned long)sizeof(struct pid_stat));
571 return NULL;
572 }
573
574 all_pids[pid]->fds = calloc(sizeof(int), 100);
575 if(!all_pids[pid]->fds)
576 - error("apps.plugin: ERROR: Cannot allocate %ld bytes of memory", (unsigned long)(sizeof(int) * 100));
576 + error("Cannot allocate %ld bytes of memory", (unsigned long)(sizeof(int) * 100));
577 else all_pids[pid]->fds_size = 100;
578
579 if(root_of_pids) root_of_pids->prev = all_pids[pid];
@@ -610,7 +610,7 @@ int read_proc_pid_stat(struct pid_stat *p) {
610
611 snprintf(filename, FILENAME_MAX, "/proc/%d/stat", p->pid);
612
613 - ff = procfile_reopen(ff, filename, "");
613 + ff = procfile_reopen(ff, filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
614 if(!ff) return 1;
615
616 ff = procfile_readall(ff);
@@ -699,7 +699,7 @@ int read_proc_pid_statm(struct pid_stat *p) {
699
700 snprintf(filename, FILENAME_MAX, "/proc/%d/statm", p->pid);
701
702 - ff = procfile_reopen(ff, filename, "");
702 + ff = procfile_reopen(ff, filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
703 if(!ff) return 1;
704
705 ff = procfile_readall(ff);
@@ -727,7 +727,7 @@ int read_proc_pid_io(struct pid_stat *p) {
727
728 snprintf(filename, FILENAME_MAX, "/proc/%d/io", p->pid);
729
730 - ff = procfile_reopen(ff, filename, "");
730 + ff = procfile_reopen(ff, filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
731 if(!ff) return 1;
732
733 ff = procfile_readall(ff);
@@ -875,9 +875,9 @@ void file_descriptor_not_used(int id)
875 }
876 }
877 else
878 - error("apps.plugin: ERROR: request to decrease counter of fd %d (%s), while the use counter is 0", id, all_files[id].name);
878 + error("Request to decrease counter of fd %d (%s), while the use counter is 0", id, all_files[id].name);
879 }
880 - 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);
880 + else error("Request to decrease counter of fd %d, which is outside the array size (1 to %d)", id, all_files_size);
881 }
882
883 unsigned long file_descriptor_find_or_add(const char *name)
@@ -940,7 +940,7 @@ unsigned long file_descriptor_find_or_add(const char *name)
940 if(debug) fprintf(stderr, "apps.plugin: >> Examining slot %d.\n", c);
941
942 if(all_files[c].magic == 0x0BADCAFE && all_files[c].name && file_descriptor_find(all_files[c].name, all_files[c].hash))
943 - error("apps.plugin: fd on position %d is not cleared properly. It still has %s in it.\n", c, all_files[c].name);
943 + error("fd on position %d is not cleared properly. It still has %s in it.\n", c, all_files[c].name);
944
945 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);
946 if(all_files[c].name) free((void *)all_files[c].name);
@@ -1042,7 +1042,9 @@ int update_from_proc(void)
1042 // /proc/<pid>/stat
1043
1044 if(read_proc_pid_stat(p)) {
1045 - error("Cannot process /proc/%d/stat", pid);
1045 + if(!count_errors++ || debug || (p->target && p->target->debug))
1046 + error("Cannot process /proc/%d/stat", pid);
1047 +
1048 continue;
1049 }
1050 if(p->ppid < 0 || p->ppid > pid_max) p->ppid = 0;
@@ -1052,7 +1054,9 @@ int update_from_proc(void)
1054 // /proc/<pid>/statm
1055
1056 if(read_proc_pid_statm(p)) {
1055 - error("Cannot process /proc/%d/statm", pid);
1057 + if(!count_errors++ || debug || (p->target && p->target->debug))
1058 + error("Cannot process /proc/%d/statm", pid);
1059 +
1060 continue;
1061 }
1062
@@ -1061,7 +1065,9 @@ int update_from_proc(void)
1065 // /proc/<pid>/io
1066
1067 if(read_proc_pid_io(p)) {
1064 - error("Cannot process /proc/%d/io", pid);
1068 + if(!count_errors++ || debug || (p->target && p->target->debug))
1069 + error("Cannot process /proc/%d/io", pid);
1070 +
1071 continue;
1072 }
1073
@@ -1111,7 +1117,7 @@ int update_from_proc(void)
1117 if(debug) fprintf(stderr, "apps.plugin: extending fd memory slots for %s from %d to %d\n", p->comm, p->fds_size, fdid + 100);
1118 p->fds = realloc(p->fds, (fdid + 100) * sizeof(int));
1119 if(!p->fds) {
1114 - error("apps.plugin: ERROR: cannot re-allocate fds for %s", p->comm);
1120 + error("Cannot re-allocate fds for %s", p->comm);
1121 break;
1122 }
1123
@@ -1128,7 +1134,7 @@ int update_from_proc(void)
1134 if(l == -1) {
1135 if(debug || (p->target && p->target->debug)) {
1136 if(!count_errors++ || debug || (p->target && p->target->debug))
1131 - error("apps.plugin: ERROR: cannot read link %s", fdname);
1137 + error("Cannot read link %s", fdname);
1138 }
1139 continue;
1140 }
@@ -1161,7 +1167,7 @@ int update_from_proc(void)
1167 p->updated = 1;
1168 }
1169 if(count_errors > 1000) {
1164 - error("apps.plugin: ERROR: %ld more errors encountered\n", count_errors - 1);
1170 + error("%ld more errors encountered\n", count_errors - 1);
1171 count_errors = 0;
1172 }
1173
@@ -1199,7 +1205,7 @@ void update_statistics(void)
1205 p->parent = all_pids[p->ppid];
1206 p->parent->childs++;
1207 }
1202 - 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);
1208 + else if(p->ppid != 0) error("pid %d %s states parent %d, but the later does not exist.", p->pid, p->comm, p->ppid);
1209 }
1210
1211 // find all the procs with 0 childs and merge them to their parents
@@ -1309,10 +1315,10 @@ void update_statistics(void)
1315 }
1316 }
1317
1312 - if(diff_utime) error("apps.plugin: \t cannot fix up utime %llu", diff_utime);
1313 - if(diff_stime) error("apps.plugin: \t cannot fix up stime %llu", diff_stime);
1314 - if(diff_minflt) error("apps.plugin: \t cannot fix up minflt %llu", diff_minflt);
1315 - if(diff_majflt) error("apps.plugin: \t cannot fix up majflt %llu", diff_majflt);
1318 + if(diff_utime) error("Cannot fix up utime %llu", diff_utime);
1319 + if(diff_stime) error("Cannot fix up stime %llu", diff_stime);
1320 + if(diff_minflt) error("Cannot fix up minflt %llu", diff_minflt);
1321 + if(diff_majflt) error("Cannot fix up majflt %llu", diff_majflt);
1322 }
1323 #endif
1324
@@ -1324,7 +1330,7 @@ void update_statistics(void)
1330
1331 w->fds = calloc(sizeof(int), all_files_size);
1332 if(!w->fds)
1327 - error("apps.plugin: ERROR: cannot allocate memory for fds in %s", w->name);
1333 + error("Cannot allocate memory for fds in %s", w->name);
1334
1335 w->minflt = 0;
1336 w->majflt = 0;
@@ -1362,7 +1368,7 @@ void update_statistics(void)
1368 // concentrate everything on the targets
1369 for(p = root_of_pids; p ; p = p->next) {
1370 if(!p->target) {
1365 - error("apps.plugin: ERROR: pid %d %s was left without a target!", p->pid, p->comm);
1371 + error("pid %d %s was left without a target!", p->pid, p->comm);
1372 continue;
1373 }
1374
@@ -1410,7 +1416,7 @@ void update_statistics(void)
1416 if(p->target->fds) p->target->fds[p->fds[c]]++;
1417 }
1418 else
1413 - error("apps.plugin: ERROR: invalid fd number %d", p->fds[c]);
1419 + error("Invalid fd number %d", p->fds[c]);
1420 }
1421
1422 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)
1882 continue;
1883 }
1884
1879 - error("apps.plugin: ERROR: cannot understand option %s", argv[i]);
1885 + error("Cannot understand option %s", argv[i]);
1886 exit(1);
1887 }
1888
@@ -1884,7 +1890,7 @@ void parse_args(int argc, char **argv)
1890 if(!name) name = "groups";
1891
1892 if(read_process_groups(name)) {
1887 - error("apps.plugin: ERROR: cannot read process groups %s", name);
1893 + error("Cannot read process groups %s", name);
1894 exit(1);
1895 }
1896 }
@@ -1893,7 +1899,10 @@ int main(int argc, char **argv)
1899 {
1900 // debug_flags = D_PROCFILE;
1901
1896 - info("apps.plugin: starting...");
1902 + // set the name for logging
1903 + program_name = "apps.plugin";
1904 +
1905 + info("starting...");
1906
1907 procfile_adaptive_initial_allocation = 1;
1908
@@ -1906,7 +1915,7 @@ int main(int argc, char **argv)
1915
1916 all_pids = calloc(sizeof(struct pid_stat *), pid_max);
1917 if(!all_pids) {
1909 - error("apps.plugin: ERROR: cannot allocate %lu bytes of memory.", sizeof(struct pid_stat *) * pid_max);
1918 + error("Cannot allocate %lu bytes of memory.", sizeof(struct pid_stat *) * pid_max);
1919 printf("DISABLE\n");
1920 exit(1);
1921 }
@@ -1918,7 +1927,7 @@ int main(int argc, char **argv)
1927
1928 for(;1; counter++) {
1929 if(!update_from_proc()) {
1921 - error("apps.plugin: ERROR: cannot allocate %lu bytes of memory.", sizeof(struct pid_stat *) * pid_max);
1930 + error("Cannot allocate %lu bytes of memory.", sizeof(struct pid_stat *) * pid_max);
1931 printf("DISABLE\n");
1932 exit(1);
1933 }
src/proc_diskstats.c
+1 -1
@@ -30,7 +30,7 @@ int do_proc_diskstats(int update_every, unsigned long long dt) {
30
31 if(dt) {};
32
33 - if(!ff) ff = procfile_open("/proc/diskstats", " \t");
33 + if(!ff) ff = procfile_open("/proc/diskstats", " \t", PROCFILE_FLAG_DEFAULT);
34 if(!ff) return 1;
35
36 ff = procfile_readall(ff);
src/proc_meminfo.c
+1 -1
@@ -27,7 +27,7 @@ int do_proc_meminfo(int update_every, unsigned long long dt) {
27
28 if(dt) {};
29
30 - if(!ff) ff = procfile_open("/proc/meminfo", " \t:");
30 + if(!ff) ff = procfile_open("/proc/meminfo", " \t:", PROCFILE_FLAG_DEFAULT);
31 if(!ff) return 1;
32
33 ff = procfile_readall(ff);
src/proc_net_dev.c
+1 -1
@@ -14,7 +14,7 @@ int do_proc_net_dev(int update_every, unsigned long long dt) {
14
15 if(dt) {};
16
17 - if(!ff) ff = procfile_open("/proc/net/dev", " \t,:|");
17 + if(!ff) ff = procfile_open("/proc/net/dev", " \t,:|", PROCFILE_FLAG_DEFAULT);
18 if(!ff) return 1;
19
20 ff = procfile_readall(ff);
src/proc_net_ip_vs_stats.c
+1 -1
@@ -20,7 +20,7 @@ int do_proc_net_ip_vs_stats(int update_every, unsigned long long dt) {
20
21 if(dt) {};
22
23 - if(!ff) ff = procfile_open("/proc/net/ip_vs_stats", " \t,:|");
23 + if(!ff) ff = procfile_open("/proc/net/ip_vs_stats", " \t,:|", PROCFILE_FLAG_DEFAULT);
24 if(!ff) return 1;
25
26 ff = procfile_readall(ff);
src/proc_net_netstat.c
+1 -1
@@ -22,7 +22,7 @@ int do_proc_net_netstat(int update_every, unsigned long long dt) {
22
23 if(dt) {};
24
25 - if(!ff) ff = procfile_open("/proc/net/netstat", " \t:");
25 + if(!ff) ff = procfile_open("/proc/net/netstat", " \t:", PROCFILE_FLAG_DEFAULT);
26 if(!ff) return 1;
27
28 ff = procfile_readall(ff);
src/proc_net_rpc_nfsd.c
+1 -1
@@ -137,7 +137,7 @@ int do_proc_net_rpc_nfsd(int update_every, unsigned long long dt) {
137
138 if(dt) {};
139
140 - if(!ff) ff = procfile_open("/proc/net/rpc/nfsd", " \t");
140 + if(!ff) ff = procfile_open("/proc/net/rpc/nfsd", " \t", PROCFILE_FLAG_DEFAULT);
141 if(!ff) return 1;
142
143 ff = procfile_readall(ff);
src/proc_net_snmp.c
+1 -1
@@ -31,7 +31,7 @@ int do_proc_net_snmp(int update_every, unsigned long long dt) {
31
32 if(dt) {};
33
34 - if(!ff) ff = procfile_open("/proc/net/snmp", " \t:");
34 + if(!ff) ff = procfile_open("/proc/net/snmp", " \t:", PROCFILE_FLAG_DEFAULT);
35 if(!ff) return 1;
36
37 ff = procfile_readall(ff);
src/proc_net_stat_conntrack.c
+1 -1
@@ -25,7 +25,7 @@ int do_proc_net_stat_conntrack(int update_every, unsigned long long dt) {
25
26 if(dt) {};
27
28 - if(!ff) ff = procfile_open("/proc/net/stat/nf_conntrack", " \t:");
28 + if(!ff) ff = procfile_open("/proc/net/stat/nf_conntrack", " \t:", PROCFILE_FLAG_DEFAULT);
29 if(!ff) return 1;
30
31 ff = procfile_readall(ff);
src/proc_stat.c
+1 -1
@@ -25,7 +25,7 @@ int do_proc_stat(int update_every, unsigned long long dt) {
25
26 if(dt) {};
27
28 - if(!ff) ff = procfile_open("/proc/stat", " \t:");
28 + if(!ff) ff = procfile_open("/proc/stat", " \t:", PROCFILE_FLAG_DEFAULT);
29 if(!ff) return 1;
30
31 ff = procfile_readall(ff);
src/proc_vmstat.c
+1 -1
@@ -23,7 +23,7 @@ int do_proc_vmstat(int update_every, unsigned long long dt) {
23
24 if(dt) {};
25
26 - if(!ff) ff = procfile_open("/proc/vmstat", " \t:");
26 + if(!ff) ff = procfile_open("/proc/vmstat", " \t:", PROCFILE_FLAG_DEFAULT);
27 if(!ff) return 1;
28
29 ff = procfile_readall(ff);
src/procfile.c
+47 -23
@@ -136,9 +136,9 @@ void pflines_free(pflines *fl) {
136 // ----------------------------------------------------------------------------
137 // The procfile
138
139 -#define PF_CHAR_IS_SEPARATOR 0
140 -#define PF_CHAR_IS_NEWLINE 1
141 -#define PF_CHAR_IS_WORD 2
139 +#define PF_CHAR_IS_SEPARATOR ' '
140 +#define PF_CHAR_IS_NEWLINE 'N'
141 +#define PF_CHAR_IS_WORD 'W'
142
143 void procfile_close(procfile *ff) {
144 debug(D_PROCFILE, PF_PREFIX ": Closing file '%s'", ff->filename);
@@ -224,7 +224,7 @@ procfile *procfile_parser(procfile *ff) {
224 return ff;
225
226 cleanup:
227 - error(PF_PREFIX ": Failed to parse file '%s'. Reason: %s", ff->filename, strerror(errno));
227 + error(PF_PREFIX ": Failed to parse file '%s'", ff->filename);
228 procfile_close(ff);
229 return NULL;
230 }
@@ -241,7 +241,7 @@ procfile *procfile_readall(procfile *ff) {
241
242 procfile *new = realloc(ff, sizeof(procfile) + ff->size + PROCFILE_INCREMENT_BUFFER);
243 if(!new) {
244 - error(PF_PREFIX ": Cannot allocate memory for file '%s'. Reason: %s", ff->filename, strerror(errno));
244 + error(PF_PREFIX ": Cannot allocate memory for file '%s'", ff->filename);
245 procfile_close(ff);
246 return NULL;
247 }
@@ -253,7 +253,7 @@ procfile *procfile_readall(procfile *ff) {
253 debug(D_PROCFILE, "Reading file '%s', from position %ld with length %ld", ff->filename, s, ff->size - s);
254 r = read(ff->fd, &ff->data[s], ff->size - s);
255 if(r == -1) {
256 - error(PF_PREFIX ": Cannot read from file '%s'. Reason: %s", ff->filename, strerror(errno));
256 + if(!(ff->flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO)) error(PF_PREFIX ": Cannot read from file '%s'", ff->filename);
257 procfile_close(ff);
258 return NULL;
259 }
@@ -264,7 +264,7 @@ procfile *procfile_readall(procfile *ff) {
264
265 debug(D_PROCFILE, "Rewinding file '%s'", ff->filename);
266 if(lseek(ff->fd, 0, SEEK_SET) == -1) {
267 - error(PF_PREFIX ": Cannot rewind on file '%s'.", ff->filename);
267 + if(!(ff->flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO)) error(PF_PREFIX ": Cannot rewind on file '%s'.", ff->filename);
268 procfile_close(ff);
269 return NULL;
270 }
@@ -284,19 +284,46 @@ procfile *procfile_readall(procfile *ff) {
284 return ff;
285 }
286
287 -procfile *procfile_open(const char *filename, const char *separators) {
287 +static void procfile_set_separators(procfile *ff, const char *separators) {
288 + static char def[256] = { [0 ... 255] = 0 };
289 + int i;
290 +
291 + if(!def[255]) {
292 + // this is thread safe
293 + // we check that the last byte is non-zero
294 + // if it is zero, multiple threads may be executing this at the same time
295 + // setting in def[] the exact same values
296 + for(i = 0; i < 256 ;i++) {
297 + if(i == '\n' || i == '\r') def[i] = PF_CHAR_IS_NEWLINE;
298 + else if(isspace(i) || !isprint(i)) def[i] = PF_CHAR_IS_SEPARATOR;
299 + else def[i] = PF_CHAR_IS_WORD;
300 + }
301 + }
302 +
303 + // copy the default
304 + char *ffs = ff->separators, *ffd = def, *ffe = &def[256];
305 + while(ffd != ffe) *ffs++ = *ffd++;
306 +
307 + // set the separators
308 + if(!separators) separators = " \t=|";
309 + ffs = ff->separators;
310 + const char *s = separators;
311 + while(*s) ffs[(int)*s++] = PF_CHAR_IS_SEPARATOR;
312 +}
313 +
314 +procfile *procfile_open(const char *filename, const char *separators, uint32_t flags) {
315 debug(D_PROCFILE, PF_PREFIX ": Opening file '%s'", filename);
316
317 int fd = open(filename, O_RDONLY, 0666);
318 if(fd == -1) {
292 - error(PF_PREFIX ": Cannot open file '%s'. Reason: %s", filename, strerror(errno));
319 + if(!(flags & PROCFILE_FLAG_NO_ERROR_ON_FILE_IO)) error(PF_PREFIX ": Cannot open file '%s'", filename);
320 return NULL;
321 }
322
323 size_t size = (procfile_adaptive_initial_allocation) ? procfile_max_allocation : PROCFILE_INCREMENT_BUFFER;
324 procfile *ff = malloc(sizeof(procfile) + size);
325 if(!ff) {
299 - error(PF_PREFIX ": Cannot allocate memory for file '%s'. Reason: %s", filename, strerror(errno));
326 + error(PF_PREFIX ": Cannot allocate memory for file '%s'", filename);
327 close(fd);
328 return NULL;
329 }
@@ -307,33 +334,25 @@ procfile *procfile_open(const char *filename, const char *separators) {
334 ff->fd = fd;
335 ff->size = size;
336 ff->len = 0;
337 + ff->flags = flags;
338
339 ff->lines = pflines_new();
340 ff->words = pfwords_new();
341
342 if(!ff->lines || !ff->words) {
315 - error(PF_PREFIX ": Cannot initialize parser for file '%s'. Reason: %s", filename, strerror(errno));
343 + error(PF_PREFIX ": Cannot initialize parser for file '%s'", filename);
344 procfile_close(ff);
345 return NULL;
346 }
347
320 - int i;
321 - for(i = 0; i < 256 ;i++) {
322 - if(i == '\n' || i == '\r') ff->separators[i] = PF_CHAR_IS_NEWLINE;
323 - else if(isspace(i) || !isprint(i)) ff->separators[i] = PF_CHAR_IS_SEPARATOR;
324 - else ff->separators[i] = PF_CHAR_IS_WORD;
325 - }
326 -
327 - if(!separators) separators = " \t=|";
328 - const char *s = separators;
329 - while(*s) ff->separators[(int)*s++] = PF_CHAR_IS_SEPARATOR;
348 + procfile_set_separators(ff, separators);
349
350 debug(D_PROCFILE, "File '%s' opened.", filename);
351 return ff;
352 }
353
335 -procfile *procfile_reopen(procfile *ff, const char *filename, const char *separators) {
336 - if(!ff) return procfile_open(filename, separators);
354 +procfile *procfile_reopen(procfile *ff, const char *filename, const char *separators, uint32_t flags) {
355 + if(!ff) return procfile_open(filename, separators, flags);
356
357 if(ff->fd != -1) close(ff->fd);
358
@@ -346,6 +365,11 @@ procfile *procfile_reopen(procfile *ff, const char *filename, const char *separa
365 strncpy(ff->filename, filename, FILENAME_MAX);
366 ff->filename[FILENAME_MAX] = '\0';
367
368 + ff->flags = flags;
369 +
370 + // do not do the separators again if NULL is given
371 + if(separators) procfile_set_separators(ff, separators);
372 +
373 return ff;
374 }
375
src/procfile.h
+7 -3
@@ -55,8 +55,12 @@ typedef struct {
55 // ----------------------------------------------------------------------------
56 // The procfile
57
58 +#define PROCFILE_FLAG_DEFAULT 0x00000000
59 +#define PROCFILE_FLAG_NO_ERROR_ON_FILE_IO 0x00000001
60 +
61 typedef struct {
62 char filename[FILENAME_MAX + 1];
63 + uint32_t flags;
64 int fd; // the file desriptor
65 size_t len; // the bytes we have placed into data
66 size_t size; // the bytes we have allocated for data
@@ -73,11 +77,11 @@ extern void procfile_close(procfile *ff);
77 extern procfile *procfile_readall(procfile *ff);
78
79 // open a /proc or /sys file
76 -extern procfile *procfile_open(const char *filename, const char *separators);
80 +extern procfile *procfile_open(const char *filename, const char *separators, uint32_t flags);
81
82 // re-open a file
79 -// the separators argument is only used if ff == NULL
80 -extern procfile *procfile_reopen(procfile *ff, const char *filename, const char *separators);
83 +// if separators == NULL, the last separators are used
84 +extern procfile *procfile_reopen(procfile *ff, const char *filename, const char *separators, uint32_t flags);
85
86 // example walk-through a procfile parsed file
87 extern void procfile_print(procfile *ff);