libnetdata.c 39 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "libnetdata.h"
  3. #ifdef __APPLE__
  4. #define INHERIT_NONE 0
  5. #endif /* __APPLE__ */
  6. #if defined(__FreeBSD__) || defined(__APPLE__)
  7. # define O_NOATIME 0
  8. # define MADV_DONTFORK INHERIT_NONE
  9. #endif /* __FreeBSD__ || __APPLE__*/
  10. struct rlimit rlimit_nofile = { .rlim_cur = 1024, .rlim_max = 1024 };
  11. int enable_ksm = 1;
  12. volatile sig_atomic_t netdata_exit = 0;
  13. const char *os_type = NETDATA_OS_TYPE;
  14. const char *program_version = VERSION;
  15. // ----------------------------------------------------------------------------
  16. // memory allocation functions that handle failures
  17. // although netdata does not use memory allocations too often (netdata tries to
  18. // maintain its memory footprint stable during runtime, i.e. all buffers are
  19. // allocated during initialization and are adapted to current use throughout
  20. // its lifetime), these can be used to override the default system allocation
  21. // routines.
  22. #ifdef NETDATA_LOG_ALLOCATIONS
  23. static __thread struct memory_statistics {
  24. volatile ssize_t malloc_calls_made;
  25. volatile ssize_t calloc_calls_made;
  26. volatile ssize_t realloc_calls_made;
  27. volatile ssize_t strdup_calls_made;
  28. volatile ssize_t free_calls_made;
  29. volatile ssize_t memory_calls_made;
  30. volatile ssize_t allocated_memory;
  31. volatile ssize_t mmapped_memory;
  32. } memory_statistics = { 0, 0, 0, 0, 0, 0, 0, 0 };
  33. __thread size_t log_thread_memory_allocations = 0;
  34. static inline void print_allocations(const char *file, const char *function, const unsigned long line, const char *type, size_t size) {
  35. static __thread struct memory_statistics old = { 0, 0, 0, 0, 0, 0, 0, 0 };
  36. fprintf(stderr, "%s iteration %zu MEMORY TRACE: %lu@%s : %s : %s : %zu\n",
  37. netdata_thread_tag(),
  38. log_thread_memory_allocations,
  39. line, file, function,
  40. type, size
  41. );
  42. fprintf(stderr, "%s iteration %zu MEMORY ALLOCATIONS: (%04lu@%-40.40s:%-40.40s): Allocated %zd KB (%+zd B), mmapped %zd KB (%+zd B): %s : malloc %zd (%+zd), calloc %zd (%+zd), realloc %zd (%+zd), strdup %zd (%+zd), free %zd (%+zd)\n",
  43. netdata_thread_tag(),
  44. log_thread_memory_allocations,
  45. line, file, function,
  46. (memory_statistics.allocated_memory + 512) / 1024, memory_statistics.allocated_memory - old.allocated_memory,
  47. (memory_statistics.mmapped_memory + 512) / 1024, memory_statistics.mmapped_memory - old.mmapped_memory,
  48. type,
  49. memory_statistics.malloc_calls_made, memory_statistics.malloc_calls_made - old.malloc_calls_made,
  50. memory_statistics.calloc_calls_made, memory_statistics.calloc_calls_made - old.calloc_calls_made,
  51. memory_statistics.realloc_calls_made, memory_statistics.realloc_calls_made - old.realloc_calls_made,
  52. memory_statistics.strdup_calls_made, memory_statistics.strdup_calls_made - old.strdup_calls_made,
  53. memory_statistics.free_calls_made, memory_statistics.free_calls_made - old.free_calls_made
  54. );
  55. memcpy(&old, &memory_statistics, sizeof(struct memory_statistics));
  56. }
  57. static inline void mmap_accounting(size_t size) {
  58. if(log_thread_memory_allocations) {
  59. memory_statistics.memory_calls_made++;
  60. memory_statistics.mmapped_memory += size;
  61. }
  62. }
  63. void *mallocz_int(const char *file, const char *function, const unsigned long line, size_t size) {
  64. if(log_thread_memory_allocations) {
  65. memory_statistics.memory_calls_made++;
  66. memory_statistics.malloc_calls_made++;
  67. memory_statistics.allocated_memory += size;
  68. print_allocations(file, function, line, "malloc()", size);
  69. }
  70. size_t *n = (size_t *)malloc(sizeof(size_t) + size);
  71. if (unlikely(!n)) fatal("mallocz() cannot allocate %zu bytes of memory.", size);
  72. *n = size;
  73. return (void *)&n[1];
  74. }
  75. void *callocz_int(const char *file, const char *function, const unsigned long line, size_t nmemb, size_t size) {
  76. size = nmemb * size;
  77. if(log_thread_memory_allocations) {
  78. memory_statistics.memory_calls_made++;
  79. memory_statistics.calloc_calls_made++;
  80. memory_statistics.allocated_memory += size;
  81. print_allocations(file, function, line, "calloc()", size);
  82. }
  83. size_t *n = (size_t *)calloc(1, sizeof(size_t) + size);
  84. if (unlikely(!n)) fatal("callocz() cannot allocate %zu bytes of memory.", size);
  85. *n = size;
  86. return (void *)&n[1];
  87. }
  88. void *reallocz_int(const char *file, const char *function, const unsigned long line, void *ptr, size_t size) {
  89. if(!ptr) return mallocz_int(file, function, line, size);
  90. size_t *n = (size_t *)ptr;
  91. n--;
  92. size_t old_size = *n;
  93. n = realloc(n, sizeof(size_t) + size);
  94. if (unlikely(!n)) fatal("reallocz() cannot allocate %zu bytes of memory (from %zu bytes).", size, old_size);
  95. if(log_thread_memory_allocations) {
  96. memory_statistics.memory_calls_made++;
  97. memory_statistics.realloc_calls_made++;
  98. memory_statistics.allocated_memory += (size - old_size);
  99. print_allocations(file, function, line, "realloc()", size - old_size);
  100. }
  101. *n = size;
  102. return (void *)&n[1];
  103. }
  104. char *strdupz_int(const char *file, const char *function, const unsigned long line, const char *s) {
  105. size_t size = strlen(s) + 1;
  106. if(log_thread_memory_allocations) {
  107. memory_statistics.memory_calls_made++;
  108. memory_statistics.strdup_calls_made++;
  109. memory_statistics.allocated_memory += size;
  110. print_allocations(file, function, line, "strdup()", size);
  111. }
  112. size_t *n = (size_t *)malloc(sizeof(size_t) + size);
  113. if (unlikely(!n)) fatal("strdupz() cannot allocate %zu bytes of memory.", size);
  114. *n = size;
  115. char *t = (char *)&n[1];
  116. strcpy(t, s);
  117. return t;
  118. }
  119. void freez_int(const char *file, const char *function, const unsigned long line, void *ptr) {
  120. if(unlikely(!ptr)) return;
  121. size_t *n = (size_t *)ptr;
  122. n--;
  123. size_t size = *n;
  124. if(log_thread_memory_allocations) {
  125. memory_statistics.memory_calls_made++;
  126. memory_statistics.free_calls_made++;
  127. memory_statistics.allocated_memory -= size;
  128. print_allocations(file, function, line, "free()", size);
  129. }
  130. free(n);
  131. }
  132. #else
  133. char *strdupz(const char *s) {
  134. char *t = strdup(s);
  135. if (unlikely(!t)) fatal("Cannot strdup() string '%s'", s);
  136. return t;
  137. }
  138. void freez(void *ptr) {
  139. free(ptr);
  140. }
  141. void *mallocz(size_t size) {
  142. void *p = malloc(size);
  143. if (unlikely(!p)) fatal("Cannot allocate %zu bytes of memory.", size);
  144. return p;
  145. }
  146. void *callocz(size_t nmemb, size_t size) {
  147. void *p = calloc(nmemb, size);
  148. if (unlikely(!p)) fatal("Cannot allocate %zu bytes of memory.", nmemb * size);
  149. return p;
  150. }
  151. void *reallocz(void *ptr, size_t size) {
  152. void *p = realloc(ptr, size);
  153. if (unlikely(!p)) fatal("Cannot re-allocate memory to %zu bytes.", size);
  154. return p;
  155. }
  156. #endif
  157. // --------------------------------------------------------------------------------------------------------------------
  158. void json_escape_string(char *dst, const char *src, size_t size) {
  159. const char *t;
  160. char *d = dst, *e = &dst[size - 1];
  161. for(t = src; *t && d < e ;t++) {
  162. if(unlikely(*t == '\\' || *t == '"')) {
  163. if(unlikely(d + 1 >= e)) break;
  164. *d++ = '\\';
  165. }
  166. *d++ = *t;
  167. }
  168. *d = '\0';
  169. }
  170. void json_fix_string(char *s) {
  171. unsigned char c;
  172. while((c = (unsigned char)*s)) {
  173. if(unlikely(c == '\\'))
  174. *s++ = '/';
  175. else if(unlikely(c == '"'))
  176. *s++ = '\'';
  177. else if(unlikely(isspace(c) || iscntrl(c)))
  178. *s++ = ' ';
  179. else if(unlikely(!isprint(c) || c > 127))
  180. *s++ = '_';
  181. else
  182. s++;
  183. }
  184. }
  185. unsigned char netdata_map_chart_names[256] = {
  186. [0] = '\0', //
  187. [1] = '_', //
  188. [2] = '_', //
  189. [3] = '_', //
  190. [4] = '_', //
  191. [5] = '_', //
  192. [6] = '_', //
  193. [7] = '_', //
  194. [8] = '_', //
  195. [9] = '_', //
  196. [10] = '_', //
  197. [11] = '_', //
  198. [12] = '_', //
  199. [13] = '_', //
  200. [14] = '_', //
  201. [15] = '_', //
  202. [16] = '_', //
  203. [17] = '_', //
  204. [18] = '_', //
  205. [19] = '_', //
  206. [20] = '_', //
  207. [21] = '_', //
  208. [22] = '_', //
  209. [23] = '_', //
  210. [24] = '_', //
  211. [25] = '_', //
  212. [26] = '_', //
  213. [27] = '_', //
  214. [28] = '_', //
  215. [29] = '_', //
  216. [30] = '_', //
  217. [31] = '_', //
  218. [32] = '_', //
  219. [33] = '_', // !
  220. [34] = '_', // "
  221. [35] = '_', // #
  222. [36] = '_', // $
  223. [37] = '_', // %
  224. [38] = '_', // &
  225. [39] = '_', // '
  226. [40] = '_', // (
  227. [41] = '_', // )
  228. [42] = '_', // *
  229. [43] = '_', // +
  230. [44] = '.', // ,
  231. [45] = '-', // -
  232. [46] = '.', // .
  233. [47] = '/', // /
  234. [48] = '0', // 0
  235. [49] = '1', // 1
  236. [50] = '2', // 2
  237. [51] = '3', // 3
  238. [52] = '4', // 4
  239. [53] = '5', // 5
  240. [54] = '6', // 6
  241. [55] = '7', // 7
  242. [56] = '8', // 8
  243. [57] = '9', // 9
  244. [58] = '_', // :
  245. [59] = '_', // ;
  246. [60] = '_', // <
  247. [61] = '_', // =
  248. [62] = '_', // >
  249. [63] = '_', // ?
  250. [64] = '_', // @
  251. [65] = 'a', // A
  252. [66] = 'b', // B
  253. [67] = 'c', // C
  254. [68] = 'd', // D
  255. [69] = 'e', // E
  256. [70] = 'f', // F
  257. [71] = 'g', // G
  258. [72] = 'h', // H
  259. [73] = 'i', // I
  260. [74] = 'j', // J
  261. [75] = 'k', // K
  262. [76] = 'l', // L
  263. [77] = 'm', // M
  264. [78] = 'n', // N
  265. [79] = 'o', // O
  266. [80] = 'p', // P
  267. [81] = 'q', // Q
  268. [82] = 'r', // R
  269. [83] = 's', // S
  270. [84] = 't', // T
  271. [85] = 'u', // U
  272. [86] = 'v', // V
  273. [87] = 'w', // W
  274. [88] = 'x', // X
  275. [89] = 'y', // Y
  276. [90] = 'z', // Z
  277. [91] = '_', // [
  278. [92] = '/', // backslash
  279. [93] = '_', // ]
  280. [94] = '_', // ^
  281. [95] = '_', // _
  282. [96] = '_', // `
  283. [97] = 'a', // a
  284. [98] = 'b', // b
  285. [99] = 'c', // c
  286. [100] = 'd', // d
  287. [101] = 'e', // e
  288. [102] = 'f', // f
  289. [103] = 'g', // g
  290. [104] = 'h', // h
  291. [105] = 'i', // i
  292. [106] = 'j', // j
  293. [107] = 'k', // k
  294. [108] = 'l', // l
  295. [109] = 'm', // m
  296. [110] = 'n', // n
  297. [111] = 'o', // o
  298. [112] = 'p', // p
  299. [113] = 'q', // q
  300. [114] = 'r', // r
  301. [115] = 's', // s
  302. [116] = 't', // t
  303. [117] = 'u', // u
  304. [118] = 'v', // v
  305. [119] = 'w', // w
  306. [120] = 'x', // x
  307. [121] = 'y', // y
  308. [122] = 'z', // z
  309. [123] = '_', // {
  310. [124] = '_', // |
  311. [125] = '_', // }
  312. [126] = '_', // ~
  313. [127] = '_', //
  314. [128] = '_', //
  315. [129] = '_', //
  316. [130] = '_', //
  317. [131] = '_', //
  318. [132] = '_', //
  319. [133] = '_', //
  320. [134] = '_', //
  321. [135] = '_', //
  322. [136] = '_', //
  323. [137] = '_', //
  324. [138] = '_', //
  325. [139] = '_', //
  326. [140] = '_', //
  327. [141] = '_', //
  328. [142] = '_', //
  329. [143] = '_', //
  330. [144] = '_', //
  331. [145] = '_', //
  332. [146] = '_', //
  333. [147] = '_', //
  334. [148] = '_', //
  335. [149] = '_', //
  336. [150] = '_', //
  337. [151] = '_', //
  338. [152] = '_', //
  339. [153] = '_', //
  340. [154] = '_', //
  341. [155] = '_', //
  342. [156] = '_', //
  343. [157] = '_', //
  344. [158] = '_', //
  345. [159] = '_', //
  346. [160] = '_', //
  347. [161] = '_', //
  348. [162] = '_', //
  349. [163] = '_', //
  350. [164] = '_', //
  351. [165] = '_', //
  352. [166] = '_', //
  353. [167] = '_', //
  354. [168] = '_', //
  355. [169] = '_', //
  356. [170] = '_', //
  357. [171] = '_', //
  358. [172] = '_', //
  359. [173] = '_', //
  360. [174] = '_', //
  361. [175] = '_', //
  362. [176] = '_', //
  363. [177] = '_', //
  364. [178] = '_', //
  365. [179] = '_', //
  366. [180] = '_', //
  367. [181] = '_', //
  368. [182] = '_', //
  369. [183] = '_', //
  370. [184] = '_', //
  371. [185] = '_', //
  372. [186] = '_', //
  373. [187] = '_', //
  374. [188] = '_', //
  375. [189] = '_', //
  376. [190] = '_', //
  377. [191] = '_', //
  378. [192] = '_', //
  379. [193] = '_', //
  380. [194] = '_', //
  381. [195] = '_', //
  382. [196] = '_', //
  383. [197] = '_', //
  384. [198] = '_', //
  385. [199] = '_', //
  386. [200] = '_', //
  387. [201] = '_', //
  388. [202] = '_', //
  389. [203] = '_', //
  390. [204] = '_', //
  391. [205] = '_', //
  392. [206] = '_', //
  393. [207] = '_', //
  394. [208] = '_', //
  395. [209] = '_', //
  396. [210] = '_', //
  397. [211] = '_', //
  398. [212] = '_', //
  399. [213] = '_', //
  400. [214] = '_', //
  401. [215] = '_', //
  402. [216] = '_', //
  403. [217] = '_', //
  404. [218] = '_', //
  405. [219] = '_', //
  406. [220] = '_', //
  407. [221] = '_', //
  408. [222] = '_', //
  409. [223] = '_', //
  410. [224] = '_', //
  411. [225] = '_', //
  412. [226] = '_', //
  413. [227] = '_', //
  414. [228] = '_', //
  415. [229] = '_', //
  416. [230] = '_', //
  417. [231] = '_', //
  418. [232] = '_', //
  419. [233] = '_', //
  420. [234] = '_', //
  421. [235] = '_', //
  422. [236] = '_', //
  423. [237] = '_', //
  424. [238] = '_', //
  425. [239] = '_', //
  426. [240] = '_', //
  427. [241] = '_', //
  428. [242] = '_', //
  429. [243] = '_', //
  430. [244] = '_', //
  431. [245] = '_', //
  432. [246] = '_', //
  433. [247] = '_', //
  434. [248] = '_', //
  435. [249] = '_', //
  436. [250] = '_', //
  437. [251] = '_', //
  438. [252] = '_', //
  439. [253] = '_', //
  440. [254] = '_', //
  441. [255] = '_' //
  442. };
  443. // make sure the supplied string
  444. // is good for a netdata chart/dimension ID/NAME
  445. void netdata_fix_chart_name(char *s) {
  446. while ((*s = netdata_map_chart_names[(unsigned char) *s])) s++;
  447. }
  448. unsigned char netdata_map_chart_ids[256] = {
  449. [0] = '\0', //
  450. [1] = '_', //
  451. [2] = '_', //
  452. [3] = '_', //
  453. [4] = '_', //
  454. [5] = '_', //
  455. [6] = '_', //
  456. [7] = '_', //
  457. [8] = '_', //
  458. [9] = '_', //
  459. [10] = '_', //
  460. [11] = '_', //
  461. [12] = '_', //
  462. [13] = '_', //
  463. [14] = '_', //
  464. [15] = '_', //
  465. [16] = '_', //
  466. [17] = '_', //
  467. [18] = '_', //
  468. [19] = '_', //
  469. [20] = '_', //
  470. [21] = '_', //
  471. [22] = '_', //
  472. [23] = '_', //
  473. [24] = '_', //
  474. [25] = '_', //
  475. [26] = '_', //
  476. [27] = '_', //
  477. [28] = '_', //
  478. [29] = '_', //
  479. [30] = '_', //
  480. [31] = '_', //
  481. [32] = '_', //
  482. [33] = '_', // !
  483. [34] = '_', // "
  484. [35] = '_', // #
  485. [36] = '_', // $
  486. [37] = '_', // %
  487. [38] = '_', // &
  488. [39] = '_', // '
  489. [40] = '_', // (
  490. [41] = '_', // )
  491. [42] = '_', // *
  492. [43] = '_', // +
  493. [44] = '.', // ,
  494. [45] = '-', // -
  495. [46] = '.', // .
  496. [47] = '_', // /
  497. [48] = '0', // 0
  498. [49] = '1', // 1
  499. [50] = '2', // 2
  500. [51] = '3', // 3
  501. [52] = '4', // 4
  502. [53] = '5', // 5
  503. [54] = '6', // 6
  504. [55] = '7', // 7
  505. [56] = '8', // 8
  506. [57] = '9', // 9
  507. [58] = '_', // :
  508. [59] = '_', // ;
  509. [60] = '_', // <
  510. [61] = '_', // =
  511. [62] = '_', // >
  512. [63] = '_', // ?
  513. [64] = '_', // @
  514. [65] = 'a', // A
  515. [66] = 'b', // B
  516. [67] = 'c', // C
  517. [68] = 'd', // D
  518. [69] = 'e', // E
  519. [70] = 'f', // F
  520. [71] = 'g', // G
  521. [72] = 'h', // H
  522. [73] = 'i', // I
  523. [74] = 'j', // J
  524. [75] = 'k', // K
  525. [76] = 'l', // L
  526. [77] = 'm', // M
  527. [78] = 'n', // N
  528. [79] = 'o', // O
  529. [80] = 'p', // P
  530. [81] = 'q', // Q
  531. [82] = 'r', // R
  532. [83] = 's', // S
  533. [84] = 't', // T
  534. [85] = 'u', // U
  535. [86] = 'v', // V
  536. [87] = 'w', // W
  537. [88] = 'x', // X
  538. [89] = 'y', // Y
  539. [90] = 'z', // Z
  540. [91] = '_', // [
  541. [92] = '/', // backslash
  542. [93] = '_', // ]
  543. [94] = '_', // ^
  544. [95] = '_', // _
  545. [96] = '_', // `
  546. [97] = 'a', // a
  547. [98] = 'b', // b
  548. [99] = 'c', // c
  549. [100] = 'd', // d
  550. [101] = 'e', // e
  551. [102] = 'f', // f
  552. [103] = 'g', // g
  553. [104] = 'h', // h
  554. [105] = 'i', // i
  555. [106] = 'j', // j
  556. [107] = 'k', // k
  557. [108] = 'l', // l
  558. [109] = 'm', // m
  559. [110] = 'n', // n
  560. [111] = 'o', // o
  561. [112] = 'p', // p
  562. [113] = 'q', // q
  563. [114] = 'r', // r
  564. [115] = 's', // s
  565. [116] = 't', // t
  566. [117] = 'u', // u
  567. [118] = 'v', // v
  568. [119] = 'w', // w
  569. [120] = 'x', // x
  570. [121] = 'y', // y
  571. [122] = 'z', // z
  572. [123] = '_', // {
  573. [124] = '_', // |
  574. [125] = '_', // }
  575. [126] = '_', // ~
  576. [127] = '_', //
  577. [128] = '_', //
  578. [129] = '_', //
  579. [130] = '_', //
  580. [131] = '_', //
  581. [132] = '_', //
  582. [133] = '_', //
  583. [134] = '_', //
  584. [135] = '_', //
  585. [136] = '_', //
  586. [137] = '_', //
  587. [138] = '_', //
  588. [139] = '_', //
  589. [140] = '_', //
  590. [141] = '_', //
  591. [142] = '_', //
  592. [143] = '_', //
  593. [144] = '_', //
  594. [145] = '_', //
  595. [146] = '_', //
  596. [147] = '_', //
  597. [148] = '_', //
  598. [149] = '_', //
  599. [150] = '_', //
  600. [151] = '_', //
  601. [152] = '_', //
  602. [153] = '_', //
  603. [154] = '_', //
  604. [155] = '_', //
  605. [156] = '_', //
  606. [157] = '_', //
  607. [158] = '_', //
  608. [159] = '_', //
  609. [160] = '_', //
  610. [161] = '_', //
  611. [162] = '_', //
  612. [163] = '_', //
  613. [164] = '_', //
  614. [165] = '_', //
  615. [166] = '_', //
  616. [167] = '_', //
  617. [168] = '_', //
  618. [169] = '_', //
  619. [170] = '_', //
  620. [171] = '_', //
  621. [172] = '_', //
  622. [173] = '_', //
  623. [174] = '_', //
  624. [175] = '_', //
  625. [176] = '_', //
  626. [177] = '_', //
  627. [178] = '_', //
  628. [179] = '_', //
  629. [180] = '_', //
  630. [181] = '_', //
  631. [182] = '_', //
  632. [183] = '_', //
  633. [184] = '_', //
  634. [185] = '_', //
  635. [186] = '_', //
  636. [187] = '_', //
  637. [188] = '_', //
  638. [189] = '_', //
  639. [190] = '_', //
  640. [191] = '_', //
  641. [192] = '_', //
  642. [193] = '_', //
  643. [194] = '_', //
  644. [195] = '_', //
  645. [196] = '_', //
  646. [197] = '_', //
  647. [198] = '_', //
  648. [199] = '_', //
  649. [200] = '_', //
  650. [201] = '_', //
  651. [202] = '_', //
  652. [203] = '_', //
  653. [204] = '_', //
  654. [205] = '_', //
  655. [206] = '_', //
  656. [207] = '_', //
  657. [208] = '_', //
  658. [209] = '_', //
  659. [210] = '_', //
  660. [211] = '_', //
  661. [212] = '_', //
  662. [213] = '_', //
  663. [214] = '_', //
  664. [215] = '_', //
  665. [216] = '_', //
  666. [217] = '_', //
  667. [218] = '_', //
  668. [219] = '_', //
  669. [220] = '_', //
  670. [221] = '_', //
  671. [222] = '_', //
  672. [223] = '_', //
  673. [224] = '_', //
  674. [225] = '_', //
  675. [226] = '_', //
  676. [227] = '_', //
  677. [228] = '_', //
  678. [229] = '_', //
  679. [230] = '_', //
  680. [231] = '_', //
  681. [232] = '_', //
  682. [233] = '_', //
  683. [234] = '_', //
  684. [235] = '_', //
  685. [236] = '_', //
  686. [237] = '_', //
  687. [238] = '_', //
  688. [239] = '_', //
  689. [240] = '_', //
  690. [241] = '_', //
  691. [242] = '_', //
  692. [243] = '_', //
  693. [244] = '_', //
  694. [245] = '_', //
  695. [246] = '_', //
  696. [247] = '_', //
  697. [248] = '_', //
  698. [249] = '_', //
  699. [250] = '_', //
  700. [251] = '_', //
  701. [252] = '_', //
  702. [253] = '_', //
  703. [254] = '_', //
  704. [255] = '_' //
  705. };
  706. // make sure the supplied string
  707. // is good for a netdata chart/dimension ID/NAME
  708. void netdata_fix_chart_id(char *s) {
  709. while ((*s = netdata_map_chart_ids[(unsigned char) *s])) s++;
  710. }
  711. /*
  712. // http://stackoverflow.com/questions/7666509/hash-function-for-string
  713. uint32_t simple_hash(const char *name)
  714. {
  715. const char *s = name;
  716. uint32_t hash = 5381;
  717. int i;
  718. while((i = *s++)) hash = ((hash << 5) + hash) + i;
  719. // fprintf(stderr, "HASH: %lu %s\n", hash, name);
  720. return hash;
  721. }
  722. */
  723. /*
  724. // http://isthe.com/chongo/tech/comp/fnv/#FNV-1a
  725. uint32_t simple_hash(const char *name) {
  726. unsigned char *s = (unsigned char *) name;
  727. uint32_t hval = 0x811c9dc5;
  728. // FNV-1a algorithm
  729. while (*s) {
  730. // multiply by the 32 bit FNV magic prime mod 2^32
  731. // NOTE: No need to optimize with left shifts.
  732. // GCC will use imul instruction anyway.
  733. // Tested with 'gcc -O3 -S'
  734. //hval += (hval<<1) + (hval<<4) + (hval<<7) + (hval<<8) + (hval<<24);
  735. hval *= 16777619;
  736. // xor the bottom with the current octet
  737. hval ^= (uint32_t) *s++;
  738. }
  739. // fprintf(stderr, "HASH: %u = %s\n", hval, name);
  740. return hval;
  741. }
  742. uint32_t simple_uhash(const char *name) {
  743. unsigned char *s = (unsigned char *) name;
  744. uint32_t hval = 0x811c9dc5, c;
  745. // FNV-1a algorithm
  746. while ((c = *s++)) {
  747. if (unlikely(c >= 'A' && c <= 'Z')) c += 'a' - 'A';
  748. hval *= 16777619;
  749. hval ^= c;
  750. }
  751. return hval;
  752. }
  753. */
  754. /*
  755. // http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx
  756. // one at a time hash
  757. uint32_t simple_hash(const char *name) {
  758. unsigned char *s = (unsigned char *)name;
  759. uint32_t h = 0;
  760. while(*s) {
  761. h += *s++;
  762. h += (h << 10);
  763. h ^= (h >> 6);
  764. }
  765. h += (h << 3);
  766. h ^= (h >> 11);
  767. h += (h << 15);
  768. // fprintf(stderr, "HASH: %u = %s\n", h, name);
  769. return h;
  770. }
  771. */
  772. void strreverse(char *begin, char *end) {
  773. while (end > begin) {
  774. // clearer code.
  775. char aux = *end;
  776. *end-- = *begin;
  777. *begin++ = aux;
  778. }
  779. }
  780. char *strsep_on_1char(char **ptr, char c) {
  781. if(unlikely(!ptr || !*ptr))
  782. return NULL;
  783. // remember the position we started
  784. char *s = *ptr;
  785. // skip separators in front
  786. while(*s == c) s++;
  787. char *ret = s;
  788. // find the next separator
  789. while(*s++) {
  790. if(unlikely(*s == c)) {
  791. *s++ = '\0';
  792. *ptr = s;
  793. return ret;
  794. }
  795. }
  796. *ptr = NULL;
  797. return ret;
  798. }
  799. char *mystrsep(char **ptr, char *s) {
  800. char *p = "";
  801. while (p && !p[0] && *ptr) p = strsep(ptr, s);
  802. return (p);
  803. }
  804. char *trim(char *s) {
  805. // skip leading spaces
  806. while (*s && isspace(*s)) s++;
  807. if (!*s) return NULL;
  808. // skip tailing spaces
  809. // this way is way faster. Writes only one NUL char.
  810. ssize_t l = strlen(s);
  811. if (--l >= 0) {
  812. char *p = s + l;
  813. while (p > s && isspace(*p)) p--;
  814. *++p = '\0';
  815. }
  816. if (!*s) return NULL;
  817. return s;
  818. }
  819. inline char *trim_all(char *buffer) {
  820. char *d = buffer, *s = buffer;
  821. // skip spaces
  822. while(isspace(*s)) s++;
  823. while(*s) {
  824. // copy the non-space part
  825. while(*s && !isspace(*s)) *d++ = *s++;
  826. // add a space if we have to
  827. if(*s && isspace(*s)) {
  828. *d++ = ' ';
  829. s++;
  830. }
  831. // skip spaces
  832. while(isspace(*s)) s++;
  833. }
  834. *d = '\0';
  835. if(d > buffer) {
  836. d--;
  837. if(isspace(*d)) *d = '\0';
  838. }
  839. if(!buffer[0]) return NULL;
  840. return buffer;
  841. }
  842. static int memory_file_open(const char *filename, size_t size) {
  843. // info("memory_file_open('%s', %zu", filename, size);
  844. int fd = open(filename, O_RDWR | O_CREAT | O_NOATIME, 0664);
  845. if (fd != -1) {
  846. if (lseek(fd, size, SEEK_SET) == (off_t) size) {
  847. if (write(fd, "", 1) == 1) {
  848. if (ftruncate(fd, size))
  849. error("Cannot truncate file '%s' to size %zu. Will use the larger file.", filename, size);
  850. }
  851. else error("Cannot write to file '%s' at position %zu.", filename, size);
  852. }
  853. else error("Cannot seek file '%s' to size %zu.", filename, size);
  854. }
  855. else error("Cannot create/open file '%s'.", filename);
  856. return fd;
  857. }
  858. // mmap_shared is used for memory mode = map
  859. static void *memory_file_mmap(const char *filename, size_t size, int flags) {
  860. // info("memory_file_mmap('%s', %zu", filename, size);
  861. static int log_madvise = 1;
  862. int fd = -1;
  863. if(filename) {
  864. fd = memory_file_open(filename, size);
  865. if(fd == -1) return MAP_FAILED;
  866. }
  867. void *mem = mmap(NULL, size, PROT_READ | PROT_WRITE, flags, fd, 0);
  868. if (mem != MAP_FAILED) {
  869. #ifdef NETDATA_LOG_ALLOCATIONS
  870. mmap_accounting(size);
  871. #endif
  872. int advise = MADV_SEQUENTIAL | MADV_DONTFORK;
  873. if (flags & MAP_SHARED) advise |= MADV_WILLNEED;
  874. if (madvise(mem, size, advise) != 0 && log_madvise) {
  875. error("Cannot advise the kernel about shared memory usage.");
  876. log_madvise--;
  877. }
  878. }
  879. if(fd != -1)
  880. close(fd);
  881. return mem;
  882. }
  883. #ifdef MADV_MERGEABLE
  884. static void *memory_file_mmap_ksm(const char *filename, size_t size, int flags) {
  885. // info("memory_file_mmap_ksm('%s', %zu", filename, size);
  886. static int log_madvise_2 = 1, log_madvise_3 = 1;
  887. int fd = -1;
  888. if(filename) {
  889. fd = memory_file_open(filename, size);
  890. if(fd == -1) return MAP_FAILED;
  891. }
  892. void *mem = mmap(NULL, size, PROT_READ | PROT_WRITE, flags | MAP_ANONYMOUS, -1, 0);
  893. if (mem != MAP_FAILED) {
  894. #ifdef NETDATA_LOG_ALLOCATIONS
  895. mmap_accounting(size);
  896. #endif
  897. if(fd != -1) {
  898. if (lseek(fd, 0, SEEK_SET) == 0) {
  899. if (read(fd, mem, size) != (ssize_t) size)
  900. error("Cannot read from file '%s'", filename);
  901. }
  902. else error("Cannot seek to beginning of file '%s'.", filename);
  903. }
  904. // don't use MADV_SEQUENTIAL|MADV_DONTFORK, they disable MADV_MERGEABLE
  905. if (madvise(mem, size, MADV_SEQUENTIAL | MADV_DONTFORK) != 0 && log_madvise_2) {
  906. error("Cannot advise the kernel about the memory usage (MADV_SEQUENTIAL|MADV_DONTFORK) of file '%s'.", filename);
  907. log_madvise_2--;
  908. }
  909. if (madvise(mem, size, MADV_MERGEABLE) != 0 && log_madvise_3) {
  910. error("Cannot advise the kernel about the memory usage (MADV_MERGEABLE) of file '%s'.", filename);
  911. log_madvise_3--;
  912. }
  913. }
  914. if(fd != -1)
  915. close(fd);
  916. return mem;
  917. }
  918. #else
  919. static void *memory_file_mmap_ksm(const char *filename, size_t size, int flags) {
  920. // info("memory_file_mmap_ksm FALLBACK ('%s', %zu", filename, size);
  921. if(filename)
  922. return memory_file_mmap(filename, size, flags);
  923. // when KSM is not available and no filename is given (memory mode = ram),
  924. // we just report failure
  925. return MAP_FAILED;
  926. }
  927. #endif
  928. void *mymmap(const char *filename, size_t size, int flags, int ksm) {
  929. void *mem = NULL;
  930. if (filename && (flags & MAP_SHARED || !enable_ksm || !ksm))
  931. // memory mode = map | save
  932. // when KSM is not enabled
  933. // MAP_SHARED is used for memory mode = map (no KSM possible)
  934. mem = memory_file_mmap(filename, size, flags);
  935. else
  936. // memory mode = save | ram
  937. // when KSM is enabled
  938. // for memory mode = ram, the filename is NULL
  939. mem = memory_file_mmap_ksm(filename, size, flags);
  940. if(mem == MAP_FAILED) return NULL;
  941. errno = 0;
  942. return mem;
  943. }
  944. int memory_file_save(const char *filename, void *mem, size_t size) {
  945. char tmpfilename[FILENAME_MAX + 1];
  946. snprintfz(tmpfilename, FILENAME_MAX, "%s.%ld.tmp", filename, (long) getpid());
  947. int fd = open(tmpfilename, O_RDWR | O_CREAT | O_NOATIME, 0664);
  948. if (fd < 0) {
  949. error("Cannot create/open file '%s'.", filename);
  950. return -1;
  951. }
  952. if (write(fd, mem, size) != (ssize_t) size) {
  953. error("Cannot write to file '%s' %ld bytes.", filename, (long) size);
  954. close(fd);
  955. return -1;
  956. }
  957. close(fd);
  958. if (rename(tmpfilename, filename)) {
  959. error("Cannot rename '%s' to '%s'", tmpfilename, filename);
  960. return -1;
  961. }
  962. return 0;
  963. }
  964. int fd_is_valid(int fd) {
  965. return fcntl(fd, F_GETFD) != -1 || errno != EBADF;
  966. }
  967. char *fgets_trim_len(char *buf, size_t buf_size, FILE *fp, size_t *len) {
  968. char *s = fgets(buf, (int)buf_size, fp);
  969. if (!s) return NULL;
  970. char *t = s;
  971. if (*t != '\0') {
  972. // find the string end
  973. while (*++t != '\0');
  974. // trim trailing spaces/newlines/tabs
  975. while (--t > s && *t == '\n')
  976. *t = '\0';
  977. }
  978. if (len)
  979. *len = t - s + 1;
  980. return s;
  981. }
  982. int vsnprintfz(char *dst, size_t n, const char *fmt, va_list args) {
  983. int size = vsnprintf(dst, n, fmt, args);
  984. if (unlikely((size_t) size > n)) {
  985. // truncated
  986. size = (int)n;
  987. }
  988. dst[size] = '\0';
  989. return size;
  990. }
  991. int snprintfz(char *dst, size_t n, const char *fmt, ...) {
  992. va_list args;
  993. va_start(args, fmt);
  994. int ret = vsnprintfz(dst, n, fmt, args);
  995. va_end(args);
  996. return ret;
  997. }
  998. /*
  999. // poor man cycle counting
  1000. static unsigned long tsc;
  1001. void begin_tsc(void) {
  1002. unsigned long a, d;
  1003. asm volatile ("cpuid\nrdtsc" : "=a" (a), "=d" (d) : "0" (0) : "ebx", "ecx");
  1004. tsc = ((unsigned long)d << 32) | (unsigned long)a;
  1005. }
  1006. unsigned long end_tsc(void) {
  1007. unsigned long a, d;
  1008. asm volatile ("rdtscp" : "=a" (a), "=d" (d) : : "ecx");
  1009. return (((unsigned long)d << 32) | (unsigned long)a) - tsc;
  1010. }
  1011. */
  1012. int recursively_delete_dir(const char *path, const char *reason) {
  1013. DIR *dir = opendir(path);
  1014. if(!dir) {
  1015. error("Cannot read %s directory to be deleted '%s'", reason?reason:"", path);
  1016. return -1;
  1017. }
  1018. int ret = 0;
  1019. struct dirent *de = NULL;
  1020. while((de = readdir(dir))) {
  1021. if(de->d_type == DT_DIR
  1022. && (
  1023. (de->d_name[0] == '.' && de->d_name[1] == '\0')
  1024. || (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')
  1025. ))
  1026. continue;
  1027. char fullpath[FILENAME_MAX + 1];
  1028. snprintfz(fullpath, FILENAME_MAX, "%s/%s", path, de->d_name);
  1029. if(de->d_type == DT_DIR) {
  1030. int r = recursively_delete_dir(fullpath, reason);
  1031. if(r > 0) ret += r;
  1032. continue;
  1033. }
  1034. info("Deleting %s file '%s'", reason?reason:"", fullpath);
  1035. if(unlikely(unlink(fullpath) == -1))
  1036. error("Cannot delete %s file '%s'", reason?reason:"", fullpath);
  1037. else
  1038. ret++;
  1039. }
  1040. info("Deleting empty directory '%s'", path);
  1041. if(unlikely(rmdir(path) == -1))
  1042. error("Cannot delete empty directory '%s'", path);
  1043. else
  1044. ret++;
  1045. closedir(dir);
  1046. return ret;
  1047. }
  1048. static int is_virtual_filesystem(const char *path, char **reason) {
  1049. #if defined(__APPLE__) || defined(__FreeBSD__)
  1050. (void)path;
  1051. (void)reason;
  1052. #else
  1053. struct statfs stat;
  1054. // stat.f_fsid.__val[0] is a file system id
  1055. // stat.f_fsid.__val[1] is the inode
  1056. // so their combination uniquely identifies the file/dir
  1057. if (statfs(path, &stat) == -1) {
  1058. if(reason) *reason = "failed to statfs()";
  1059. return -1;
  1060. }
  1061. if(stat.f_fsid.__val[0] != 0 || stat.f_fsid.__val[1] != 0) {
  1062. errno = EINVAL;
  1063. if(reason) *reason = "is not a virtual file system";
  1064. return -1;
  1065. }
  1066. #endif
  1067. return 0;
  1068. }
  1069. int verify_netdata_host_prefix() {
  1070. if(!netdata_configured_host_prefix)
  1071. netdata_configured_host_prefix = "";
  1072. if(!*netdata_configured_host_prefix)
  1073. return 0;
  1074. char buffer[FILENAME_MAX + 1];
  1075. char *path = netdata_configured_host_prefix;
  1076. char *reason = "unknown reason";
  1077. errno = 0;
  1078. struct stat sb;
  1079. if (stat(path, &sb) == -1) {
  1080. reason = "failed to stat()";
  1081. goto failed;
  1082. }
  1083. if((sb.st_mode & S_IFMT) != S_IFDIR) {
  1084. errno = EINVAL;
  1085. reason = "is not a directory";
  1086. goto failed;
  1087. }
  1088. path = buffer;
  1089. snprintfz(path, FILENAME_MAX, "%s/proc", netdata_configured_host_prefix);
  1090. if(is_virtual_filesystem(path, &reason) == -1)
  1091. goto failed;
  1092. snprintfz(path, FILENAME_MAX, "%s/sys", netdata_configured_host_prefix);
  1093. if(is_virtual_filesystem(path, &reason) == -1)
  1094. goto failed;
  1095. if(netdata_configured_host_prefix && *netdata_configured_host_prefix)
  1096. info("Using host prefix directory '%s'", netdata_configured_host_prefix);
  1097. return 0;
  1098. failed:
  1099. error("Ignoring host prefix '%s': path '%s' %s", netdata_configured_host_prefix, path, reason);
  1100. netdata_configured_host_prefix = "";
  1101. return -1;
  1102. }
  1103. char *strdupz_path_subpath(const char *path, const char *subpath) {
  1104. if(unlikely(!path || !*path)) path = ".";
  1105. if(unlikely(!subpath)) subpath = "";
  1106. // skip trailing slashes in path
  1107. size_t len = strlen(path);
  1108. while(len > 0 && path[len - 1] == '/') len--;
  1109. // skip leading slashes in subpath
  1110. while(subpath[0] == '/') subpath++;
  1111. // if the last character in path is / and (there is a subpath or path is now empty)
  1112. // keep the trailing slash in path and remove the additional slash
  1113. char *slash = "/";
  1114. if(path[len] == '/' && (*subpath || len == 0)) {
  1115. slash = "";
  1116. len++;
  1117. }
  1118. else if(!*subpath) {
  1119. // there is no subpath
  1120. // no need for trailing slash
  1121. slash = "";
  1122. }
  1123. char buffer[FILENAME_MAX + 1];
  1124. snprintfz(buffer, FILENAME_MAX, "%.*s%s%s", (int)len, path, slash, subpath);
  1125. return strdupz(buffer);
  1126. }
  1127. int path_is_dir(const char *path, const char *subpath) {
  1128. char *s = strdupz_path_subpath(path, subpath);
  1129. size_t max_links = 100;
  1130. int is_dir = 0;
  1131. struct stat statbuf;
  1132. while(max_links-- && stat(s, &statbuf) == 0) {
  1133. if((statbuf.st_mode & S_IFMT) == S_IFDIR) {
  1134. is_dir = 1;
  1135. break;
  1136. }
  1137. else if((statbuf.st_mode & S_IFMT) == S_IFLNK) {
  1138. char buffer[FILENAME_MAX + 1];
  1139. ssize_t l = readlink(s, buffer, FILENAME_MAX);
  1140. if(l > 0) {
  1141. buffer[l] = '\0';
  1142. freez(s);
  1143. s = strdupz(buffer);
  1144. continue;
  1145. }
  1146. else {
  1147. is_dir = 0;
  1148. break;
  1149. }
  1150. }
  1151. else {
  1152. is_dir = 0;
  1153. break;
  1154. }
  1155. }
  1156. freez(s);
  1157. return is_dir;
  1158. }
  1159. int path_is_file(const char *path, const char *subpath) {
  1160. char *s = strdupz_path_subpath(path, subpath);
  1161. size_t max_links = 100;
  1162. int is_file = 0;
  1163. struct stat statbuf;
  1164. while(max_links-- && stat(s, &statbuf) == 0) {
  1165. if((statbuf.st_mode & S_IFMT) == S_IFREG) {
  1166. is_file = 1;
  1167. break;
  1168. }
  1169. else if((statbuf.st_mode & S_IFMT) == S_IFLNK) {
  1170. char buffer[FILENAME_MAX + 1];
  1171. ssize_t l = readlink(s, buffer, FILENAME_MAX);
  1172. if(l > 0) {
  1173. buffer[l] = '\0';
  1174. freez(s);
  1175. s = strdupz(buffer);
  1176. continue;
  1177. }
  1178. else {
  1179. is_file = 0;
  1180. break;
  1181. }
  1182. }
  1183. else {
  1184. is_file = 0;
  1185. break;
  1186. }
  1187. }
  1188. freez(s);
  1189. return is_file;
  1190. }
  1191. 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) {
  1192. if(depth > 3) {
  1193. error("CONFIG: Max directory depth reached while reading user path '%s', stock path '%s', subpath '%s'", user_path, stock_path, subpath);
  1194. return;
  1195. }
  1196. char *udir = strdupz_path_subpath(user_path, subpath);
  1197. char *sdir = strdupz_path_subpath(stock_path, subpath);
  1198. debug(D_HEALTH, "CONFIG traversing user-config directory '%s', stock config directory '%s'", udir, sdir);
  1199. DIR *dir = opendir(udir);
  1200. if (!dir) {
  1201. error("CONFIG cannot open user-config directory '%s'.", udir);
  1202. }
  1203. else {
  1204. struct dirent *de = NULL;
  1205. while((de = readdir(dir))) {
  1206. if(de->d_type == DT_DIR || de->d_type == DT_LNK) {
  1207. if( !de->d_name[0] ||
  1208. (de->d_name[0] == '.' && de->d_name[1] == '\0') ||
  1209. (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')
  1210. ) {
  1211. debug(D_HEALTH, "CONFIG ignoring user-config directory '%s/%s'", udir, de->d_name);
  1212. continue;
  1213. }
  1214. if(path_is_dir(udir, de->d_name)) {
  1215. recursive_config_double_dir_load(udir, sdir, de->d_name, callback, data, depth + 1);
  1216. continue;
  1217. }
  1218. }
  1219. if(de->d_type == DT_REG || de->d_type == DT_LNK) {
  1220. size_t len = strlen(de->d_name);
  1221. if(path_is_file(udir, de->d_name) &&
  1222. len > 5 && !strcmp(&de->d_name[len - 5], ".conf")) {
  1223. char *filename = strdupz_path_subpath(udir, de->d_name);
  1224. callback(filename, data);
  1225. freez(filename);
  1226. }
  1227. else
  1228. debug(D_HEALTH, "CONFIG ignoring user-config file '%s/%s'", udir, de->d_name);
  1229. }
  1230. }
  1231. closedir(dir);
  1232. }
  1233. debug(D_HEALTH, "CONFIG traversing stock config directory '%s', user config directory '%s'", sdir, udir);
  1234. dir = opendir(sdir);
  1235. if (!dir) {
  1236. error("CONFIG cannot open stock config directory '%s'.", sdir);
  1237. }
  1238. else {
  1239. struct dirent *de = NULL;
  1240. while((de = readdir(dir))) {
  1241. if(de->d_type == DT_DIR || de->d_type == DT_LNK) {
  1242. if( !de->d_name[0] ||
  1243. (de->d_name[0] == '.' && de->d_name[1] == '\0') ||
  1244. (de->d_name[0] == '.' && de->d_name[1] == '.' && de->d_name[2] == '\0')
  1245. ) {
  1246. debug(D_HEALTH, "CONFIG ignoring stock config directory '%s/%s'", sdir, de->d_name);
  1247. continue;
  1248. }
  1249. if(path_is_dir(sdir, de->d_name)) {
  1250. // we recurse in stock subdirectory, only when there is no corresponding
  1251. // user subdirectory - to avoid reading the files twice
  1252. if(!path_is_dir(udir, de->d_name))
  1253. recursive_config_double_dir_load(udir, sdir, de->d_name, callback, data, depth + 1);
  1254. continue;
  1255. }
  1256. }
  1257. if(de->d_type == DT_REG || de->d_type == DT_LNK) {
  1258. size_t len = strlen(de->d_name);
  1259. if(path_is_file(sdir, de->d_name) && !path_is_file(udir, de->d_name) &&
  1260. len > 5 && !strcmp(&de->d_name[len - 5], ".conf")) {
  1261. char *filename = strdupz_path_subpath(sdir, de->d_name);
  1262. callback(filename, data);
  1263. freez(filename);
  1264. }
  1265. else
  1266. debug(D_HEALTH, "CONFIG ignoring stock config file '%s/%s'", sdir, de->d_name);
  1267. }
  1268. }
  1269. closedir(dir);
  1270. }
  1271. freez(udir);
  1272. freez(sdir);
  1273. }