libnetdata.c 41 KB

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