9 #define CONFIG_FILE_LINE_MAX 4096
11 pthread_rwlock_t config_rwlock = PTHREAD_RWLOCK_INITIALIZER;
14 char name[CONFIG_MAX_NAME + 1];
15 char value[CONFIG_MAX_VALUE + 1];
17 unsigned long hash; // a simple hash to speed up searching
18 // we first compare hashes, and only if the hashes are equal we do string comparisons
20 int loaded; // loaded from the user config
21 int used; // has been accessed from the program
22 int changed; // changed from the internal default
24 struct config_value *next;
28 char name[CONFIG_MAX_NAME + 1];
30 unsigned long hash; // a simple hash to speed up searching
31 // we first compare hashes, and only if the hashes are equal we do string comparisons
33 struct config_value *values;
36 } *config_root = NULL;
38 struct config_value *config_value_create(struct config *co, const char *name, const char *value)
40 debug(D_CONFIG, "Creating config entry for name '%s', value '%s', in section '%s'.", name, value, co->name);
42 struct config_value *cv = calloc(1, sizeof(struct config_value));
43 if(!cv) fatal("Cannot allocate config_value");
45 strncpy(cv->name, name, CONFIG_MAX_NAME);
46 strncpy(cv->value, value, CONFIG_MAX_VALUE);
47 cv->hash = simple_hash(cv->name);
49 // no need for string termination, due to calloc()
51 struct config_value *cv2 = co->values;
53 while (cv2->next) cv2 = cv2->next;
61 struct config *config_create(const char *section)
63 debug(D_CONFIG, "Creating section '%s'.", section);
65 struct config *co = calloc(1, sizeof(struct config));
66 if(!co) fatal("Cannot allocate config");
68 strncpy(co->name, section, CONFIG_MAX_NAME);
69 co->hash = simple_hash(co->name);
71 // no need for string termination, due to calloc()
73 struct config *co2 = config_root;
75 while (co2->next) co2 = co2->next;
78 else config_root = co;
83 struct config *config_find_section(const char *section)
86 unsigned long hash = simple_hash(section);
88 for(co = config_root; co ; co = co->next)
90 if(strcmp(co->name, section) == 0)
96 int load_config(char *filename, int overwrite_used)
99 struct config *co = NULL;
101 pthread_rwlock_wrlock(&config_rwlock);
103 char buffer[CONFIG_FILE_LINE_MAX + 1], *s;
105 if(!filename) filename = CONFIG_DIR "/" CONFIG_FILENAME;
106 FILE *fp = fopen(filename, "r");
108 error("Cannot open file '%s'", CONFIG_DIR "/" CONFIG_FILENAME);
109 pthread_rwlock_unlock(&config_rwlock);
113 while(fgets(buffer, CONFIG_FILE_LINE_MAX, fp) != NULL) {
114 buffer[CONFIG_FILE_LINE_MAX] = '\0';
119 debug(D_CONFIG, "Ignoring line %d, it is empty.", line);
124 if(*s == '[' && s[len - 1] == ']') {
129 co = config_find_section(s);
130 if(!co) co = config_create(s);
136 // line outside a section
137 error("Ignoring line %d ('%s'), it is outsize all sections.", line, s);
142 char *value = strchr(s, '=');
144 error("Ignoring line %d ('%s'), there is no = in it.", line, s);
154 error("Ignoring line %d, name is empty.", line);
158 debug(D_CONFIG, "Ignoring line %d, value is empty.", line);
162 struct config_value *cv;
163 for(cv = co->values; cv ; cv = cv->next)
164 if(strcmp(cv->name, name) == 0) break;
166 if(!cv) cv = config_value_create(co, name, value);
168 if((cv->used && overwrite_used) || !cv->used) {
169 debug(D_CONFIG, "Overwriting '%s/%s'.", line, co->name, cv->name);
170 strncpy(cv->value, value, CONFIG_MAX_VALUE);
171 // termination is already there
174 debug(D_CONFIG, "Ignoring line %d, '%s/%s' is already present and used.", line, co->name, cv->name);
181 pthread_rwlock_unlock(&config_rwlock);
185 char *config_get(const char *section, const char *name, const char *default_value)
187 struct config_value *cv;
189 debug(D_CONFIG, "request to get config in section '%s', name '%s', default_value '%s'", section, name, default_value);
191 pthread_rwlock_rdlock(&config_rwlock);
193 struct config *co = config_find_section(section);
194 if(!co) co = config_create(section);
196 unsigned long hash = simple_hash(name);
197 for(cv = co->values; cv ; cv = cv->next)
199 if(strcmp(cv->name, name) == 0)
202 if(!cv) cv = config_value_create(co, name, default_value);
205 if(cv->loaded || cv->changed) {
206 // this is a loaded value from the config file
207 // if it is different that the default, mark it
208 if(strcmp(cv->value, default_value) != 0) cv->changed = 1;
211 // this is not loaded from the config
212 // copy the default value to it
213 strncpy(cv->value, default_value, CONFIG_MAX_VALUE);
216 pthread_rwlock_unlock(&config_rwlock);
220 long long config_get_number(const char *section, const char *name, long long value)
222 char buffer[100], *s;
223 sprintf(buffer, "%lld", value);
225 s = config_get(section, name, buffer);
226 return strtoll(s, NULL, 0);
229 int config_get_boolean(const char *section, const char *name, int value)
235 s = config_get(section, name, s);
237 if(strcmp(s, "yes") == 0 || strcmp(s, "true") == 0 || strcmp(s, "1") == 0) {
247 const char *config_set(const char *section, const char *name, const char *value)
249 struct config_value *cv;
251 debug(D_CONFIG, "request to set config in section '%s', name '%s', value '%s'", section, name, value);
253 pthread_rwlock_wrlock(&config_rwlock);
255 struct config *co = config_find_section(section);
256 if(!co) co = config_create(section);
258 unsigned long hash = simple_hash(name);
259 for(cv = co->values; cv ; cv = cv->next)
261 if(strcmp(cv->name, name) == 0)
264 if(!cv) cv = config_value_create(co, name, value);
267 if(strcmp(cv->value, value) != 0) cv->changed = 1;
269 strncpy(cv->value, value, CONFIG_MAX_VALUE);
270 // termination is already there
272 pthread_rwlock_unlock(&config_rwlock);
277 long long config_set_number(const char *section, const char *name, long long value)
280 sprintf(buffer, "%lld", value);
282 config_set(section, name, buffer);
287 int config_set_boolean(const char *section, const char *name, int value)
293 config_set(section, name, s);
298 void generate_config(struct web_buffer *wb, int only_changed)
302 struct config_value *cv;
304 for(i = 0; i < 3 ;i++) {
305 web_buffer_increase(wb, 500);
308 web_buffer_printf(wb,
309 "# NetData Configuration\n"
310 "# You can uncomment and change any of the options bellow.\n"
311 "# The value shown in the commented settings, is the default value.\n"
312 "\n# global netdata configuration\n");
316 web_buffer_printf(wb, "\n\n# per plugin configuration\n");
320 web_buffer_printf(wb, "\n\n# per chart configuration\n");
324 for(co = config_root; co ; co = co->next) {
325 if(strcmp(co->name, "global") == 0 || strcmp(co->name, "plugins") == 0) pri = 0;
326 else if(strncmp(co->name, "plugin:", 7) == 0) pri = 1;
333 for(cv = co->values; cv ; cv = cv->next) {
335 changed += cv->changed;
340 if(only_changed && !changed) continue;
343 web_buffer_increase(wb, 500);
344 web_buffer_printf(wb, "\n# node '%s' is not used.", co->name);
347 web_buffer_increase(wb, CONFIG_MAX_NAME + 4);
348 web_buffer_printf(wb, "\n[%s]\n", co->name);
350 for(cv = co->values; cv ; cv = cv->next) {
352 if(used && !cv->used) {
353 web_buffer_increase(wb, CONFIG_MAX_NAME + 200);
354 web_buffer_printf(wb, "\n\t# option '%s' is not used.\n", cv->name);
356 web_buffer_increase(wb, CONFIG_MAX_NAME + CONFIG_MAX_VALUE + 5);
357 web_buffer_printf(wb, "\t%s%s = %s\n", (!cv->changed && cv->used)?"# ":"", cv->name, cv->value);