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);