2
3
#include "common.h"
4
5
-#ifdef __APPLE__
6
-#define INHERIT_NONE 0
7
-#endif /* __APPLE__ */
8
-#if defined(__FreeBSD__) || defined(__APPLE__)
9
-# define O_NOATIME 0
10
-# define MADV_DONTFORK INHERIT_NONE
11
-#endif /* __FreeBSD__ || __APPLE__*/
12
-
5
char *netdata_configured_hostname = NULL;
6
char *netdata_configured_user_config_dir = CONFIG_DIR;
7
char *netdata_configured_stock_config_dir = LIBCONFIG_DIR;
14
char *netdata_configured_host_prefix = NULL;
15
char *netdata_configured_timezone = NULL;
16
25
-struct rlimit rlimit_nofile = { .rlim_cur = 1024, .rlim_max = 1024 };
26
-int enable_ksm = 1;
27
-
28
-volatile sig_atomic_t netdata_exit = 0;
29
-const char *os_type = NETDATA_OS_TYPE;
30
-const char *program_version = VERSION;
31
-
32
-// ----------------------------------------------------------------------------
33
-// memory allocation functions that handle failures
34
-
35
-// although netdata does not use memory allocations too often (netdata tries to
36
-// maintain its memory footprint stable during runtime, i.e. all buffers are
37
-// allocated during initialization and are adapted to current use throughout
38
-// its lifetime), these can be used to override the default system allocation
39
-// routines.
40
-
41
-#ifdef NETDATA_LOG_ALLOCATIONS
42
-static struct memory_statistics {
43
- volatile size_t malloc_calls_made;
44
- volatile size_t calloc_calls_made;
45
- volatile size_t realloc_calls_made;
46
- volatile size_t strdup_calls_made;
47
- volatile size_t free_calls_made;
48
- volatile size_t memory_calls_made;
49
- volatile size_t allocated_memory;
50
- volatile size_t mmapped_memory;
51
-} memory_statistics;
52
-
53
-static inline void print_allocations(const char *file, const char *function, const unsigned long line) {
54
- static struct memory_statistics old = { 0, 0, 0, 0, 0, 0, 0, 0 };
55
-
56
- //if(unlikely(!(memory_statistics.memory_calls_made % 5))) {
57
- fprintf(stderr, "(%04lu@%-10.10s:%-15.15s): Allocated %zu KB (+%zu B), mmapped %zu KB (+%zu B): malloc %zu (+%zu), calloc %zu (+%zu), realloc %zu (+%zu), strdup %zu (+%zu), free %zu (+%zu)\n",
58
- line, file, function,
59
- (memory_statistics.allocated_memory + 512) / 1024, memory_statistics.allocated_memory - old.allocated_memory,
60
- (memory_statistics.mmapped_memory + 512) / 1024, memory_statistics.mmapped_memory - old.mmapped_memory,
61
- memory_statistics.malloc_calls_made, memory_statistics.malloc_calls_made - old.malloc_calls_made,
62
- memory_statistics.calloc_calls_made, memory_statistics.calloc_calls_made - old.calloc_calls_made,
63
- memory_statistics.realloc_calls_made, memory_statistics.realloc_calls_made - old.realloc_calls_made,
64
- memory_statistics.strdup_calls_made, memory_statistics.strdup_calls_made - old.strdup_calls_made,
65
- memory_statistics.free_calls_made, memory_statistics.free_calls_made - old.free_calls_made
66
- );
67
-
68
- memcpy(&old, &memory_statistics, sizeof(struct memory_statistics));
69
- //}
70
-}
71
-
72
-static inline void malloc_accounting(const char *file, const char *function, const unsigned long line, size_t size) {
73
-#if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS)
74
- __atomic_fetch_add(&memory_statistics.memory_calls_made, 1, __ATOMIC_SEQ_CST);
75
- __atomic_fetch_add(&memory_statistics.malloc_calls_made, 1, __ATOMIC_SEQ_CST);
76
- __atomic_fetch_add(&memory_statistics.allocated_memory, size, __ATOMIC_SEQ_CST);
77
-#else
78
- // this is for debugging - we don't care locking it
79
- memory_statistics.memory_calls_made++;
80
- memory_statistics.malloc_calls_made++;
81
- memory_statistics.allocated_memory += size;
82
-#endif
83
- print_allocations(file, function, line);
84
-}
85
-
86
-static inline void mmap_accounting(size_t size) {
87
-#if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS)
88
- __atomic_fetch_add(&memory_statistics.malloc_calls_made, 1, __ATOMIC_SEQ_CST);
89
- __atomic_fetch_add(&memory_statistics.mmapped_memory, size, __ATOMIC_SEQ_CST);
90
-#else
91
- // this is for debugging - we don't care locking it
92
- memory_statistics.memory_calls_made++;
93
- memory_statistics.mmapped_memory += size;
94
-#endif
95
-}
96
-
97
-static inline void calloc_accounting(const char *file, const char *function, const unsigned long line, size_t size) {
98
-#if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS)
99
- __atomic_fetch_add(&memory_statistics.memory_calls_made, 1, __ATOMIC_SEQ_CST);
100
- __atomic_fetch_add(&memory_statistics.calloc_calls_made, 1, __ATOMIC_SEQ_CST);
101
- __atomic_fetch_add(&memory_statistics.allocated_memory, size, __ATOMIC_SEQ_CST);
102
-#else
103
- // this is for debugging - we don't care locking it
104
- memory_statistics.memory_calls_made++;
105
- memory_statistics.calloc_calls_made++;
106
- memory_statistics.allocated_memory += size;
107
-#endif
108
- print_allocations(file, function, line);
109
-}
110
-
111
-static inline void realloc_accounting(const char *file, const char *function, const unsigned long line, void *ptr, size_t size) {
112
- (void)ptr;
113
-
114
-#if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS)
115
- __atomic_fetch_add(&memory_statistics.memory_calls_made, 1, __ATOMIC_SEQ_CST);
116
- __atomic_fetch_add(&memory_statistics.realloc_calls_made, 1, __ATOMIC_SEQ_CST);
117
- __atomic_fetch_add(&memory_statistics.allocated_memory, size, __ATOMIC_SEQ_CST);
118
-#else
119
- // this is for debugging - we don't care locking it
120
- memory_statistics.memory_calls_made++;
121
- memory_statistics.realloc_calls_made++;
122
- memory_statistics.allocated_memory += size;
123
-#endif
124
- print_allocations(file, function, line);
125
-}
126
-
127
-static inline void strdup_accounting(const char *file, const char *function, const unsigned long line, const char *s) {
128
- size_t size = strlen(s) + 1;
129
-
130
-#if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS)
131
- __atomic_fetch_add(&memory_statistics.memory_calls_made, 1, __ATOMIC_SEQ_CST);
132
- __atomic_fetch_add(&memory_statistics.strdup_calls_made, 1, __ATOMIC_SEQ_CST);
133
- __atomic_fetch_add(&memory_statistics.allocated_memory, size, __ATOMIC_SEQ_CST);
134
-#else
135
- // this is for debugging - we don't care locking it
136
- memory_statistics.memory_calls_made++;
137
- memory_statistics.strdup_calls_made++;
138
- memory_statistics.allocated_memory += size;
139
-#endif
140
- print_allocations(file, function, line);
141
-}
142
-
143
-static inline void free_accounting(const char *file, const char *function, const unsigned long line, void *ptr) {
144
- (void)file;
145
- (void)function;
146
- (void)line;
147
-
148
- if(likely(ptr)) {
149
-#if defined(HAVE_C___ATOMIC) && !defined(NETDATA_NO_ATOMIC_INSTRUCTIONS)
150
- __atomic_fetch_add(&memory_statistics.memory_calls_made, 1, __ATOMIC_SEQ_CST);
151
- __atomic_fetch_add(&memory_statistics.free_calls_made, 1, __ATOMIC_SEQ_CST);
152
-#else
153
- // this is for debugging - we don't care locking it
154
- memory_statistics.memory_calls_made++;
155
- memory_statistics.free_calls_made++;
156
-#endif
157
- }
158
-}
159
-#endif
160
-
161
-#ifdef NETDATA_LOG_ALLOCATIONS
162
-char *strdupz_int(const char *file, const char *function, const unsigned long line, const char *s) {
163
- strdup_accounting(file, function, line, s);
164
-#else
165
-char *strdupz(const char *s) {
166
-#endif
167
-
168
- char *t = strdup(s);
169
- if (unlikely(!t)) fatal("Cannot strdup() string '%s'", s);
170
- return t;
171
-}
172
-
173
-#ifdef NETDATA_LOG_ALLOCATIONS
174
-void *mallocz_int(const char *file, const char *function, const unsigned long line, size_t size) {
175
- malloc_accounting(file, function, line, size);
176
-#else
177
-void *mallocz(size_t size) {
178
-#endif
179
-
180
- void *p = malloc(size);
181
- if (unlikely(!p)) fatal("Cannot allocate %zu bytes of memory.", size);
182
- return p;
183
-}
184
-
185
-#ifdef NETDATA_LOG_ALLOCATIONS
186
-void *callocz_int(const char *file, const char *function, const unsigned long line, size_t nmemb, size_t size) {
187
- calloc_accounting(file, function, line, nmemb * size);
188
-#else
189
-void *callocz(size_t nmemb, size_t size) {
190
-#endif
191
-
192
- void *p = calloc(nmemb, size);
193
- if (unlikely(!p)) fatal("Cannot allocate %zu bytes of memory.", nmemb * size);
194
- return p;
195
-}
196
-
197
-#ifdef NETDATA_LOG_ALLOCATIONS
198
-void *reallocz_int(const char *file, const char *function, const unsigned long line, void *ptr, size_t size) {
199
- realloc_accounting(file, function, line, ptr, size);
200
-#else
201
-void *reallocz(void *ptr, size_t size) {
202
-#endif
203
-
204
- void *p = realloc(ptr, size);
205
- if (unlikely(!p)) fatal("Cannot re-allocate memory to %zu bytes.", size);
206
- return p;
207
-}
208
-
209
-#ifdef NETDATA_LOG_ALLOCATIONS
210
-void freez_int(const char *file, const char *function, const unsigned long line, void *ptr) {
211
- free_accounting(file, function, line, ptr);
212
-#else
213
-void freez(void *ptr) {
214
-#endif
215
-
216
- free(ptr);
217
-}
218
-
219
-void json_escape_string(char *dst, const char *src, size_t size) {
220
- const char *t;
221
- char *d = dst, *e = &dst[size - 1];
222
-
223
- for(t = src; *t && d < e ;t++) {
224
- if(unlikely(*t == '\\' || *t == '"')) {
225
- if(unlikely(d + 1 >= e)) break;
226
- *d++ = '\\';
227
- }
228
- *d++ = *t;
229
- }
230
-
231
- *d = '\0';
232
-}
233
-
234
-void json_fix_string(char *s) {
235
- unsigned char c;
236
- while((c = (unsigned char)*s)) {
237
- if(unlikely(c == '\\'))
238
- *s++ = '/';
239
- else if(unlikely(c == '"'))
240
- *s++ = '\'';
241
- else if(unlikely(isspace(c) || iscntrl(c)))
242
- *s++ = ' ';
243
- else if(unlikely(!isprint(c) || c > 127))
244
- *s++ = '_';
245
- else
246
- s++;
247
- }
248
-}
249
-
250
-int sleep_usec(usec_t usec) {
251
-
252
-#ifndef NETDATA_WITH_USLEEP
253
- // we expect microseconds (1.000.000 per second)
254
- // but timespec is nanoseconds (1.000.000.000 per second)
255
- struct timespec rem, req = {
256
- .tv_sec = (time_t) (usec / 1000000),
257
- .tv_nsec = (suseconds_t) ((usec % 1000000) * 1000)
258
- };
259
-
260
- while (nanosleep(&req, &rem) == -1) {
261
- if (likely(errno == EINTR)) {
262
- debug(D_SYSTEM, "nanosleep() interrupted (while sleeping for %llu microseconds).", usec);
263
- req.tv_sec = rem.tv_sec;
264
- req.tv_nsec = rem.tv_nsec;
265
- } else {
266
- error("Cannot nanosleep() for %llu microseconds.", usec);
267
- break;
268
- }
269
- }
270
-
271
- return 0;
272
-#else
273
- int ret = usleep(usec);
274
- if(unlikely(ret == -1 && errno == EINVAL)) {
275
- // on certain systems, usec has to be up to 999999
276
- if(usec > 999999) {
277
- int counter = usec / 999999;
278
- while(counter--)
279
- usleep(999999);
280
-
281
- usleep(usec % 999999);
282
- }
283
- else {
284
- error("Cannot usleep() for %llu microseconds.", usec);
285
- return ret;
286
- }
287
- }
288
-
289
- if(ret != 0)
290
- error("usleep() failed for %llu microseconds.", usec);
291
-
292
- return ret;
293
-#endif
294
-}
295
-
296
-unsigned char netdata_map_chart_names[256] = {
297
- [0] = '\0', //
298
- [1] = '_', //
299
- [2] = '_', //
300
- [3] = '_', //
301
- [4] = '_', //
302
- [5] = '_', //
303
- [6] = '_', //
304
- [7] = '_', //
305
- [8] = '_', //
306
- [9] = '_', //
307
- [10] = '_', //
308
- [11] = '_', //
309
- [12] = '_', //
310
- [13] = '_', //
311
- [14] = '_', //
312
- [15] = '_', //
313
- [16] = '_', //
314
- [17] = '_', //
315
- [18] = '_', //
316
- [19] = '_', //
317
- [20] = '_', //
318
- [21] = '_', //
319
- [22] = '_', //
320
- [23] = '_', //
321
- [24] = '_', //
322
- [25] = '_', //
323
- [26] = '_', //
324
- [27] = '_', //
325
- [28] = '_', //
326
- [29] = '_', //
327
- [30] = '_', //
328
- [31] = '_', //
329
- [32] = '_', //
330
- [33] = '_', // !
331
- [34] = '_', // "
332
- [35] = '_', // #
333
- [36] = '_', // $
334
- [37] = '_', // %
335
- [38] = '_', // &
336
- [39] = '_', // '
337
- [40] = '_', // (
338
- [41] = '_', // )
339
- [42] = '_', // *
340
- [43] = '_', // +
341
- [44] = '.', // ,
342
- [45] = '-', // -
343
- [46] = '.', // .
344
- [47] = '/', // /
345
- [48] = '0', // 0
346
- [49] = '1', // 1
347
- [50] = '2', // 2
348
- [51] = '3', // 3
349
- [52] = '4', // 4
350
- [53] = '5', // 5
351
- [54] = '6', // 6
352
- [55] = '7', // 7
353
- [56] = '8', // 8
354
- [57] = '9', // 9
355
- [58] = '_', // :
356
- [59] = '_', // ;
357
- [60] = '_', // <
358
- [61] = '_', // =
359
- [62] = '_', // >
360
- [63] = '_', // ?
361
- [64] = '_', // @
362
- [65] = 'a', // A
363
- [66] = 'b', // B
364
- [67] = 'c', // C
365
- [68] = 'd', // D
366
- [69] = 'e', // E
367
- [70] = 'f', // F
368
- [71] = 'g', // G
369
- [72] = 'h', // H
370
- [73] = 'i', // I
371
- [74] = 'j', // J
372
- [75] = 'k', // K
373
- [76] = 'l', // L
374
- [77] = 'm', // M
375
- [78] = 'n', // N
376
- [79] = 'o', // O
377
- [80] = 'p', // P
378
- [81] = 'q', // Q
379
- [82] = 'r', // R
380
- [83] = 's', // S
381
- [84] = 't', // T
382
- [85] = 'u', // U
383
- [86] = 'v', // V
384
- [87] = 'w', // W
385
- [88] = 'x', // X
386
- [89] = 'y', // Y
387
- [90] = 'z', // Z
388
- [91] = '_', // [
389
- [92] = '/', // backslash
390
- [93] = '_', // ]
391
- [94] = '_', // ^
392
- [95] = '_', // _
393
- [96] = '_', // `
394
- [97] = 'a', // a
395
- [98] = 'b', // b
396
- [99] = 'c', // c
397
- [100] = 'd', // d
398
- [101] = 'e', // e
399
- [102] = 'f', // f
400
- [103] = 'g', // g
401
- [104] = 'h', // h
402
- [105] = 'i', // i
403
- [106] = 'j', // j
404
- [107] = 'k', // k
405
- [108] = 'l', // l
406
- [109] = 'm', // m
407
- [110] = 'n', // n
408
- [111] = 'o', // o
409
- [112] = 'p', // p
410
- [113] = 'q', // q
411
- [114] = 'r', // r
412
- [115] = 's', // s
413
- [116] = 't', // t
414
- [117] = 'u', // u
415
- [118] = 'v', // v
416
- [119] = 'w', // w
417
- [120] = 'x', // x
418
- [121] = 'y', // y
419
- [122] = 'z', // z
420
- [123] = '_', // {
421
- [124] = '_', // |
422
- [125] = '_', // }
423
- [126] = '_', // ~
424
- [127] = '_', //
425
- [128] = '_', //
426
- [129] = '_', //
427
- [130] = '_', //
428
- [131] = '_', //
429
- [132] = '_', //
430
- [133] = '_', //
431
- [134] = '_', //
432
- [135] = '_', //
433
- [136] = '_', //
434
- [137] = '_', //
435
- [138] = '_', //
436
- [139] = '_', //
437
- [140] = '_', //
438
- [141] = '_', //
439
- [142] = '_', //
440
- [143] = '_', //
441
- [144] = '_', //
442
- [145] = '_', //
443
- [146] = '_', //
444
- [147] = '_', //
445
- [148] = '_', //
446
- [149] = '_', //
447
- [150] = '_', //
448
- [151] = '_', //
449
- [152] = '_', //
450
- [153] = '_', //
451
- [154] = '_', //
452
- [155] = '_', //
453
- [156] = '_', //
454
- [157] = '_', //
455
- [158] = '_', //
456
- [159] = '_', //
457
- [160] = '_', //
458
- [161] = '_', //
459
- [162] = '_', //
460
- [163] = '_', //
461
- [164] = '_', //
462
- [165] = '_', //
463
- [166] = '_', //
464
- [167] = '_', //
465
- [168] = '_', //
466
- [169] = '_', //
467
- [170] = '_', //
468
- [171] = '_', //
469
- [172] = '_', //
470
- [173] = '_', //
471
- [174] = '_', //
472
- [175] = '_', //
473
- [176] = '_', //
474
- [177] = '_', //
475
- [178] = '_', //
476
- [179] = '_', //
477
- [180] = '_', //
478
- [181] = '_', //
479
- [182] = '_', //
480
- [183] = '_', //
481
- [184] = '_', //
482
- [185] = '_', //
483
- [186] = '_', //
484
- [187] = '_', //
485
- [188] = '_', //
486
- [189] = '_', //
487
- [190] = '_', //
488
- [191] = '_', //
489
- [192] = '_', //
490
- [193] = '_', //
491
- [194] = '_', //
492
- [195] = '_', //
493
- [196] = '_', //
494
- [197] = '_', //
495
- [198] = '_', //
496
- [199] = '_', //
497
- [200] = '_', //
498
- [201] = '_', //
499
- [202] = '_', //
500
- [203] = '_', //
501
- [204] = '_', //
502
- [205] = '_', //
503
- [206] = '_', //
504
- [207] = '_', //
505
- [208] = '_', //
506
- [209] = '_', //
507
- [210] = '_', //
508
- [211] = '_', //
509
- [212] = '_', //
510
- [213] = '_', //
511
- [214] = '_', //
512
- [215] = '_', //
513
- [216] = '_', //
514
- [217] = '_', //
515
- [218] = '_', //
516
- [219] = '_', //
517
- [220] = '_', //
518
- [221] = '_', //
519
- [222] = '_', //
520
- [223] = '_', //
521
- [224] = '_', //
522
- [225] = '_', //
523
- [226] = '_', //
524
- [227] = '_', //
525
- [228] = '_', //
526
- [229] = '_', //
527
- [230] = '_', //
528
- [231] = '_', //
529
- [232] = '_', //
530
- [233] = '_', //
531
- [234] = '_', //
532
- [235] = '_', //
533
- [236] = '_', //
534
- [237] = '_', //
535
- [238] = '_', //
536
- [239] = '_', //
537
- [240] = '_', //
538
- [241] = '_', //
539
- [242] = '_', //
540
- [243] = '_', //
541
- [244] = '_', //
542
- [245] = '_', //
543
- [246] = '_', //
544
- [247] = '_', //
545
- [248] = '_', //
546
- [249] = '_', //
547
- [250] = '_', //
548
- [251] = '_', //
549
- [252] = '_', //
550
- [253] = '_', //
551
- [254] = '_', //
552
- [255] = '_' //
553
-};
554
-
555
-// make sure the supplied string
556
-// is good for a netdata chart/dimension ID/NAME
557
-void netdata_fix_chart_name(char *s) {
558
- while ((*s = netdata_map_chart_names[(unsigned char) *s])) s++;
559
-}
560
-
561
-unsigned char netdata_map_chart_ids[256] = {
562
- [0] = '\0', //
563
- [1] = '_', //
564
- [2] = '_', //
565
- [3] = '_', //
566
- [4] = '_', //
567
- [5] = '_', //
568
- [6] = '_', //
569
- [7] = '_', //
570
- [8] = '_', //
571
- [9] = '_', //
572
- [10] = '_', //
573
- [11] = '_', //
574
- [12] = '_', //
575
- [13] = '_', //
576
- [14] = '_', //
577
- [15] = '_', //
578
- [16] = '_', //
579
- [17] = '_', //
580
- [18] = '_', //
581
- [19] = '_', //
582
- [20] = '_', //
583
- [21] = '_', //
584
- [22] = '_', //
585
- [23] = '_', //
586
- [24] = '_', //
587
- [25] = '_', //
588
- [26] = '_', //
589
- [27] = '_', //
590
- [28] = '_', //
591
- [29] = '_', //
592
- [30] = '_', //
593
- [31] = '_', //
594
- [32] = '_', //
595
- [33] = '_', // !
596
- [34] = '_', // "
597
- [35] = '_', // #
598
- [36] = '_', // $
599
- [37] = '_', // %
600
- [38] = '_', // &
601
- [39] = '_', // '
602
- [40] = '_', // (
603
- [41] = '_', // )
604
- [42] = '_', // *
605
- [43] = '_', // +
606
- [44] = '.', // ,
607
- [45] = '-', // -
608
- [46] = '.', // .
609
- [47] = '_', // /
610
- [48] = '0', // 0
611
- [49] = '1', // 1
612
- [50] = '2', // 2
613
- [51] = '3', // 3
614
- [52] = '4', // 4
615
- [53] = '5', // 5
616
- [54] = '6', // 6
617
- [55] = '7', // 7
618
- [56] = '8', // 8
619
- [57] = '9', // 9
620
- [58] = '_', // :
621
- [59] = '_', // ;
622
- [60] = '_', // <
623
- [61] = '_', // =
624
- [62] = '_', // >
625
- [63] = '_', // ?
626
- [64] = '_', // @
627
- [65] = 'a', // A
628
- [66] = 'b', // B
629
- [67] = 'c', // C
630
- [68] = 'd', // D
631
- [69] = 'e', // E
632
- [70] = 'f', // F
633
- [71] = 'g', // G
634
- [72] = 'h', // H
635
- [73] = 'i', // I
636
- [74] = 'j', // J
637
- [75] = 'k', // K
638
- [76] = 'l', // L
639
- [77] = 'm', // M
640
- [78] = 'n', // N
641
- [79] = 'o', // O
642
- [80] = 'p', // P
643
- [81] = 'q', // Q
644
- [82] = 'r', // R
645
- [83] = 's', // S
646
- [84] = 't', // T
647
- [85] = 'u', // U
648
- [86] = 'v', // V
649
- [87] = 'w', // W
650
- [88] = 'x', // X
651
- [89] = 'y', // Y
652
- [90] = 'z', // Z
653
- [91] = '_', // [
654
- [92] = '/', // backslash
655
- [93] = '_', // ]
656
- [94] = '_', // ^
657
- [95] = '_', // _
658
- [96] = '_', // `
659
- [97] = 'a', // a
660
- [98] = 'b', // b
661
- [99] = 'c', // c
662
- [100] = 'd', // d
663
- [101] = 'e', // e
664
- [102] = 'f', // f
665
- [103] = 'g', // g
666
- [104] = 'h', // h
667
- [105] = 'i', // i
668
- [106] = 'j', // j
669
- [107] = 'k', // k
670
- [108] = 'l', // l
671
- [109] = 'm', // m
672
- [110] = 'n', // n
673
- [111] = 'o', // o
674
- [112] = 'p', // p
675
- [113] = 'q', // q
676
- [114] = 'r', // r
677
- [115] = 's', // s
678
- [116] = 't', // t
679
- [117] = 'u', // u
680
- [118] = 'v', // v
681
- [119] = 'w', // w
682
- [120] = 'x', // x
683
- [121] = 'y', // y
684
- [122] = 'z', // z
685
- [123] = '_', // {
686
- [124] = '_', // |
687
- [125] = '_', // }
688
- [126] = '_', // ~
689
- [127] = '_', //
690
- [128] = '_', //
691
- [129] = '_', //
692
- [130] = '_', //
693
- [131] = '_', //
694
- [132] = '_', //
695
- [133] = '_', //
696
- [134] = '_', //
697
- [135] = '_', //
698
- [136] = '_', //
699
- [137] = '_', //
700
- [138] = '_', //
701
- [139] = '_', //
702
- [140] = '_', //
703
- [141] = '_', //
704
- [142] = '_', //
705
- [143] = '_', //
706
- [144] = '_', //
707
- [145] = '_', //
708
- [146] = '_', //
709
- [147] = '_', //
710
- [148] = '_', //
711
- [149] = '_', //
712
- [150] = '_', //
713
- [151] = '_', //
714
- [152] = '_', //
715
- [153] = '_', //
716
- [154] = '_', //
717
- [155] = '_', //
718
- [156] = '_', //
719
- [157] = '_', //
720
- [158] = '_', //
721
- [159] = '_', //
722
- [160] = '_', //
723
- [161] = '_', //
724
- [162] = '_', //
725
- [163] = '_', //
726
- [164] = '_', //
727
- [165] = '_', //
728
- [166] = '_', //
729
- [167] = '_', //
730
- [168] = '_', //
731
- [169] = '_', //
732
- [170] = '_', //
733
- [171] = '_', //
734
- [172] = '_', //
735
- [173] = '_', //
736
- [174] = '_', //
737
- [175] = '_', //
738
- [176] = '_', //
739
- [177] = '_', //
740
- [178] = '_', //
741
- [179] = '_', //
742
- [180] = '_', //
743
- [181] = '_', //
744
- [182] = '_', //
745
- [183] = '_', //
746
- [184] = '_', //
747
- [185] = '_', //
748
- [186] = '_', //
749
- [187] = '_', //
750
- [188] = '_', //
751
- [189] = '_', //
752
- [190] = '_', //
753
- [191] = '_', //
754
- [192] = '_', //
755
- [193] = '_', //
756
- [194] = '_', //
757
- [195] = '_', //
758
- [196] = '_', //
759
- [197] = '_', //
760
- [198] = '_', //
761
- [199] = '_', //
762
- [200] = '_', //
763
- [201] = '_', //
764
- [202] = '_', //
765
- [203] = '_', //
766
- [204] = '_', //
767
- [205] = '_', //
768
- [206] = '_', //
769
- [207] = '_', //
770
- [208] = '_', //
771
- [209] = '_', //
772
- [210] = '_', //
773
- [211] = '_', //
774
- [212] = '_', //
775
- [213] = '_', //
776
- [214] = '_', //
777
- [215] = '_', //
778
- [216] = '_', //
779
- [217] = '_', //
780
- [218] = '_', //
781
- [219] = '_', //
782
- [220] = '_', //
783
- [221] = '_', //
784
- [222] = '_', //
785
- [223] = '_', //
786
- [224] = '_', //
787
- [225] = '_', //
788
- [226] = '_', //
789
- [227] = '_', //
790
- [228] = '_', //
791
- [229] = '_', //
792
- [230] = '_', //
793
- [231] = '_', //
794
- [232] = '_', //
795
- [233] = '_', //
796
- [234] = '_', //
797
- [235] = '_', //
798
- [236] = '_', //
799
- [237] = '_', //
800
- [238] = '_', //
801
- [239] = '_', //
802
- [240] = '_', //
803
- [241] = '_', //
804
- [242] = '_', //
805
- [243] = '_', //
806
- [244] = '_', //
807
- [245] = '_', //
808
- [246] = '_', //
809
- [247] = '_', //
810
- [248] = '_', //
811
- [249] = '_', //
812
- [250] = '_', //
813
- [251] = '_', //
814
- [252] = '_', //
815
- [253] = '_', //
816
- [254] = '_', //
817
- [255] = '_' //
818
-};
819
-
820
-// make sure the supplied string
821
-// is good for a netdata chart/dimension ID/NAME
822
-void netdata_fix_chart_id(char *s) {
823
- while ((*s = netdata_map_chart_ids[(unsigned char) *s])) s++;
824
-}
825
-
826
-/*
827
-// http://stackoverflow.com/questions/7666509/hash-function-for-string
828
-uint32_t simple_hash(const char *name)
829
-{
830
- const char *s = name;
831
- uint32_t hash = 5381;
832
- int i;
833
-
834
- while((i = *s++)) hash = ((hash << 5) + hash) + i;
835
-
836
- // fprintf(stderr, "HASH: %lu %s\n", hash, name);
837
-
838
- return hash;
839
-}
840
-*/
841
-
842
-/*
843
-// http://isthe.com/chongo/tech/comp/fnv/#FNV-1a
844
-uint32_t simple_hash(const char *name) {
845
- unsigned char *s = (unsigned char *) name;
846
- uint32_t hval = 0x811c9dc5;
847
-
848
- // FNV-1a algorithm
849
- while (*s) {
850
- // multiply by the 32 bit FNV magic prime mod 2^32
851
- // NOTE: No need to optimize with left shifts.
852
- // GCC will use imul instruction anyway.
853
- // Tested with 'gcc -O3 -S'
854
- //hval += (hval<<1) + (hval<<4) + (hval<<7) + (hval<<8) + (hval<<24);
855
- hval *= 16777619;
856
-
857
- // xor the bottom with the current octet
858
- hval ^= (uint32_t) *s++;
859
- }
860
-
861
- // fprintf(stderr, "HASH: %u = %s\n", hval, name);
862
- return hval;
863
-}
864
-
865
-uint32_t simple_uhash(const char *name) {
866
- unsigned char *s = (unsigned char *) name;
867
- uint32_t hval = 0x811c9dc5, c;
868
-
869
- // FNV-1a algorithm
870
- while ((c = *s++)) {
871
- if (unlikely(c >= 'A' && c <= 'Z')) c += 'a' - 'A';
872
- hval *= 16777619;
873
- hval ^= c;
874
- }
875
- return hval;
876
-}
877
-*/
878
-
879
-/*
880
-// http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx
881
-// one at a time hash
882
-uint32_t simple_hash(const char *name) {
883
- unsigned char *s = (unsigned char *)name;
884
- uint32_t h = 0;
885
-
886
- while(*s) {
887
- h += *s++;
888
- h += (h << 10);
889
- h ^= (h >> 6);
890
- }
891
-
892
- h += (h << 3);
893
- h ^= (h >> 11);
894
- h += (h << 15);
895
-
896
- // fprintf(stderr, "HASH: %u = %s\n", h, name);
897
-
898
- return h;
899
-}
900
-*/
901
-
902
-void strreverse(char *begin, char *end) {
903
- while (end > begin) {
904
- // clearer code.
905
- char aux = *end;
906
- *end-- = *begin;
907
- *begin++ = aux;
908
- }
909
-}
910
-
911
-char *strsep_on_1char(char **ptr, char c) {
912
- if(unlikely(!ptr || !*ptr))
913
- return NULL;
914
-
915
- // remember the position we started
916
- char *s = *ptr;
917
-
918
- // skip separators in front
919
- while(*s == c) s++;
920
- char *ret = s;
921
-
922
- // find the next separator
923
- while(*s++) {
924
- if(unlikely(*s == c)) {
925
- *s++ = '\0';
926
- *ptr = s;
927
- return ret;
928
- }
929
- }
930
-
931
- *ptr = NULL;
932
- return ret;
933
-}
934
-
935
-char *mystrsep(char **ptr, char *s) {
936
- char *p = "";
937
- while (p && !p[0] && *ptr) p = strsep(ptr, s);
938
- return (p);
939
-}
940
-
941
-char *trim(char *s) {
942
- // skip leading spaces
943
- while (*s && isspace(*s)) s++;
944
- if (!*s) return NULL;
945
-
946
- // skip tailing spaces
947
- // this way is way faster. Writes only one NUL char.
948
- ssize_t l = strlen(s);
949
- if (--l >= 0) {
950
- char *p = s + l;
951
- while (p > s && isspace(*p)) p--;
952
- *++p = '\0';
953
- }
954
-
955
- if (!*s) return NULL;
956
-
957
- return s;
958
-}
959
-
960
-inline char *trim_all(char *buffer) {
961
- char *d = buffer, *s = buffer;
962
-
963
- // skip spaces
964
- while(isspace(*s)) s++;
965
-
966
- while(*s) {
967
- // copy the non-space part
968
- while(*s && !isspace(*s)) *d++ = *s++;
969
-
970
- // add a space if we have to
971
- if(*s && isspace(*s)) {
972
- *d++ = ' ';
973
- s++;
974
- }
975
-
976
- // skip spaces
977
- while(isspace(*s)) s++;
978
- }
979
-
980
- *d = '\0';
981
-
982
- if(d > buffer) {
983
- d--;
984
- if(isspace(*d)) *d = '\0';
985
- }
986
-
987
- if(!buffer[0]) return NULL;
988
- return buffer;
989
-}
990
-
991
-static int memory_file_open(const char *filename, size_t size) {
992
- // info("memory_file_open('%s', %zu", filename, size);
993
-
994
- int fd = open(filename, O_RDWR | O_CREAT | O_NOATIME, 0664);
995
- if (fd != -1) {
996
- if (lseek(fd, size, SEEK_SET) == (off_t) size) {
997
- if (write(fd, "", 1) == 1) {
998
- if (ftruncate(fd, size))
999
- error("Cannot truncate file '%s' to size %zu. Will use the larger file.", filename, size);
1000
- }
1001
- else error("Cannot write to file '%s' at position %zu.", filename, size);
1002
- }
1003
- else error("Cannot seek file '%s' to size %zu.", filename, size);
1004
- }
1005
- else error("Cannot create/open file '%s'.", filename);
1006
-
1007
- return fd;
1008
-}
1009
-
1010
-// mmap_shared is used for memory mode = map
1011
-static void *memory_file_mmap(const char *filename, size_t size, int flags) {
1012
- // info("memory_file_mmap('%s', %zu", filename, size);
1013
- static int log_madvise = 1;
1014
-
1015
- int fd = -1;
1016
- if(filename) {
1017
- fd = memory_file_open(filename, size);
1018
- if(fd == -1) return MAP_FAILED;
1019
- }
1020
-
1021
- void *mem = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, fd, 0);
1022
- if (mem != MAP_FAILED) {
1023
-#ifdef NETDATA_LOG_ALLOCATIONS
1024
- mmap_accounting(size);
1025
-#endif
1026
- int advise = MADV_SEQUENTIAL | MADV_DONTFORK;
1027
- if (flags & MAP_SHARED) advise |= MADV_WILLNEED;
1028
-
1029
- if (madvise(mem, size, advise) != 0 && log_madvise) {
1030
- error("Cannot advise the kernel about shared memory usage.");
1031
- log_madvise--;
1032
- }
1033
- }
1034
-
1035
- if(fd != -1)
1036
- close(fd);
1037
-
1038
- return mem;
1039
-}
1040
-
1041
-#ifdef MADV_MERGEABLE
1042
-static void *memory_file_mmap_ksm(const char *filename, size_t size, int flags) {
1043
- // info("memory_file_mmap_ksm('%s', %zu", filename, size);
1044
- static int log_madvise_2 = 1, log_madvise_3 = 1;
1045
-
1046
- int fd = -1;
1047
- if(filename) {
1048
- fd = memory_file_open(filename, size);
1049
- if(fd == -1) return MAP_FAILED;
1050
- }
1051
-
1052
- void *mem = mmap(NULL, size, PROT_READ | PROT_WRITE, flags | MAP_ANONYMOUS, -1, 0);
1053
- if (mem != MAP_FAILED) {
1054
-#ifdef NETDATA_LOG_ALLOCATIONS
1055
- mmap_accounting(size);
1056
-#endif
1057
- if(fd != -1) {
1058
- if (lseek(fd, 0, SEEK_SET) == 0) {
1059
- if (read(fd, mem, size) != (ssize_t) size)
1060
- error("Cannot read from file '%s'", filename);
1061
- }
1062
- else error("Cannot seek to beginning of file '%s'.", filename);
1063
- }
1064
-
1065
- // don't use MADV_SEQUENTIAL|MADV_DONTFORK, they disable MADV_MERGEABLE
1066
- if (madvise(mem, size, MADV_SEQUENTIAL | MADV_DONTFORK) != 0 && log_madvise_2) {
1067
- error("Cannot advise the kernel about the memory usage (MADV_SEQUENTIAL|MADV_DONTFORK) of file '%s'.", filename);
1068
- log_madvise_2--;
1069
- }
1070
-
1071
- if (madvise(mem, size, MADV_MERGEABLE) != 0 && log_madvise_3) {
1072
- error("Cannot advise the kernel about the memory usage (MADV_MERGEABLE) of file '%s'.", filename);
1073
- log_madvise_3--;
1074
- }
1075
- }
1076
-
1077
- if(fd != -1)
1078
- close(fd);
1079
-
1080
- return mem;
1081
-}
1082
-#else
1083
-static void *memory_file_mmap_ksm(const char *filename, size_t size, int flags) {
1084
- // info("memory_file_mmap_ksm FALLBACK ('%s', %zu", filename, size);
1085
-
1086
- if(filename)
1087
- return memory_file_mmap(filename, size, flags);
1088
-
1089
- // when KSM is not available and no filename is given (memory mode = ram),
1090
- // we just report failure
1091
- return MAP_FAILED;
1092
-}
1093
-#endif
1094
-
1095
-void *mymmap(const char *filename, size_t size, int flags, int ksm) {
1096
- void *mem = NULL;
1097
-
1098
- if (filename && (flags & MAP_SHARED || !enable_ksm || !ksm))
1099
- // memory mode = map | save
1100
- // when KSM is not enabled
1101
- // MAP_SHARED is used for memory mode = map (no KSM possible)
1102
- mem = memory_file_mmap(filename, size, flags);
1103
-
1104
- else
1105
- // memory mode = save | ram
1106
- // when KSM is enabled
1107
- // for memory mode = ram, the filename is NULL
1108
- mem = memory_file_mmap_ksm(filename, size, flags);
1109
-
1110
- if(mem == MAP_FAILED) return NULL;
1111
-
1112
- errno = 0;
1113
- return mem;
1114
-}
1115
-
1116
-int memory_file_save(const char *filename, void *mem, size_t size) {
1117
- char tmpfilename[FILENAME_MAX + 1];
1118
-
1119
- snprintfz(tmpfilename, FILENAME_MAX, "%s.%ld.tmp", filename, (long) getpid());
1120
-
1121
- int fd = open(tmpfilename, O_RDWR | O_CREAT | O_NOATIME, 0664);
1122
- if (fd < 0) {
1123
- error("Cannot create/open file '%s'.", filename);
1124
- return -1;
1125
- }
1126
-
1127
- if (write(fd, mem, size) != (ssize_t) size) {
1128
- error("Cannot write to file '%s' %ld bytes.", filename, (long) size);
1129
- close(fd);
1130
- return -1;
1131
- }
1132
-
1133
- close(fd);
1134
-
1135
- if (rename(tmpfilename, filename)) {
1136
- error("Cannot rename '%s' to '%s'", tmpfilename, filename);
1137
- return -1;
1138
- }
1139
-
1140
- return 0;
1141
-}
1142
-
1143
-int fd_is_valid(int fd) {
1144
- return fcntl(fd, F_GETFD) != -1 || errno != EBADF;
1145
-}
1146
-
1147
-char *fgets_trim_len(char *buf, size_t buf_size, FILE *fp, size_t *len) {
1148
- char *s = fgets(buf, (int)buf_size, fp);
1149
- if (!s) return NULL;
1150
-
1151
- char *t = s;
1152
- if (*t != '\0') {
1153
- // find the string end
1154
- while (*++t != '\0');
1155
-
1156
- // trim trailing spaces/newlines/tabs
1157
- while (--t > s && *t == '\n')
1158
- *t = '\0';
1159
- }
1160
-
1161
- if (len)
1162
- *len = t - s + 1;
1163
-
1164
- return s;
1165
-}
1166
-
1167
-int vsnprintfz(char *dst, size_t n, const char *fmt, va_list args) {
1168
- int size = vsnprintf(dst, n, fmt, args);
1169
-
1170
- if (unlikely((size_t) size > n)) {
1171
- // truncated
1172
- size = (int)n;
1173
- }
1174
-
1175
- dst[size] = '\0';
1176
- return size;
1177
-}
1178
-
1179
-int snprintfz(char *dst, size_t n, const char *fmt, ...) {
1180
- va_list args;
1181
-
1182
- va_start(args, fmt);
1183
- int ret = vsnprintfz(dst, n, fmt, args);
1184
- va_end(args);
1185
-
1186
- return ret;
1187
-}
1188
-
1189
-// ----------------------------------------------------------------------------
1190
-// system functions
1191
-// to retrieve settings of the system
1192
-
1193
-int processors = 1;
1194
-long get_system_cpus(void) {
1195
- processors = 1;
1196
-
1197
- #ifdef __APPLE__
1198
- int32_t tmp_processors;
1199
-
1200
- if (unlikely(GETSYSCTL_BY_NAME("hw.logicalcpu", tmp_processors))) {
1201
- error("Assuming system has %d processors.", processors);
1202
- } else {
1203
- processors = tmp_processors;
1204
- }
1205
-
1206
- return processors;
1207
- #elif __FreeBSD__
1208
- int32_t tmp_processors;
1209
-
1210
- if (unlikely(GETSYSCTL_BY_NAME("hw.ncpu", tmp_processors))) {
1211
- error("Assuming system has %d processors.", processors);
1212
- } else {
1213
- processors = tmp_processors;
1214
- }
1215
-
1216
- return processors;
1217
- #else
1218
-
1219
- char filename[FILENAME_MAX + 1];
1220
- snprintfz(filename, FILENAME_MAX, "%s/proc/stat", netdata_configured_host_prefix);
1221
-
1222
- procfile *ff = procfile_open(filename, NULL, PROCFILE_FLAG_DEFAULT);
1223
- if(!ff) {
1224
- error("Cannot open file '%s'. Assuming system has %d processors.", filename, processors);
1225
- return processors;
1226
- }
1227
-
1228
- ff = procfile_readall(ff);
1229
- if(!ff) {
1230
- error("Cannot open file '%s'. Assuming system has %d processors.", filename, processors);
1231
- return processors;
1232
- }
1233
-
1234
- processors = 0;
1235
- unsigned int i;
1236
- for(i = 0; i < procfile_lines(ff); i++) {
1237
- if(!procfile_linewords(ff, i)) continue;
1238
-
1239
- if(strncmp(procfile_lineword(ff, i, 0), "cpu", 3) == 0) processors++;
1240
- }
1241
- processors--;
1242
- if(processors < 1) processors = 1;
1243
-
1244
- procfile_close(ff);
1245
-
1246
- debug(D_SYSTEM, "System has %d processors.", processors);
1247
- return processors;
1248
-
1249
- #endif /* __APPLE__, __FreeBSD__ */
1250
-}
1251
-
1252
-pid_t pid_max = 32768;
1253
-pid_t get_system_pid_max(void) {
1254
- #ifdef __APPLE__
1255
- // As we currently do not know a solution to query pid_max from the os
1256
- // we use the number defined in bsd/sys/proc_internal.h in XNU sources
1257
- pid_max = 99999;
1258
- return pid_max;
1259
- #elif __FreeBSD__
1260
- int32_t tmp_pid_max;
1261
-
1262
- if (unlikely(GETSYSCTL_BY_NAME("kern.pid_max", tmp_pid_max))) {
1263
- pid_max = 99999;
1264
- error("Assuming system's maximum pid is %d.", pid_max);
1265
- } else {
1266
- pid_max = tmp_pid_max;
1267
- }
1268
-
1269
- return pid_max;
1270
- #else
1271
-
1272
- static char read = 0;
1273
- if(unlikely(read)) return pid_max;
1274
- read = 1;
1275
-
1276
- char filename[FILENAME_MAX + 1];
1277
- snprintfz(filename, FILENAME_MAX, "%s/proc/sys/kernel/pid_max", netdata_configured_host_prefix);
1278
-
1279
- unsigned long long max = 0;
1280
- if(read_single_number_file(filename, &max) != 0) {
1281
- error("Cannot open file '%s'. Assuming system supports %d pids.", filename, pid_max);
1282
- return pid_max;
1283
- }
1284
-
1285
- if(!max) {
1286
- error("Cannot parse file '%s'. Assuming system supports %d pids.", filename, pid_max);
1287
- return pid_max;
1288
- }
1289
-
1290
- pid_max = (pid_t) max;
1291
- return pid_max;
1292
-
1293
- #endif /* __APPLE__, __FreeBSD__ */
1294
-}
1295
-
1296
-unsigned int system_hz;
1297
-void get_system_HZ(void) {
1298
- long ticks;
1299
-
1300
- if ((ticks = sysconf(_SC_CLK_TCK)) == -1) {
1301
- error("Cannot get system clock ticks");
1302
- }
1303
-
1304
- system_hz = (unsigned int) ticks;
1305
-}
1306
-
1307
-/*
1308
-// poor man cycle counting
1309
-static unsigned long tsc;
1310
-void begin_tsc(void) {
1311
- unsigned long a, d;
1312
- asm volatile ("cpuid\nrdtsc" : "=a" (a), "=d" (d) : "0" (0) : "ebx", "ecx");
1313
- tsc = ((unsigned long)d << 32) | (unsigned long)a;
1314
-}
1315
-unsigned long end_tsc(void) {
1316
- unsigned long a, d;
1317
- asm volatile ("rdtscp" : "=a" (a), "=d" (d) : : "ecx");
1318
- return (((unsigned long)d << 32) | (unsigned long)a) - tsc;
1319
-}
1320
-*/
1321
-
1322
-int recursively_delete_dir(const char *path, const char *reason) {
1323
- DIR *dir = opendir(path);
1324
- if(!dir) {
1325
- error("Cannot read %s directory to be deleted '%s'", reason?reason:"", path);
1326
- return -1;
1327
- }
1328
-
1329
- int ret = 0;
1330
- struct dirent *de = NULL;
1331
- while((de = readdir(dir))) {
1332
- if(de->d_type == DT_DIR
1333
- && (
1334
- (de->d_name[0] == '.' && de->d_name[1] == '\0')
1335
- || (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')
1336
- ))
1337
- continue;
1338
-
1339
- char fullpath[FILENAME_MAX + 1];
1340
- snprintfz(fullpath, FILENAME_MAX, "%s/%s", path, de->d_name);
1341
-
1342
- if(de->d_type == DT_DIR) {
1343
- int r = recursively_delete_dir(fullpath, reason);
1344
- if(r > 0) ret += r;
1345
- continue;
1346
- }
1347
-
1348
- info("Deleting %s file '%s'", reason?reason:"", fullpath);
1349
- if(unlikely(unlink(fullpath) == -1))
1350
- error("Cannot delete %s file '%s'", reason?reason:"", fullpath);
1351
- else
1352
- ret++;
1353
- }
1354
-
1355
- info("Deleting empty directory '%s'", path);
1356
- if(unlikely(rmdir(path) == -1))
1357
- error("Cannot delete empty directory '%s'", path);
1358
- else
1359
- ret++;
1360
-
1361
- closedir(dir);
1362
-
1363
- return ret;
1364
-}
1365
-
1366
-static int is_virtual_filesystem(const char *path, char **reason) {
1367
-
1368
-#if defined(__APPLE__) || defined(__FreeBSD__)
1369
- (void)path;
1370
- (void)reason;
1371
-#else
1372
- struct statfs stat;
1373
- // stat.f_fsid.__val[0] is a file system id
1374
- // stat.f_fsid.__val[1] is the inode
1375
- // so their combination uniquely identifies the file/dir
1376
-
1377
- if (statfs(path, &stat) == -1) {
1378
- if(reason) *reason = "failed to statfs()";
1379
- return -1;
1380
- }
1381
-
1382
- if(stat.f_fsid.__val[0] != 0 || stat.f_fsid.__val[1] != 0) {
1383
- errno = EINVAL;
1384
- if(reason) *reason = "is not a virtual file system";
1385
- return -1;
1386
- }
1387
-#endif
1388
-
1389
- return 0;
1390
-}
1391
-
1392
-int verify_netdata_host_prefix() {
1393
- if(!netdata_configured_host_prefix)
1394
- netdata_configured_host_prefix = "";
1395
-
1396
- if(!*netdata_configured_host_prefix)
1397
- return 0;
1398
-
1399
- char buffer[FILENAME_MAX + 1];
1400
- char *path = netdata_configured_host_prefix;
1401
- char *reason = "unknown reason";
1402
- errno = 0;
1403
-
1404
- struct stat sb;
1405
- if (stat(path, &sb) == -1) {
1406
- reason = "failed to stat()";
1407
- goto failed;
1408
- }
1409
-
1410
- if((sb.st_mode & S_IFMT) != S_IFDIR) {
1411
- errno = EINVAL;
1412
- reason = "is not a directory";
1413
- goto failed;
1414
- }
1415
-
1416
- path = buffer;
1417
- snprintfz(path, FILENAME_MAX, "%s/proc", netdata_configured_host_prefix);
1418
- if(is_virtual_filesystem(path, &reason) == -1)
1419
- goto failed;
1420
-
1421
- snprintfz(path, FILENAME_MAX, "%s/sys", netdata_configured_host_prefix);
1422
- if(is_virtual_filesystem(path, &reason) == -1)
1423
- goto failed;
1424
-
1425
- if(netdata_configured_host_prefix && *netdata_configured_host_prefix)
1426
- info("Using host prefix directory '%s'", netdata_configured_host_prefix);
1427
-
1428
- return 0;
1429
-
1430
-failed:
1431
- error("Ignoring host prefix '%s': path '%s' %s", netdata_configured_host_prefix, path, reason);
1432
- netdata_configured_host_prefix = "";
1433
- return -1;
1434
-}
1435
-
1436
-char *strdupz_path_subpath(const char *path, const char *subpath) {
1437
- if(unlikely(!path || !*path)) path = ".";
1438
- if(unlikely(!subpath)) subpath = "";
1439
-
1440
- // skip trailing slashes in path
1441
- size_t len = strlen(path);
1442
- while(len > 0 && path[len - 1] == '/') len--;
1443
-
1444
- // skip leading slashes in subpath
1445
- while(subpath[0] == '/') subpath++;
1446
-
1447
- // if the last character in path is / and (there is a subpath or path is now empty)
1448
- // keep the trailing slash in path and remove the additional slash
1449
- char *slash = "/";
1450
- if(path[len] == '/' && (*subpath || len == 0)) {
1451
- slash = "";
1452
- len++;
1453
- }
1454
- else if(!*subpath) {
1455
- // there is no subpath
1456
- // no need for trailing slash
1457
- slash = "";
1458
- }
1459
-
1460
- char buffer[FILENAME_MAX + 1];
1461
- snprintfz(buffer, FILENAME_MAX, "%.*s%s%s", (int)len, path, slash, subpath);
1462
- return strdupz(buffer);
1463
-}
1464
-
1465
-int path_is_dir(const char *path, const char *subpath) {
1466
- char *s = strdupz_path_subpath(path, subpath);
1467
-
1468
- size_t max_links = 100;
1469
-
1470
- int is_dir = 0;
1471
- struct stat statbuf;
1472
- while(max_links-- && stat(s, &statbuf) == 0) {
1473
- if((statbuf.st_mode & S_IFMT) == S_IFDIR) {
1474
- is_dir = 1;
1475
- break;
1476
- }
1477
- else if((statbuf.st_mode & S_IFMT) == S_IFLNK) {
1478
- char buffer[FILENAME_MAX + 1];
1479
- ssize_t l = readlink(s, buffer, FILENAME_MAX);
1480
- if(l > 0) {
1481
- buffer[l] = '\0';
1482
- freez(s);
1483
- s = strdupz(buffer);
1484
- continue;
1485
- }
1486
- else {
1487
- is_dir = 0;
1488
- break;
1489
- }
1490
- }
1491
- else {
1492
- is_dir = 0;
1493
- break;
1494
- }
1495
- }
1496
-
1497
- freez(s);
1498
- return is_dir;
1499
-}
1500
-
1501
-int path_is_file(const char *path, const char *subpath) {
1502
- char *s = strdupz_path_subpath(path, subpath);
1503
-
1504
- size_t max_links = 100;
1505
-
1506
- int is_file = 0;
1507
- struct stat statbuf;
1508
- while(max_links-- && stat(s, &statbuf) == 0) {
1509
- if((statbuf.st_mode & S_IFMT) == S_IFREG) {
1510
- is_file = 1;
1511
- break;
1512
- }
1513
- else if((statbuf.st_mode & S_IFMT) == S_IFLNK) {
1514
- char buffer[FILENAME_MAX + 1];
1515
- ssize_t l = readlink(s, buffer, FILENAME_MAX);
1516
- if(l > 0) {
1517
- buffer[l] = '\0';
1518
- freez(s);
1519
- s = strdupz(buffer);
1520
- continue;
1521
- }
1522
- else {
1523
- is_file = 0;
1524
- break;
1525
- }
1526
- }
1527
- else {
1528
- is_file = 0;
1529
- break;
1530
- }
1531
- }
1532
-
1533
- freez(s);
1534
- return is_file;
1535
-}
1536
-
1537
-void recursive_config_double_dir_load(const char *user_path, const char *stock_path, const char *subpath, int (*callback)(const char *filename, void *data), void *data, size_t depth) {
1538
- if(depth > 3) {
1539
- error("CONFIG: Max directory depth reached while reading user path '%s', stock path '%s', subpath '%s'", user_path, stock_path, subpath);
1540
- return;
1541
- }
1542
-
1543
- char *udir = strdupz_path_subpath(user_path, subpath);
1544
- char *sdir = strdupz_path_subpath(stock_path, subpath);
1545
-
1546
- debug(D_HEALTH, "CONFIG traversing user-config directory '%s', stock config directory '%s'", udir, sdir);
1547
-
1548
- DIR *dir = opendir(udir);
1549
- if (!dir) {
1550
- error("CONFIG cannot open user-config directory '%s'.", udir);
1551
- }
1552
- else {
1553
- struct dirent *de = NULL;
1554
- while((de = readdir(dir))) {
1555
- if(de->d_type == DT_DIR || de->d_type == DT_LNK) {
1556
- if( !de->d_name[0] ||
1557
- (de->d_name[0] == '.' && de->d_name[1] == '\0') ||
1558
- (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')
1559
- ) {
1560
- debug(D_HEALTH, "CONFIG ignoring user-config directory '%s/%s'", udir, de->d_name);
1561
- continue;
1562
- }
1563
-
1564
- if(path_is_dir(udir, de->d_name)) {
1565
- recursive_config_double_dir_load(udir, sdir, de->d_name, callback, data, depth + 1);
1566
- continue;
1567
- }
1568
- }
1569
-
1570
- if(de->d_type == DT_REG || de->d_type == DT_LNK) {
1571
- size_t len = strlen(de->d_name);
1572
- if(path_is_file(udir, de->d_name) &&
1573
- len > 5 && !strcmp(&de->d_name[len - 5], ".conf")) {
1574
- char *filename = strdupz_path_subpath(udir, de->d_name);
1575
- callback(filename, data);
1576
- freez(filename);
1577
- }
1578
- else
1579
- debug(D_HEALTH, "CONFIG ignoring user-config file '%s/%s'", udir, de->d_name);
1580
- }
1581
- }
1582
-
1583
- closedir(dir);
1584
- }
1585
-
1586
- debug(D_HEALTH, "CONFIG traversing stock config directory '%s', user config directory '%s'", sdir, udir);
1587
-
1588
- dir = opendir(sdir);
1589
- if (!dir) {
1590
- error("CONFIG cannot open stock config directory '%s'.", sdir);
1591
- }
1592
- else {
1593
- struct dirent *de = NULL;
1594
- while((de = readdir(dir))) {
1595
- if(de->d_type == DT_DIR || de->d_type == DT_LNK) {
1596
- if( !de->d_name[0] ||
1597
- (de->d_name[0] == '.' && de->d_name[1] == '\0') ||
1598
- (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')
1599
- ) {
1600
- debug(D_HEALTH, "CONFIG ignoring stock config directory '%s/%s'", sdir, de->d_name);
1601
- continue;
1602
- }
1603
-
1604
- if(path_is_dir(sdir, de->d_name)) {
1605
- // we recurse in stock subdirectory, only when there is no corresponding
1606
- // user subdirectory - to avoid reading the files twice
1607
-
1608
- if(!path_is_dir(udir, de->d_name))
1609
- recursive_config_double_dir_load(udir, sdir, de->d_name, callback, data, depth + 1);
1610
-
1611
- continue;
1612
- }
1613
- }
1614
-
1615
- if(de->d_type == DT_REG || de->d_type == DT_LNK) {
1616
- size_t len = strlen(de->d_name);
1617
- if(path_is_file(sdir, de->d_name) && !path_is_file(udir, de->d_name) &&
1618
- len > 5 && !strcmp(&de->d_name[len - 5], ".conf")) {
1619
- char *filename = strdupz_path_subpath(sdir, de->d_name);
1620
- callback(filename, data);
1621
- freez(filename);
1622
- }
1623
- else
1624
- debug(D_HEALTH, "CONFIG ignoring stock config file '%s/%s'", sdir, de->d_name);
1625
- }
1626
- }
1627
-
1628
- closedir(dir);
1629
- }
1630
-
1631
- freez(udir);
1632
- freez(sdir);
1633
-}