appconfig.c 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908
  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. strncpy(local_ci->instance_name, instance->name, CONFIG_MAX_NAME);
  30. strncpy(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. // ----------------------------------------------------------------------------
  209. // config name-value methods
  210. static inline struct config_option *appconfig_value_create(struct section *co, const char *name, const char *value) {
  211. debug(D_CONFIG, "Creating config entry for name '%s', value '%s', in section '%s'.", name, value, co->name);
  212. struct config_option *cv = callocz(1, sizeof(struct config_option));
  213. cv->name = strdupz(name);
  214. cv->hash = simple_hash(cv->name);
  215. cv->value = strdupz(value);
  216. struct config_option *found = appconfig_option_index_add(co, cv);
  217. if(found != cv) {
  218. error("indexing of config '%s' in section '%s': already exists - using the existing one.", cv->name, co->name);
  219. freez(cv->value);
  220. freez(cv->name);
  221. freez(cv);
  222. return found;
  223. }
  224. config_section_wrlock(co);
  225. struct config_option *cv2 = co->values;
  226. if(cv2) {
  227. while (cv2->next) cv2 = cv2->next;
  228. cv2->next = cv;
  229. }
  230. else co->values = cv;
  231. config_section_unlock(co);
  232. return cv;
  233. }
  234. int appconfig_exists(struct config *root, const char *section, const char *name) {
  235. struct config_option *cv;
  236. debug(D_CONFIG, "request to get config in section '%s', name '%s'", section, name);
  237. struct section *co = appconfig_section_find(root, section);
  238. if(!co) return 0;
  239. cv = appconfig_option_index_find(co, name, 0);
  240. if(!cv) return 0;
  241. return 1;
  242. }
  243. int appconfig_move(struct config *root, const char *section_old, const char *name_old, const char *section_new, const char *name_new) {
  244. struct config_option *cv_old, *cv_new;
  245. int ret = -1;
  246. 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);
  247. struct section *co_old = appconfig_section_find(root, section_old);
  248. if(!co_old) return ret;
  249. struct section *co_new = appconfig_section_find(root, section_new);
  250. if(!co_new) co_new = appconfig_section_create(root, section_new);
  251. config_section_wrlock(co_old);
  252. if(co_old != co_new)
  253. config_section_wrlock(co_new);
  254. cv_old = appconfig_option_index_find(co_old, name_old, 0);
  255. if(!cv_old) goto cleanup;
  256. cv_new = appconfig_option_index_find(co_new, name_new, 0);
  257. if(cv_new) goto cleanup;
  258. if(unlikely(appconfig_option_index_del(co_old, cv_old) != cv_old))
  259. error("INTERNAL ERROR: deletion of config '%s' from section '%s', deleted the wrong config entry.", cv_old->name, co_old->name);
  260. if(co_old->values == cv_old) {
  261. co_old->values = cv_old->next;
  262. }
  263. else {
  264. struct config_option *t;
  265. for(t = co_old->values; t && t->next != cv_old ;t = t->next) ;
  266. if(!t || t->next != cv_old)
  267. error("INTERNAL ERROR: cannot find variable '%s' in section '%s' of the config - but it should be there.", cv_old->name, co_old->name);
  268. else
  269. t->next = cv_old->next;
  270. }
  271. freez(cv_old->name);
  272. cv_old->name = strdupz(name_new);
  273. cv_old->hash = simple_hash(cv_old->name);
  274. cv_new = cv_old;
  275. cv_new->next = co_new->values;
  276. co_new->values = cv_new;
  277. if(unlikely(appconfig_option_index_add(co_new, cv_old) != cv_old))
  278. error("INTERNAL ERROR: re-indexing of config '%s' in section '%s', already exists.", cv_old->name, co_new->name);
  279. ret = 0;
  280. cleanup:
  281. if(co_old != co_new)
  282. config_section_unlock(co_new);
  283. config_section_unlock(co_old);
  284. return ret;
  285. }
  286. char *appconfig_get_by_section(struct section *co, const char *name, const char *default_value)
  287. {
  288. struct config_option *cv;
  289. // Only calls internal to this file check for a NULL result and they do not supply a NULL arg.
  290. // External caller should treat NULL as an error case.
  291. cv = appconfig_option_index_find(co, name, 0);
  292. if (!cv) {
  293. if (!default_value) return NULL;
  294. cv = appconfig_value_create(co, name, default_value);
  295. if (!cv) return NULL;
  296. }
  297. cv->flags |= CONFIG_VALUE_USED;
  298. if((cv->flags & CONFIG_VALUE_LOADED) || (cv->flags & CONFIG_VALUE_CHANGED)) {
  299. // this is a loaded value from the config file
  300. // if it is different than the default, mark it
  301. if(!(cv->flags & CONFIG_VALUE_CHECKED)) {
  302. if(default_value && strcmp(cv->value, default_value) != 0) cv->flags |= CONFIG_VALUE_CHANGED;
  303. cv->flags |= CONFIG_VALUE_CHECKED;
  304. }
  305. }
  306. return(cv->value);
  307. }
  308. char *appconfig_get(struct config *root, const char *section, const char *name, const char *default_value)
  309. {
  310. if (default_value == NULL)
  311. debug(D_CONFIG, "request to get config in section '%s', name '%s' or fail", section, name);
  312. else
  313. debug(D_CONFIG, "request to get config in section '%s', name '%s', default_value '%s'", section, name, default_value);
  314. struct section *co = appconfig_section_find(root, section);
  315. if (!co && !default_value)
  316. return NULL;
  317. if(!co) co = appconfig_section_create(root, section);
  318. return appconfig_get_by_section(co, name, default_value);
  319. }
  320. long long appconfig_get_number(struct config *root, const char *section, const char *name, long long value)
  321. {
  322. char buffer[100], *s;
  323. sprintf(buffer, "%lld", value);
  324. s = appconfig_get(root, section, name, buffer);
  325. if(!s) return value;
  326. return strtoll(s, NULL, 0);
  327. }
  328. LONG_DOUBLE appconfig_get_float(struct config *root, const char *section, const char *name, LONG_DOUBLE value)
  329. {
  330. char buffer[100], *s;
  331. sprintf(buffer, "%0.5" LONG_DOUBLE_MODIFIER, value);
  332. s = appconfig_get(root, section, name, buffer);
  333. if(!s) return value;
  334. return str2ld(s, NULL);
  335. }
  336. static inline int appconfig_test_boolean_value(char *s) {
  337. if(!strcasecmp(s, "yes") || !strcasecmp(s, "true") || !strcasecmp(s, "on")
  338. || !strcasecmp(s, "auto") || !strcasecmp(s, "on demand"))
  339. return 1;
  340. return 0;
  341. }
  342. int appconfig_get_boolean_by_section(struct section *co, const char *name, int value) {
  343. char *s;
  344. s = appconfig_get_by_section(co, name, (!value)?"no":"yes");
  345. if(!s) return value;
  346. return appconfig_test_boolean_value(s);
  347. }
  348. int appconfig_get_boolean(struct config *root, const char *section, const char *name, int value)
  349. {
  350. char *s;
  351. if(value) s = "yes";
  352. else s = "no";
  353. s = appconfig_get(root, section, name, s);
  354. if(!s) return value;
  355. return appconfig_test_boolean_value(s);
  356. }
  357. int appconfig_get_boolean_ondemand(struct config *root, const char *section, const char *name, int value)
  358. {
  359. char *s;
  360. if(value == CONFIG_BOOLEAN_AUTO)
  361. s = "auto";
  362. else if(value == CONFIG_BOOLEAN_NO)
  363. s = "no";
  364. else
  365. s = "yes";
  366. s = appconfig_get(root, section, name, s);
  367. if(!s) return value;
  368. if(!strcmp(s, "yes"))
  369. return CONFIG_BOOLEAN_YES;
  370. else if(!strcmp(s, "no"))
  371. return CONFIG_BOOLEAN_NO;
  372. else if(!strcmp(s, "auto") || !strcmp(s, "on demand"))
  373. return CONFIG_BOOLEAN_AUTO;
  374. return value;
  375. }
  376. const char *appconfig_set_default(struct config *root, const char *section, const char *name, const char *value)
  377. {
  378. struct config_option *cv;
  379. debug(D_CONFIG, "request to set default config in section '%s', name '%s', value '%s'", section, name, value);
  380. struct section *co = appconfig_section_find(root, section);
  381. if(!co) return appconfig_set(root, section, name, value);
  382. cv = appconfig_option_index_find(co, name, 0);
  383. if(!cv) return appconfig_set(root, section, name, value);
  384. cv->flags |= CONFIG_VALUE_USED;
  385. if(cv->flags & CONFIG_VALUE_LOADED)
  386. return cv->value;
  387. if(strcmp(cv->value, value) != 0) {
  388. cv->flags |= CONFIG_VALUE_CHANGED;
  389. freez(cv->value);
  390. cv->value = strdupz(value);
  391. }
  392. return cv->value;
  393. }
  394. const char *appconfig_set(struct config *root, const char *section, const char *name, const char *value)
  395. {
  396. struct config_option *cv;
  397. debug(D_CONFIG, "request to set config in section '%s', name '%s', value '%s'", section, name, value);
  398. struct section *co = appconfig_section_find(root, section);
  399. if(!co) co = appconfig_section_create(root, section);
  400. cv = appconfig_option_index_find(co, name, 0);
  401. if(!cv) cv = appconfig_value_create(co, name, value);
  402. cv->flags |= CONFIG_VALUE_USED;
  403. if(strcmp(cv->value, value) != 0) {
  404. cv->flags |= CONFIG_VALUE_CHANGED;
  405. freez(cv->value);
  406. cv->value = strdupz(value);
  407. }
  408. return value;
  409. }
  410. long long appconfig_set_number(struct config *root, const char *section, const char *name, long long value)
  411. {
  412. char buffer[100];
  413. sprintf(buffer, "%lld", value);
  414. appconfig_set(root, section, name, buffer);
  415. return value;
  416. }
  417. LONG_DOUBLE appconfig_set_float(struct config *root, const char *section, const char *name, LONG_DOUBLE value)
  418. {
  419. char buffer[100];
  420. sprintf(buffer, "%0.5" LONG_DOUBLE_MODIFIER, value);
  421. appconfig_set(root, section, name, buffer);
  422. return value;
  423. }
  424. int appconfig_set_boolean(struct config *root, const char *section, const char *name, int value)
  425. {
  426. char *s;
  427. if(value) s = "yes";
  428. else s = "no";
  429. appconfig_set(root, section, name, s);
  430. return value;
  431. }
  432. int appconfig_get_duration(struct config *root, const char *section, const char *name, const char *value)
  433. {
  434. int result = 0;
  435. const char *s;
  436. s = appconfig_get(root, section, name, value);
  437. if(!s) goto fallback;
  438. if(!config_parse_duration(s, &result)) {
  439. error("config option '[%s].%s = %s' is configured with an valid duration", section, name, s);
  440. goto fallback;
  441. }
  442. return result;
  443. fallback:
  444. if(!config_parse_duration(value, &result))
  445. error("INTERNAL ERROR: default duration supplied for option '[%s].%s = %s' is not a valid duration", section, name, value);
  446. return result;
  447. }
  448. // ----------------------------------------------------------------------------
  449. // config load/save
  450. int appconfig_load(struct config *root, char *filename, int overwrite_used, const char *section_name)
  451. {
  452. int line = 0;
  453. struct section *co = NULL;
  454. int is_exporter_config = 0;
  455. int _connectors = 0; // number of exporting connector sections we have
  456. char working_instance[CONFIG_MAX_NAME + 1];
  457. char working_connector[CONFIG_MAX_NAME + 1];
  458. struct section *working_connector_section = NULL;
  459. int global_exporting_section = 0;
  460. char buffer[CONFIG_FILE_LINE_MAX + 1], *s;
  461. if(!filename) filename = CONFIG_DIR "/" CONFIG_FILENAME;
  462. debug(D_CONFIG, "CONFIG: opening config file '%s'", filename);
  463. FILE *fp = fopen(filename, "r");
  464. if(!fp) {
  465. // info("CONFIG: cannot open file '%s'. Using internal defaults.", filename);
  466. return 0;
  467. }
  468. uint32_t section_hash = 0;
  469. if(section_name) {
  470. section_hash = simple_hash(section_name);
  471. }
  472. is_exporter_config = (strstr(filename, EXPORTING_CONF) != NULL);
  473. while(fgets(buffer, CONFIG_FILE_LINE_MAX, fp) != NULL) {
  474. buffer[CONFIG_FILE_LINE_MAX] = '\0';
  475. line++;
  476. s = trim(buffer);
  477. if(!s || *s == '#') {
  478. debug(D_CONFIG, "CONFIG: ignoring line %d of file '%s', it is empty.", line, filename);
  479. continue;
  480. }
  481. int len = (int) strlen(s);
  482. if(*s == '[' && s[len - 1] == ']') {
  483. // new section
  484. s[len - 1] = '\0';
  485. s++;
  486. if (is_exporter_config) {
  487. global_exporting_section =
  488. !(strcmp(s, CONFIG_SECTION_EXPORTING)) || !(strcmp(s, CONFIG_SECTION_PROMETHEUS));
  489. if (unlikely(!global_exporting_section)) {
  490. int rc;
  491. rc = is_valid_connector(s, 0);
  492. if (likely(rc)) {
  493. strncpy(working_connector, s, CONFIG_MAX_NAME);
  494. s = s + rc + 1;
  495. if (unlikely(!(*s))) {
  496. _connectors++;
  497. sprintf(buffer, "instance_%d", _connectors);
  498. s = buffer;
  499. }
  500. strncpy(working_instance, s, CONFIG_MAX_NAME);
  501. working_connector_section = NULL;
  502. if (unlikely(appconfig_section_find(root, working_instance))) {
  503. error("Instance (%s) already exists", working_instance);
  504. co = NULL;
  505. continue;
  506. }
  507. } else {
  508. co = NULL;
  509. error("Section (%s) does not specify a valid connector", s);
  510. continue;
  511. }
  512. }
  513. }
  514. co = appconfig_section_find(root, s);
  515. if(!co) co = appconfig_section_create(root, s);
  516. if(co && section_name && overwrite_used && section_hash == co->hash && !strcmp(section_name, co->name)) {
  517. config_section_wrlock(co);
  518. struct config_option *cv2 = co->values;
  519. while (cv2) {
  520. struct config_option *save = cv2->next;
  521. struct config_option *found = appconfig_option_index_del(co, cv2);
  522. if(found != cv2)
  523. error("INTERNAL ERROR: Cannot remove '%s' from section '%s', it was not inserted before.",
  524. cv2->name, co->name);
  525. freez(cv2->name);
  526. freez(cv2->value);
  527. freez(cv2);
  528. cv2 = save;
  529. }
  530. co->values = NULL;
  531. config_section_unlock(co);
  532. }
  533. continue;
  534. }
  535. if(!co) {
  536. // line outside a section
  537. error("CONFIG: ignoring line %d ('%s') of file '%s', it is outside all sections.", line, s, filename);
  538. continue;
  539. }
  540. if(section_name && overwrite_used && section_hash != co->hash && strcmp(section_name, co->name)) {
  541. continue;
  542. }
  543. char *name = s;
  544. char *value = strchr(s, '=');
  545. if(!value) {
  546. error("CONFIG: ignoring line %d ('%s') of file '%s', there is no = in it.", line, s, filename);
  547. continue;
  548. }
  549. *value = '\0';
  550. value++;
  551. name = trim(name);
  552. value = trim(value);
  553. if(!name || *name == '#') {
  554. error("CONFIG: ignoring line %d of file '%s', name is empty.", line, filename);
  555. continue;
  556. }
  557. if(!value) value = "";
  558. struct config_option *cv = appconfig_option_index_find(co, name, 0);
  559. if (!cv) {
  560. cv = appconfig_value_create(co, name, value);
  561. if (likely(is_exporter_config) && unlikely(!global_exporting_section)) {
  562. if (unlikely(!working_connector_section)) {
  563. working_connector_section = appconfig_section_find(root, working_connector);
  564. if (!working_connector_section)
  565. working_connector_section = appconfig_section_create(root, working_connector);
  566. if (likely(working_connector_section)) {
  567. add_connector_instance(working_connector_section, co);
  568. }
  569. }
  570. }
  571. } else {
  572. if (((cv->flags & CONFIG_VALUE_USED) && overwrite_used) || !(cv->flags & CONFIG_VALUE_USED)) {
  573. debug(
  574. D_CONFIG, "CONFIG: line %d of file '%s', overwriting '%s/%s'.", line, filename, co->name, cv->name);
  575. freez(cv->value);
  576. cv->value = strdupz(value);
  577. } else
  578. debug(
  579. D_CONFIG,
  580. "CONFIG: ignoring line %d of file '%s', '%s/%s' is already present and used.",
  581. line,
  582. filename,
  583. co->name,
  584. cv->name);
  585. }
  586. cv->flags |= CONFIG_VALUE_LOADED;
  587. }
  588. fclose(fp);
  589. return 1;
  590. }
  591. void appconfig_generate(struct config *root, BUFFER *wb, int only_changed)
  592. {
  593. int i, pri;
  594. struct section *co;
  595. struct config_option *cv;
  596. for(i = 0; i < 3 ;i++) {
  597. switch(i) {
  598. case 0:
  599. buffer_strcat(wb,
  600. "# netdata configuration\n"
  601. "#\n"
  602. "# You can download the latest version of this file, using:\n"
  603. "#\n"
  604. "# wget -O /etc/netdata/netdata.conf http://localhost:19999/netdata.conf\n"
  605. "# or\n"
  606. "# curl -o /etc/netdata/netdata.conf http://localhost:19999/netdata.conf\n"
  607. "#\n"
  608. "# You can uncomment and change any of the options below.\n"
  609. "# The value shown in the commented settings, is the default value.\n"
  610. "#\n"
  611. "\n# global netdata configuration\n");
  612. break;
  613. case 1:
  614. buffer_strcat(wb, "\n\n# per plugin configuration\n");
  615. break;
  616. case 2:
  617. buffer_strcat(wb, "\n\n# per chart configuration\n");
  618. break;
  619. }
  620. appconfig_wrlock(root);
  621. for(co = root->first_section; co ; co = co->next) {
  622. if(!strcmp(co->name, CONFIG_SECTION_GLOBAL)
  623. || !strcmp(co->name, CONFIG_SECTION_WEB)
  624. || !strcmp(co->name, CONFIG_SECTION_STATSD)
  625. || !strcmp(co->name, CONFIG_SECTION_PLUGINS)
  626. || !strcmp(co->name, CONFIG_SECTION_CLOUD)
  627. || !strcmp(co->name, CONFIG_SECTION_REGISTRY)
  628. || !strcmp(co->name, CONFIG_SECTION_HEALTH)
  629. || !strcmp(co->name, CONFIG_SECTION_STREAM)
  630. || !strcmp(co->name, CONFIG_SECTION_HOST_LABEL)
  631. || !strcmp(co->name, CONFIG_SECTION_ML)
  632. )
  633. pri = 0;
  634. else if(!strncmp(co->name, "plugin:", 7)) pri = 1;
  635. else pri = 2;
  636. if(i == pri) {
  637. int loaded = 0;
  638. int used = 0;
  639. int changed = 0;
  640. int count = 0;
  641. config_section_wrlock(co);
  642. for(cv = co->values; cv ; cv = cv->next) {
  643. used += (cv->flags & CONFIG_VALUE_USED)?1:0;
  644. loaded += (cv->flags & CONFIG_VALUE_LOADED)?1:0;
  645. changed += (cv->flags & CONFIG_VALUE_CHANGED)?1:0;
  646. count++;
  647. }
  648. config_section_unlock(co);
  649. if(!count) continue;
  650. if(only_changed && !changed && !loaded) continue;
  651. if(!used) {
  652. buffer_sprintf(wb, "\n# section '%s' is not used.", co->name);
  653. }
  654. buffer_sprintf(wb, "\n[%s]\n", co->name);
  655. config_section_wrlock(co);
  656. for(cv = co->values; cv ; cv = cv->next) {
  657. if(used && !(cv->flags & CONFIG_VALUE_USED)) {
  658. buffer_sprintf(wb, "\n\t# option '%s' is not used.\n", cv->name);
  659. }
  660. 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);
  661. }
  662. config_section_unlock(co);
  663. }
  664. }
  665. appconfig_unlock(root);
  666. }
  667. }
  668. /**
  669. * Parse Duration
  670. *
  671. * Parse the string setting the result
  672. *
  673. * @param string the timestamp string
  674. * @param result the output variable
  675. *
  676. * @return It returns 1 on success and 0 otherwise
  677. */
  678. int config_parse_duration(const char* string, int* result) {
  679. while(*string && isspace(*string)) string++;
  680. if(unlikely(!*string)) goto fallback;
  681. if(*string == 'n' && !strcmp(string, "never")) {
  682. // this is a valid option
  683. *result = 0;
  684. return 1;
  685. }
  686. // make sure it is a number
  687. if(!(isdigit(*string) || *string == '+' || *string == '-')) goto fallback;
  688. char *e = NULL;
  689. calculated_number n = str2ld(string, &e);
  690. if(e && *e) {
  691. switch (*e) {
  692. case 'Y':
  693. *result = (int) (n * 31536000);
  694. break;
  695. case 'M':
  696. *result = (int) (n * 2592000);
  697. break;
  698. case 'w':
  699. *result = (int) (n * 604800);
  700. break;
  701. case 'd':
  702. *result = (int) (n * 86400);
  703. break;
  704. case 'h':
  705. *result = (int) (n * 3600);
  706. break;
  707. case 'm':
  708. *result = (int) (n * 60);
  709. break;
  710. case 's':
  711. default:
  712. *result = (int) (n);
  713. break;
  714. }
  715. }
  716. else
  717. *result = (int)(n);
  718. return 1;
  719. fallback:
  720. *result = 0;
  721. return 0;
  722. }
  723. struct section *appconfig_get_section(struct config *root, const char *name)
  724. {
  725. return appconfig_section_find(root, name);
  726. }