appconfig.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "../libnetdata.h"
  3. /*
  4. * @Input:
  5. * Connector / instance to add to an internal structure
  6. * @Return
  7. * The current head of the linked list of connector_instance
  8. *
  9. */
  10. _CONNECTOR_INSTANCE *add_connector_instance(struct section *connector, struct section *instance)
  11. {
  12. static struct _connector_instance *global_connector_instance = NULL;
  13. struct _connector_instance *local_ci, *local_ci_tmp;
  14. if (unlikely(!connector)) {
  15. if (unlikely(!instance))
  16. return global_connector_instance;
  17. local_ci = global_connector_instance;
  18. while (local_ci) {
  19. local_ci_tmp = local_ci->next;
  20. freez(local_ci);
  21. local_ci = local_ci_tmp;
  22. }
  23. global_connector_instance = NULL;
  24. return NULL;
  25. }
  26. local_ci = callocz(1, sizeof(struct _connector_instance));
  27. local_ci->instance = instance;
  28. local_ci->connector = connector;
  29. strncpyz(local_ci->instance_name, instance->name, CONFIG_MAX_NAME);
  30. strncpyz(local_ci->connector_name, connector->name, CONFIG_MAX_NAME);
  31. local_ci->next = global_connector_instance;
  32. global_connector_instance = local_ci;
  33. return global_connector_instance;
  34. }
  35. int is_valid_connector(char *type, int check_reserved)
  36. {
  37. int rc = 1;
  38. if (unlikely(!type))
  39. return 0;
  40. if (!check_reserved) {
  41. if (unlikely(is_valid_connector(type,1))) {
  42. return 0;
  43. }
  44. //if (unlikely(*type == ':')
  45. // return 0;
  46. char *separator = strrchr(type, ':');
  47. if (likely(separator)) {
  48. *separator = '\0';
  49. rc = separator - type;
  50. } else
  51. return 0;
  52. }
  53. // else {
  54. // if (unlikely(is_valid_connector(type,1))) {
  55. // error("Section %s invalid -- reserved name", type);
  56. // return 0;
  57. // }
  58. // }
  59. if (!strcmp(type, "graphite") || !strcmp(type, "graphite:plaintext")) {
  60. return rc;
  61. } else if (!strcmp(type, "graphite:http") || !strcmp(type, "graphite:https")) {
  62. return rc;
  63. } else if (!strcmp(type, "json") || !strcmp(type, "json:plaintext")) {
  64. return rc;
  65. } else if (!strcmp(type, "json:http") || !strcmp(type, "json:https")) {
  66. return rc;
  67. } else if (!strcmp(type, "opentsdb") || !strcmp(type, "opentsdb:telnet")) {
  68. return rc;
  69. } else if (!strcmp(type, "opentsdb:http") || !strcmp(type, "opentsdb:https")) {
  70. return rc;
  71. } else if (!strcmp(type, "prometheus_remote_write")) {
  72. return rc;
  73. } else if (!strcmp(type, "prometheus_remote_write:http") || !strcmp(type, "prometheus_remote_write:https")) {
  74. return rc;
  75. } else if (!strcmp(type, "kinesis") || !strcmp(type, "kinesis:plaintext")) {
  76. return rc;
  77. } else if (!strcmp(type, "pubsub") || !strcmp(type, "pubsub:plaintext")) {
  78. return rc;
  79. } else if (!strcmp(type, "mongodb") || !strcmp(type, "mongodb:plaintext")) {
  80. return rc;
  81. }
  82. return 0;
  83. }
  84. // ----------------------------------------------------------------------------
  85. // locking
  86. inline void appconfig_wrlock(struct config *root) {
  87. netdata_mutex_lock(&root->mutex);
  88. }
  89. inline void appconfig_unlock(struct config *root) {
  90. netdata_mutex_unlock(&root->mutex);
  91. }
  92. inline void config_section_wrlock(struct section *co) {
  93. netdata_mutex_lock(&co->mutex);
  94. }
  95. inline void config_section_unlock(struct section *co) {
  96. netdata_mutex_unlock(&co->mutex);
  97. }
  98. // ----------------------------------------------------------------------------
  99. // config name-value index
  100. static int appconfig_option_compare(void *a, void *b) {
  101. if(((struct config_option *)a)->hash < ((struct config_option *)b)->hash) return -1;
  102. else if(((struct config_option *)a)->hash > ((struct config_option *)b)->hash) return 1;
  103. else return strcmp(((struct config_option *)a)->name, ((struct config_option *)b)->name);
  104. }
  105. #define appconfig_option_index_add(co, cv) (struct config_option *)avl_insert_lock(&((co)->values_index), (avl_t *)(cv))
  106. #define appconfig_option_index_del(co, cv) (struct config_option *)avl_remove_lock(&((co)->values_index), (avl_t *)(cv))
  107. static struct config_option *appconfig_option_index_find(struct section *co, const char *name, uint32_t hash) {
  108. struct config_option tmp;
  109. tmp.hash = (hash)?hash:simple_hash(name);
  110. tmp.name = (char *)name;
  111. return (struct config_option *)avl_search_lock(&(co->values_index), (avl_t *) &tmp);
  112. }
  113. // ----------------------------------------------------------------------------
  114. // config sections index
  115. int appconfig_section_compare(void *a, void *b) {
  116. if(((struct section *)a)->hash < ((struct section *)b)->hash) return -1;
  117. else if(((struct section *)a)->hash > ((struct section *)b)->hash) return 1;
  118. else return strcmp(((struct section *)a)->name, ((struct section *)b)->name);
  119. }
  120. #define appconfig_index_add(root, cfg) (struct section *)avl_insert_lock(&(root)->index, (avl_t *)(cfg))
  121. #define appconfig_index_del(root, cfg) (struct section *)avl_remove_lock(&(root)->index, (avl_t *)(cfg))
  122. static struct section *appconfig_index_find(struct config *root, const char *name, uint32_t hash) {
  123. struct section tmp;
  124. tmp.hash = (hash)?hash:simple_hash(name);
  125. tmp.name = (char *)name;
  126. return (struct section *)avl_search_lock(&root->index, (avl_t *) &tmp);
  127. }
  128. // ----------------------------------------------------------------------------
  129. // config section methods
  130. static inline struct section *appconfig_section_find(struct config *root, const char *section) {
  131. return appconfig_index_find(root, section, 0);
  132. }
  133. static inline struct section *appconfig_section_create(struct config *root, const char *section) {
  134. debug(D_CONFIG, "Creating section '%s'.", section);
  135. struct section *co = callocz(1, sizeof(struct section));
  136. co->name = strdupz(section);
  137. co->hash = simple_hash(co->name);
  138. netdata_mutex_init(&co->mutex);
  139. avl_init_lock(&co->values_index, appconfig_option_compare);
  140. if(unlikely(appconfig_index_add(root, co) != co))
  141. error("INTERNAL ERROR: indexing of section '%s', already exists.", co->name);
  142. appconfig_wrlock(root);
  143. struct section *co2 = root->last_section;
  144. if(co2) {
  145. co2->next = co;
  146. } else {
  147. root->first_section = co;
  148. }
  149. root->last_section = co;
  150. appconfig_unlock(root);
  151. return co;
  152. }
  153. void appconfig_section_destroy_non_loaded(struct config *root, const char *section)
  154. {
  155. struct section *co;
  156. struct config_option *cv, *cv_next;
  157. debug(D_CONFIG, "Destroying section '%s'.", section);
  158. co = appconfig_section_find(root, section);
  159. if(!co) {
  160. error("Could not destroy section '%s'. Not found.", section);
  161. return;
  162. }
  163. config_section_wrlock(co);
  164. for(cv = co->values; cv ; cv = cv->next) {
  165. if (cv->flags & CONFIG_VALUE_LOADED) {
  166. /* Do not destroy values that were loaded from the configuration files. */
  167. config_section_unlock(co);
  168. return;
  169. }
  170. }
  171. for(cv = co->values ; cv ; cv = cv_next) {
  172. cv_next = cv->next;
  173. if(unlikely(!appconfig_option_index_del(co, cv)))
  174. error("Cannot remove config option '%s' from section '%s'.", cv->name, co->name);
  175. freez(cv->value);
  176. freez(cv->name);
  177. freez(cv);
  178. }
  179. co->values = NULL;
  180. config_section_unlock(co);
  181. if (unlikely(!appconfig_index_del(root, co))) {
  182. error("Cannot remove section '%s' from config.", section);
  183. return;
  184. }
  185. appconfig_wrlock(root);
  186. if (root->first_section == co) {
  187. root->first_section = co->next;
  188. if (root->last_section == co)
  189. root->last_section = root->first_section;
  190. } else {
  191. struct section *co_cur = root->first_section, *co_prev = NULL;
  192. while(co_cur && co_cur != co) {
  193. co_prev = co_cur;
  194. co_cur = co_cur->next;
  195. }
  196. if (co_cur) {
  197. co_prev->next = co_cur->next;
  198. if (root->last_section == co_cur)
  199. root->last_section = co_prev;
  200. }
  201. }
  202. appconfig_unlock(root);
  203. avl_destroy_lock(&co->values_index);
  204. freez(co->name);
  205. pthread_mutex_destroy(&co->mutex);
  206. freez(co);
  207. }
  208. void appconfig_section_option_destroy_non_loaded(struct config *root, const char *section, const char *name)
  209. {
  210. debug(D_CONFIG, "Destroying section option '%s -> %s'.", section, name);
  211. struct section *co;
  212. co = appconfig_section_find(root, section);
  213. if (!co) {
  214. error("Could not destroy section option '%s -> %s'. The section not found.", section, name);
  215. return;
  216. }
  217. config_section_wrlock(co);
  218. struct config_option *cv;
  219. cv = appconfig_option_index_find(co, name, simple_hash(name));
  220. if (cv && cv->flags & CONFIG_VALUE_LOADED) {
  221. config_section_unlock(co);
  222. return;
  223. }
  224. if (unlikely(!(cv && appconfig_option_index_del(co, cv)))) {
  225. config_section_unlock(co);
  226. error("Could not destroy section option '%s -> %s'. The option not found.", section, name);
  227. return;
  228. }
  229. if (co->values == cv) {
  230. co->values = co->values->next;
  231. } else {
  232. struct config_option *cv_cur = co->values, *cv_prev = NULL;
  233. while (cv_cur && cv_cur != cv) {
  234. cv_prev = cv_cur;
  235. cv_cur = cv_cur->next;
  236. }
  237. if (cv_cur) {
  238. cv_prev->next = cv_cur->next;
  239. }
  240. }
  241. freez(cv->value);
  242. freez(cv->name);
  243. freez(cv);
  244. config_section_unlock(co);
  245. return;
  246. }
  247. // ----------------------------------------------------------------------------
  248. // config name-value methods
  249. static inline struct config_option *appconfig_value_create(struct section *co, const char *name, const char *value) {
  250. debug(D_CONFIG, "Creating config entry for name '%s', value '%s', in section '%s'.", name, value, co->name);
  251. struct config_option *cv = callocz(1, sizeof(struct config_option));
  252. cv->name = strdupz(name);
  253. cv->hash = simple_hash(cv->name);
  254. cv->value = strdupz(value);
  255. struct config_option *found = appconfig_option_index_add(co, cv);
  256. if(found != cv) {
  257. error("indexing of config '%s' in section '%s': already exists - using the existing one.", cv->name, co->name);
  258. freez(cv->value);
  259. freez(cv->name);
  260. freez(cv);
  261. return found;
  262. }
  263. config_section_wrlock(co);
  264. struct config_option *cv2 = co->values;
  265. if(cv2) {
  266. while (cv2->next) cv2 = cv2->next;
  267. cv2->next = cv;
  268. }
  269. else co->values = cv;
  270. config_section_unlock(co);
  271. return cv;
  272. }
  273. int appconfig_exists(struct config *root, const char *section, const char *name) {
  274. struct config_option *cv;
  275. debug(D_CONFIG, "request to get config in section '%s', name '%s'", section, name);
  276. struct section *co = appconfig_section_find(root, section);
  277. if(!co) return 0;
  278. cv = appconfig_option_index_find(co, name, 0);
  279. if(!cv) return 0;
  280. return 1;
  281. }
  282. int appconfig_move(struct config *root, const char *section_old, const char *name_old, const char *section_new, const char *name_new) {
  283. struct config_option *cv_old, *cv_new;
  284. int ret = -1;
  285. debug(D_CONFIG, "request to rename config in section '%s', old name '%s', to section '%s', new name '%s'", section_old, name_old, section_new, name_new);
  286. struct section *co_old = appconfig_section_find(root, section_old);
  287. if(!co_old) return ret;
  288. struct section *co_new = appconfig_section_find(root, section_new);
  289. if(!co_new) co_new = appconfig_section_create(root, section_new);
  290. config_section_wrlock(co_old);
  291. if(co_old != co_new)
  292. config_section_wrlock(co_new);
  293. cv_old = appconfig_option_index_find(co_old, name_old, 0);
  294. if(!cv_old) goto cleanup;
  295. cv_new = appconfig_option_index_find(co_new, name_new, 0);
  296. if(cv_new) goto cleanup;
  297. if(unlikely(appconfig_option_index_del(co_old, cv_old) != cv_old))
  298. error("INTERNAL ERROR: deletion of config '%s' from section '%s', deleted the wrong config entry.", cv_old->name, co_old->name);
  299. if(co_old->values == cv_old) {
  300. co_old->values = cv_old->next;
  301. }
  302. else {
  303. struct config_option *t;
  304. for(t = co_old->values; t && t->next != cv_old ;t = t->next) ;
  305. if(!t || t->next != cv_old)
  306. error("INTERNAL ERROR: cannot find variable '%s' in section '%s' of the config - but it should be there.", cv_old->name, co_old->name);
  307. else
  308. t->next = cv_old->next;
  309. }
  310. freez(cv_old->name);
  311. cv_old->name = strdupz(name_new);
  312. cv_old->hash = simple_hash(cv_old->name);
  313. cv_new = cv_old;
  314. cv_new->next = co_new->values;
  315. co_new->values = cv_new;
  316. if(unlikely(appconfig_option_index_add(co_new, cv_old) != cv_old))
  317. error("INTERNAL ERROR: re-indexing of config '%s' in section '%s', already exists.", cv_old->name, co_new->name);
  318. ret = 0;
  319. cleanup:
  320. if(co_old != co_new)
  321. config_section_unlock(co_new);
  322. config_section_unlock(co_old);
  323. return ret;
  324. }
  325. char *appconfig_get_by_section(struct section *co, const char *name, const char *default_value)
  326. {
  327. struct config_option *cv;
  328. // Only calls internal to this file check for a NULL result and they do not supply a NULL arg.
  329. // External caller should treat NULL as an error case.
  330. cv = appconfig_option_index_find(co, name, 0);
  331. if (!cv) {
  332. if (!default_value) return NULL;
  333. cv = appconfig_value_create(co, name, default_value);
  334. if (!cv) return NULL;
  335. }
  336. cv->flags |= CONFIG_VALUE_USED;
  337. if((cv->flags & CONFIG_VALUE_LOADED) || (cv->flags & CONFIG_VALUE_CHANGED)) {
  338. // this is a loaded value from the config file
  339. // if it is different than the default, mark it
  340. if(!(cv->flags & CONFIG_VALUE_CHECKED)) {
  341. if(default_value && strcmp(cv->value, default_value) != 0) cv->flags |= CONFIG_VALUE_CHANGED;
  342. cv->flags |= CONFIG_VALUE_CHECKED;
  343. }
  344. }
  345. return(cv->value);
  346. }
  347. char *appconfig_get(struct config *root, const char *section, const char *name, const char *default_value)
  348. {
  349. if (default_value == NULL)
  350. debug(D_CONFIG, "request to get config in section '%s', name '%s' or fail", section, name);
  351. else
  352. debug(D_CONFIG, "request to get config in section '%s', name '%s', default_value '%s'", section, name, default_value);
  353. struct section *co = appconfig_section_find(root, section);
  354. if (!co && !default_value)
  355. return NULL;
  356. if(!co) co = appconfig_section_create(root, section);
  357. return appconfig_get_by_section(co, name, default_value);
  358. }
  359. long long appconfig_get_number(struct config *root, const char *section, const char *name, long long value)
  360. {
  361. char buffer[100], *s;
  362. sprintf(buffer, "%lld", value);
  363. s = appconfig_get(root, section, name, buffer);
  364. if(!s) return value;
  365. return strtoll(s, NULL, 0);
  366. }
  367. NETDATA_DOUBLE appconfig_get_float(struct config *root, const char *section, const char *name, NETDATA_DOUBLE value)
  368. {
  369. char buffer[100], *s;
  370. sprintf(buffer, "%0.5" NETDATA_DOUBLE_MODIFIER, value);
  371. s = appconfig_get(root, section, name, buffer);
  372. if(!s) return value;
  373. return str2ndd(s, NULL);
  374. }
  375. inline int appconfig_test_boolean_value(char *s) {
  376. if(!strcasecmp(s, "yes") || !strcasecmp(s, "true") || !strcasecmp(s, "on")
  377. || !strcasecmp(s, "auto") || !strcasecmp(s, "on demand"))
  378. return 1;
  379. return 0;
  380. }
  381. int appconfig_get_boolean_by_section(struct section *co, const char *name, int value) {
  382. char *s;
  383. s = appconfig_get_by_section(co, name, (!value)?"no":"yes");
  384. if(!s) return value;
  385. return appconfig_test_boolean_value(s);
  386. }
  387. int appconfig_get_boolean(struct config *root, const char *section, const char *name, int value)
  388. {
  389. char *s;
  390. if(value) s = "yes";
  391. else s = "no";
  392. s = appconfig_get(root, section, name, s);
  393. if(!s) return value;
  394. return appconfig_test_boolean_value(s);
  395. }
  396. int appconfig_get_boolean_ondemand(struct config *root, const char *section, const char *name, int value)
  397. {
  398. char *s;
  399. if(value == CONFIG_BOOLEAN_AUTO)
  400. s = "auto";
  401. else if(value == CONFIG_BOOLEAN_NO)
  402. s = "no";
  403. else
  404. s = "yes";
  405. s = appconfig_get(root, section, name, s);
  406. if(!s) return value;
  407. if(!strcmp(s, "yes"))
  408. return CONFIG_BOOLEAN_YES;
  409. else if(!strcmp(s, "no"))
  410. return CONFIG_BOOLEAN_NO;
  411. else if(!strcmp(s, "auto") || !strcmp(s, "on demand"))
  412. return CONFIG_BOOLEAN_AUTO;
  413. return value;
  414. }
  415. const char *appconfig_set_default(struct config *root, const char *section, const char *name, const char *value)
  416. {
  417. struct config_option *cv;
  418. debug(D_CONFIG, "request to set default config in section '%s', name '%s', value '%s'", section, name, value);
  419. struct section *co = appconfig_section_find(root, section);
  420. if(!co) return appconfig_set(root, section, name, value);
  421. cv = appconfig_option_index_find(co, name, 0);
  422. if(!cv) return appconfig_set(root, section, name, value);
  423. cv->flags |= CONFIG_VALUE_USED;
  424. if(cv->flags & CONFIG_VALUE_LOADED)
  425. return cv->value;
  426. if(strcmp(cv->value, value) != 0) {
  427. cv->flags |= CONFIG_VALUE_CHANGED;
  428. freez(cv->value);
  429. cv->value = strdupz(value);
  430. }
  431. return cv->value;
  432. }
  433. const char *appconfig_set(struct config *root, const char *section, const char *name, const char *value)
  434. {
  435. struct config_option *cv;
  436. debug(D_CONFIG, "request to set config in section '%s', name '%s', value '%s'", section, name, value);
  437. struct section *co = appconfig_section_find(root, section);
  438. if(!co) co = appconfig_section_create(root, section);
  439. cv = appconfig_option_index_find(co, name, 0);
  440. if(!cv) cv = appconfig_value_create(co, name, value);
  441. cv->flags |= CONFIG_VALUE_USED;
  442. if(strcmp(cv->value, value) != 0) {
  443. cv->flags |= CONFIG_VALUE_CHANGED;
  444. freez(cv->value);
  445. cv->value = strdupz(value);
  446. }
  447. return value;
  448. }
  449. long long appconfig_set_number(struct config *root, const char *section, const char *name, long long value)
  450. {
  451. char buffer[100];
  452. sprintf(buffer, "%lld", value);
  453. appconfig_set(root, section, name, buffer);
  454. return value;
  455. }
  456. NETDATA_DOUBLE appconfig_set_float(struct config *root, const char *section, const char *name, NETDATA_DOUBLE value)
  457. {
  458. char buffer[100];
  459. sprintf(buffer, "%0.5" NETDATA_DOUBLE_MODIFIER, value);
  460. appconfig_set(root, section, name, buffer);
  461. return value;
  462. }
  463. int appconfig_set_boolean(struct config *root, const char *section, const char *name, int value)
  464. {
  465. char *s;
  466. if(value) s = "yes";
  467. else s = "no";
  468. appconfig_set(root, section, name, s);
  469. return value;
  470. }
  471. int appconfig_get_duration(struct config *root, const char *section, const char *name, const char *value)
  472. {
  473. int result = 0;
  474. const char *s;
  475. s = appconfig_get(root, section, name, value);
  476. if(!s) goto fallback;
  477. if(!config_parse_duration(s, &result)) {
  478. error("config option '[%s].%s = %s' is configured with an valid duration", section, name, s);
  479. goto fallback;
  480. }
  481. return result;
  482. fallback:
  483. if(!config_parse_duration(value, &result))
  484. error("INTERNAL ERROR: default duration supplied for option '[%s].%s = %s' is not a valid duration", section, name, value);
  485. return result;
  486. }
  487. // ----------------------------------------------------------------------------
  488. // config load/save
  489. int appconfig_load(struct config *root, char *filename, int overwrite_used, const char *section_name)
  490. {
  491. int line = 0;
  492. struct section *co = NULL;
  493. int is_exporter_config = 0;
  494. int _connectors = 0; // number of exporting connector sections we have
  495. char working_instance[CONFIG_MAX_NAME + 1];
  496. char working_connector[CONFIG_MAX_NAME + 1];
  497. struct section *working_connector_section = NULL;
  498. int global_exporting_section = 0;
  499. char buffer[CONFIG_FILE_LINE_MAX + 1], *s;
  500. if(!filename) filename = CONFIG_DIR "/" CONFIG_FILENAME;
  501. debug(D_CONFIG, "CONFIG: opening config file '%s'", filename);
  502. FILE *fp = fopen(filename, "r");
  503. if(!fp) {
  504. // info("CONFIG: cannot open file '%s'. Using internal defaults.", filename);
  505. return 0;
  506. }
  507. uint32_t section_hash = 0;
  508. if(section_name) {
  509. section_hash = simple_hash(section_name);
  510. }
  511. is_exporter_config = (strstr(filename, EXPORTING_CONF) != NULL);
  512. while(fgets(buffer, CONFIG_FILE_LINE_MAX, fp) != NULL) {
  513. buffer[CONFIG_FILE_LINE_MAX] = '\0';
  514. line++;
  515. s = trim(buffer);
  516. if(!s || *s == '#') {
  517. debug(D_CONFIG, "CONFIG: ignoring line %d of file '%s', it is empty.", line, filename);
  518. continue;
  519. }
  520. int len = (int) strlen(s);
  521. if(*s == '[' && s[len - 1] == ']') {
  522. // new section
  523. s[len - 1] = '\0';
  524. s++;
  525. if (is_exporter_config) {
  526. global_exporting_section =
  527. !(strcmp(s, CONFIG_SECTION_EXPORTING)) || !(strcmp(s, CONFIG_SECTION_PROMETHEUS));
  528. if (unlikely(!global_exporting_section)) {
  529. int rc;
  530. rc = is_valid_connector(s, 0);
  531. if (likely(rc)) {
  532. strncpyz(working_connector, s, CONFIG_MAX_NAME);
  533. s = s + rc + 1;
  534. if (unlikely(!(*s))) {
  535. _connectors++;
  536. sprintf(buffer, "instance_%d", _connectors);
  537. s = buffer;
  538. }
  539. strncpyz(working_instance, s, CONFIG_MAX_NAME);
  540. working_connector_section = NULL;
  541. if (unlikely(appconfig_section_find(root, working_instance))) {
  542. error("Instance (%s) already exists", working_instance);
  543. co = NULL;
  544. continue;
  545. }
  546. } else {
  547. co = NULL;
  548. error("Section (%s) does not specify a valid connector", s);
  549. continue;
  550. }
  551. }
  552. }
  553. co = appconfig_section_find(root, s);
  554. if(!co) co = appconfig_section_create(root, s);
  555. if(co && section_name && overwrite_used && section_hash == co->hash && !strcmp(section_name, co->name)) {
  556. config_section_wrlock(co);
  557. struct config_option *cv2 = co->values;
  558. while (cv2) {
  559. struct config_option *save = cv2->next;
  560. struct config_option *found = appconfig_option_index_del(co, cv2);
  561. if(found != cv2)
  562. error("INTERNAL ERROR: Cannot remove '%s' from section '%s', it was not inserted before.",
  563. cv2->name, co->name);
  564. freez(cv2->name);
  565. freez(cv2->value);
  566. freez(cv2);
  567. cv2 = save;
  568. }
  569. co->values = NULL;
  570. config_section_unlock(co);
  571. }
  572. continue;
  573. }
  574. if(!co) {
  575. // line outside a section
  576. error("CONFIG: ignoring line %d ('%s') of file '%s', it is outside all sections.", line, s, filename);
  577. continue;
  578. }
  579. if(section_name && overwrite_used && section_hash != co->hash && strcmp(section_name, co->name)) {
  580. continue;
  581. }
  582. char *name = s;
  583. char *value = strchr(s, '=');
  584. if(!value) {
  585. error("CONFIG: ignoring line %d ('%s') of file '%s', there is no = in it.", line, s, filename);
  586. continue;
  587. }
  588. *value = '\0';
  589. value++;
  590. name = trim(name);
  591. value = trim(value);
  592. if(!name || *name == '#') {
  593. error("CONFIG: ignoring line %d of file '%s', name is empty.", line, filename);
  594. continue;
  595. }
  596. if(!value) value = "";
  597. struct config_option *cv = appconfig_option_index_find(co, name, 0);
  598. if (!cv) {
  599. cv = appconfig_value_create(co, name, value);
  600. if (likely(is_exporter_config) && unlikely(!global_exporting_section)) {
  601. if (unlikely(!working_connector_section)) {
  602. working_connector_section = appconfig_section_find(root, working_connector);
  603. if (!working_connector_section)
  604. working_connector_section = appconfig_section_create(root, working_connector);
  605. if (likely(working_connector_section)) {
  606. add_connector_instance(working_connector_section, co);
  607. }
  608. }
  609. }
  610. } else {
  611. if (((cv->flags & CONFIG_VALUE_USED) && overwrite_used) || !(cv->flags & CONFIG_VALUE_USED)) {
  612. debug(
  613. D_CONFIG, "CONFIG: line %d of file '%s', overwriting '%s/%s'.", line, filename, co->name, cv->name);
  614. freez(cv->value);
  615. cv->value = strdupz(value);
  616. } else
  617. debug(
  618. D_CONFIG,
  619. "CONFIG: ignoring line %d of file '%s', '%s/%s' is already present and used.",
  620. line,
  621. filename,
  622. co->name,
  623. cv->name);
  624. }
  625. cv->flags |= CONFIG_VALUE_LOADED;
  626. }
  627. fclose(fp);
  628. return 1;
  629. }
  630. void appconfig_generate(struct config *root, BUFFER *wb, int only_changed)
  631. {
  632. int i, pri;
  633. struct section *co;
  634. struct config_option *cv;
  635. {
  636. int found_host_labels = 0;
  637. for (co = root->first_section; co; co = co->next)
  638. if(!strcmp(co->name, CONFIG_SECTION_HOST_LABEL))
  639. found_host_labels = 1;
  640. if(!found_host_labels) {
  641. appconfig_section_create(root, CONFIG_SECTION_HOST_LABEL);
  642. appconfig_get(root, CONFIG_SECTION_HOST_LABEL, "name", "value");
  643. }
  644. }
  645. buffer_strcat(wb,
  646. "# netdata configuration\n"
  647. "#\n"
  648. "# You can download the latest version of this file, using:\n"
  649. "#\n"
  650. "# wget -O /etc/netdata/netdata.conf http://localhost:19999/netdata.conf\n"
  651. "# or\n"
  652. "# curl -o /etc/netdata/netdata.conf http://localhost:19999/netdata.conf\n"
  653. "#\n"
  654. "# You can uncomment and change any of the options below.\n"
  655. "# The value shown in the commented settings, is the default value.\n"
  656. "#\n"
  657. "\n# global netdata configuration\n");
  658. for(i = 0; i <= 16 ;i++) {
  659. appconfig_wrlock(root);
  660. for(co = root->first_section; co ; co = co->next) {
  661. if(!strcmp(co->name, CONFIG_SECTION_GLOBAL)) pri = 0;
  662. else if(!strcmp(co->name, CONFIG_SECTION_DB)) pri = 1;
  663. else if(!strcmp(co->name, CONFIG_SECTION_DIRECTORIES)) pri = 2;
  664. else if(!strcmp(co->name, CONFIG_SECTION_LOGS)) pri = 3;
  665. else if(!strcmp(co->name, CONFIG_SECTION_ENV_VARS)) pri = 4;
  666. else if(!strcmp(co->name, CONFIG_SECTION_HOST_LABEL)) pri = 5;
  667. else if(!strcmp(co->name, CONFIG_SECTION_SQLITE)) pri = 6;
  668. else if(!strcmp(co->name, CONFIG_SECTION_CLOUD)) pri = 7;
  669. else if(!strcmp(co->name, CONFIG_SECTION_ML)) pri = 8;
  670. else if(!strcmp(co->name, CONFIG_SECTION_HEALTH)) pri = 9;
  671. else if(!strcmp(co->name, CONFIG_SECTION_WEB)) pri = 10;
  672. // by default, new sections will get pri = 11 (set at the end, below)
  673. else if(!strcmp(co->name, CONFIG_SECTION_REGISTRY)) pri = 12;
  674. else if(!strcmp(co->name, CONFIG_SECTION_GLOBAL_STATISTICS)) pri = 13;
  675. else if(!strcmp(co->name, CONFIG_SECTION_PLUGINS)) pri = 14;
  676. else if(!strcmp(co->name, CONFIG_SECTION_STATSD)) pri = 15;
  677. else if(!strncmp(co->name, "plugin:", 7)) pri = 16; // << change the loop too if you change this
  678. else pri = 11; // this is used for any new (currently unknown) sections
  679. if(i == pri) {
  680. int loaded = 0;
  681. int used = 0;
  682. int changed = 0;
  683. int count = 0;
  684. config_section_wrlock(co);
  685. for(cv = co->values; cv ; cv = cv->next) {
  686. used += (cv->flags & CONFIG_VALUE_USED)?1:0;
  687. loaded += (cv->flags & CONFIG_VALUE_LOADED)?1:0;
  688. changed += (cv->flags & CONFIG_VALUE_CHANGED)?1:0;
  689. count++;
  690. }
  691. config_section_unlock(co);
  692. if(!count) continue;
  693. if(only_changed && !changed && !loaded) continue;
  694. if(!used) {
  695. buffer_sprintf(wb, "\n# section '%s' is not used.", co->name);
  696. }
  697. buffer_sprintf(wb, "\n[%s]\n", co->name);
  698. config_section_wrlock(co);
  699. for(cv = co->values; cv ; cv = cv->next) {
  700. if(used && !(cv->flags & CONFIG_VALUE_USED)) {
  701. buffer_sprintf(wb, "\n\t# option '%s' is not used.\n", cv->name);
  702. }
  703. buffer_sprintf(wb, "\t%s%s = %s\n", ((!(cv->flags & CONFIG_VALUE_LOADED)) && (!(cv->flags & CONFIG_VALUE_CHANGED)) && (cv->flags & CONFIG_VALUE_USED))?"# ":"", cv->name, cv->value);
  704. }
  705. config_section_unlock(co);
  706. }
  707. }
  708. appconfig_unlock(root);
  709. }
  710. }
  711. /**
  712. * Parse Duration
  713. *
  714. * Parse the string setting the result
  715. *
  716. * @param string the timestamp string
  717. * @param result the output variable
  718. *
  719. * @return It returns 1 on success and 0 otherwise
  720. */
  721. int config_parse_duration(const char* string, int* result) {
  722. while(*string && isspace(*string)) string++;
  723. if(unlikely(!*string)) goto fallback;
  724. if(*string == 'n' && !strcmp(string, "never")) {
  725. // this is a valid option
  726. *result = 0;
  727. return 1;
  728. }
  729. // make sure it is a number
  730. if(!(isdigit(*string) || *string == '+' || *string == '-')) goto fallback;
  731. char *e = NULL;
  732. NETDATA_DOUBLE n = str2ndd(string, &e);
  733. if(e && *e) {
  734. switch (*e) {
  735. case 'Y':
  736. *result = (int) (n * 31536000);
  737. break;
  738. case 'M':
  739. *result = (int) (n * 2592000);
  740. break;
  741. case 'w':
  742. *result = (int) (n * 604800);
  743. break;
  744. case 'd':
  745. *result = (int) (n * 86400);
  746. break;
  747. case 'h':
  748. *result = (int) (n * 3600);
  749. break;
  750. case 'm':
  751. *result = (int) (n * 60);
  752. break;
  753. case 's':
  754. default:
  755. *result = (int) (n);
  756. break;
  757. }
  758. }
  759. else
  760. *result = (int)(n);
  761. return 1;
  762. fallback:
  763. *result = 0;
  764. return 0;
  765. }
  766. struct section *appconfig_get_section(struct config *root, const char *name)
  767. {
  768. return appconfig_section_find(root, name);
  769. }