]> git.itanic.dy.fi Git - rrdd/blob - config.c
config: Fix copy paste errors in error messages
[rrdd] / config.c
1 #include <stdlib.h>
2 #include <string.h>
3
4 #include "debug.h"
5 #include "config.h"
6 #include "rrdtool.h"
7 #include "parser.h"
8
9 #define RRD_DATABASE_LIST "rrd_database"
10 #define RRD_DATABASE_NAME "name"
11
12 static int read_strings_from_list(config_setting_t *list, const char ***strings)
13 {
14         config_setting_t *string;
15         int j;
16         int str_count = config_setting_length(list);
17         const char **strs;
18
19         strs = calloc(sizeof(*strs), str_count + 1);
20
21         for (j = 0; j < str_count; j++) {
22                 const char *str;
23
24                 string = config_setting_get_elem(list, j);
25                 str = config_setting_get_string(string);
26                 strs[j] = strdup(str);
27         }
28         *strings = strs;
29
30         return 0;
31 }
32
33 static int parse_images(config_setting_t *list, struct rrd_database *db)
34 {
35         int i, count;
36         config_setting_t *image, *str_list;
37         const char *database = NULL, *filename = NULL, *timestart = NULL;
38         const char *timeend = NULL, *imageformat = NULL;
39         const char **options = NULL, **text = NULL;
40         int width = 0, height = 0, text_lead = 0;
41
42         count = config_setting_length(list);
43
44         pr_info("%s: Parsing %d images\n", db->name, count);
45         db->images = calloc(sizeof(*db->images), count + 1);
46
47         for (i = 0; i < count; i++) {
48                 image = config_setting_get_elem(list, i);
49                 db->images[i] = calloc(sizeof(*db->images[i]), 1);
50
51                 config_setting_lookup_string(image, "database", &database);
52                 config_setting_lookup_int(image, "text_lead", &text_lead);
53
54                 /*
55                  * The config_setting_lookup_* functions will leave
56                  * the destination unchanged in case requested value
57                  * is not found. If that is the case, the value from
58                  * previous image group is used. That makes it
59                  * possible for the user to only define once all
60                  * fields and then leave identical fields unset on the
61                  * following groups, making it easier to define many
62                  * almost identical images.
63                  */
64
65                 config_setting_lookup_string(image, "filename", &filename);
66                 if (!filename) {
67                         pr_err("Database %s does not have \"filename\" entry "
68                                 " in image data\n",
69                                 db->name);
70                         return -1;
71                 }
72
73                 config_setting_lookup_int(image, "width", &width);
74                 if (!width) {
75                         pr_err("Database %s does not have \"width\" entry "
76                                 " in image data\n",
77                                 db->name);
78                         return -1;
79                 }
80
81                 config_setting_lookup_int(image, "height", &height);
82                 if (!height) {
83                         pr_err("Database %s does not have \"height\" entry "
84                                 " in image data\n",
85                                 db->name);
86                         return -1;
87                 }
88
89                 config_setting_lookup_string(image, "timestart", &timestart);
90                 if (!timestart) {
91                         pr_err("Database %s does not have \"timestart\" entry "
92                                 " in image data\n",
93                                 db->name);
94                         return -1;
95                 }
96
97                 config_setting_lookup_string(image, "timeend", &timeend);
98                 if (!timeend) {
99                         pr_err("Database %s does not have \"timeend\" entry "
100                                 " in image data\n",
101                                 db->name);
102                         return -1;
103                 }
104
105                 config_setting_lookup_string(image, "imageformat",
106                                         &imageformat);
107                 if (!imageformat) {
108                         pr_err("Database %s does not have \"imageformat\" "\
109                                 "entry in image data\n",
110                                 db->name);
111                         return -1;
112                 }
113
114                 str_list = config_setting_get_member(image, "options");
115                 if (str_list)
116                         read_strings_from_list(str_list, &options);
117
118                 str_list = config_setting_get_member(image, "text");
119                 if (str_list)
120                         read_strings_from_list(str_list, &text);
121
122                 db->images[i]->rrd_database     =
123                         database ? strdup(database) : NULL;
124                 db->images[i]->image_filename   = strdup(filename);
125                 db->images[i]->width            = width;
126                 db->images[i]->height           = height;
127                 strncpy(db->images[i]->timestart, timestart,
128                         sizeof(db->images[i]->timestart));
129                 strncpy(db->images[i]->timeend, timeend,
130                         sizeof(db->images[i]->timeend));
131                 strncpy(db->images[i]->imageformat, imageformat,
132                         sizeof(db->images[i]->imageformat));
133                 db->images[i]->options          = options;
134                 db->images[i]->text_lead        = text_lead;
135                 db->images[i]->text             = text;
136         }
137
138         return 0;
139 }
140
141 static int (*str_to_parser(const char *str))(char *rrd_data, const char **parser_data)
142 {
143         if (!str)
144                 return NULL;
145
146         if (!strcmp(str, "cpu"))
147                 return cpu_parser;
148
149         if (!strcmp(str, "mem"))
150                 return mem_parser;
151
152         if (!strcmp(str, "cpu_mem"))
153                 return cpu_mem_parser;
154
155         if (!strcmp(str, "digitemp"))
156                 return digitemp_parser;
157
158         if (!strcmp(str, "digitemp_mod"))
159                 return digitemp_parser_mod;
160
161         if (!strcmp(str, "script"))
162                 return script_parser;
163
164         if (!strcmp(str, "netstats"))
165                 return netstats_parser;
166
167         if (!strcmp(str, "onewire"))
168                 return onewire_parser;
169
170         return NULL;
171 }
172
173 static int parse_data_sources(config_setting_t *rrd, struct rrd_database *db)
174 {
175         config_setting_t *list, *group;
176         int i, count;
177         const char *type = NULL, *name = NULL;
178         int heartbeat = 0;
179         double min = 0;
180         double max = 0;
181
182         list = config_setting_get_member(rrd, "sources");
183         if (!list) {
184                 pr_info("No data sources\n");
185                 return 0;
186         }
187
188         if (!config_setting_is_list(list)) {
189                 pr_err("Data sources have no list\n");
190                 return 0;
191         }
192
193         count = config_setting_length(list);
194         db->sources = calloc(sizeof(*db->sources), count + 1);
195
196         for (i = 0; i < count; i++) {
197                 group = config_setting_get_elem(list, i);
198
199                 config_setting_lookup_string(group, "type", &type);
200                 config_setting_lookup_string(group, "name", &name);
201                 config_setting_lookup_float(group, "min", &min);
202                 config_setting_lookup_float(group, "max", &max);
203                 config_setting_lookup_int(group, "heartbeat", &heartbeat);
204
205                 db->sources[i].type = strdup(type);
206                 db->sources[i].name = strdup(name);
207                 db->sources[i].heartbeat = heartbeat;
208                 db->sources[i].min = min;
209                 db->sources[i].max = max;
210         }
211
212         return 0;
213 }
214
215 static int parse_archives(config_setting_t *rrd, struct rrd_database *db)
216 {
217         config_setting_t *list, *group;
218         int i, count;
219         const char *type = NULL;
220         double xff = 0;
221         int steps = 0;
222         int rows = 0;
223
224         list = config_setting_get_member(rrd, "archives");
225         if (!list) {
226                 pr_info("No archive found\n");
227                 return 0;
228         }
229
230         if (!config_setting_is_list(list)) {
231                 pr_err("Archive does not contain a list\n");
232                 return 0;
233         }
234
235         count = config_setting_length(list);
236         db->archives = calloc(sizeof(*db->archives), count + 1);
237
238         for (i = 0; i < count; i++) {
239                 group = config_setting_get_elem(list, i);
240
241                 config_setting_lookup_string(group, "type", &type);
242                 config_setting_lookup_float(group, "xff", &xff);
243                 config_setting_lookup_int(group, "steps", &steps);
244                 config_setting_lookup_int(group, "rows", &rows);
245
246                 db->archives[i].type = strdup(type);
247                 db->archives[i].xff = xff;
248                 db->archives[i].steps = steps;
249                 db->archives[i].rows = rows;
250         }
251
252         return 0;
253 }
254
255 static int parse_database(config_setting_t *rrd, struct rrd_database *db)
256 {
257         config_setting_t *list, *str_list;
258         const char *name, *parser = NULL, *filename, **parser_data;
259
260         if (!config_setting_lookup_string(rrd, "name", &name)) {
261                 pr_err("Database entry does not contain name\n");
262                 return -1;
263         }
264
265         pr_info("parsing database %s\n", name);
266         db->name = strdup(name);
267
268         if (!config_setting_lookup_string(rrd, "filename", &filename)) {
269                 pr_err("Database %s does not contain filename\n", db->name);
270                 return -1;
271         }
272         db->filename = strdup(filename);
273
274         if (!config_setting_lookup_int(rrd, "interval", &db->interval)) {
275                 pr_err("Database %s does not have interval set\n", name);
276                 return -1;
277         }
278
279         /* Parser is not a mandatory parameter */
280         config_setting_lookup_string(rrd, "parser", &parser);
281         db->parse = str_to_parser(parser);
282
283         list = config_setting_get_member(rrd, "image");
284         parse_images(list, db);
285         parse_data_sources(rrd, db);
286         parse_archives(rrd, db);
287
288         str_list = config_setting_get_member(rrd, "parser_data");
289         if (str_list) {
290                 read_strings_from_list(str_list, &parser_data);
291                 db->parser_data = parser_data;
292         }
293
294         return 0;
295 }
296
297 struct rrd_database **populate_database(const char *conffile)
298 {
299         struct rrd_database **rrd_db = NULL;
300         config_t config;
301         config_setting_t *rrd_database;
302         int i, count;
303
304         config_init(&config);
305
306         if (!config_read_file(&config, conffile)) {
307                 pr_err("%s:%d - %s\n", config_error_file(&config),
308                         config_error_line(&config),
309                         config_error_text(&config));
310                 goto out;
311         }
312
313         rrd_database = config_lookup(&config, "rrd_database");
314         count = config_setting_length(rrd_database);
315
316         /*
317          * Allocate one element extra. The last one is zeroed out to
318          * indicate the end of the db list
319          */
320         rrd_db = calloc(count + 1, sizeof(*rrd_db));
321
322         pr_info("There are %d database entries\n", count);
323
324         for (i = 0; i < count; i++) {
325                 config_setting_t *rrd;
326                 rrd_db[i] = calloc(1, sizeof(*rrd_db[i]));
327                 rrd = config_setting_get_elem(rrd_database, i);
328                 parse_database(rrd, rrd_db[i]);
329         }
330
331 out:
332         config_destroy(&config);
333         return rrd_db;
334 }
335
336 #define CONFIG_ADD_STRING(_config, _setting, _name, _val)               \
337         do {                                                            \
338                 _setting = config_setting_add(_config, _name,           \
339                                         CONFIG_TYPE_STRING);            \
340                 config_setting_set_string(_setting, _val);              \
341         } while (0);                                                    \
342
343 #define CONFIG_ADD_INT(_config, _setting, _name, _val)                  \
344         do {                                                            \
345                 _setting = config_setting_add(_config, _name,           \
346                                         CONFIG_TYPE_INT);               \
347                 config_setting_set_int(_setting, _val);                 \
348         } while (0);                                                    \
349
350 #define CONFIG_ADD_FLOAT(_config, _setting, _name, _val)                \
351         do {                                                            \
352                 _setting = config_setting_add(_config, _name,           \
353                                         CONFIG_TYPE_FLOAT);             \
354                 config_setting_set_float(_setting, _val);               \
355         } while (0);                                                    \
356
357 static void put_strings_to_list(config_setting_t *config,
358                                 const char *entry_name, const char **strings)
359 {
360         config_setting_t *list, *setting;
361         int i;
362
363         list = config_setting_add(config, entry_name, CONFIG_TYPE_LIST);
364         for (i = 0; strings[i]; i++)
365                 CONFIG_ADD_STRING(list, setting, NULL, strings[i]);
366 }
367
368 static void put_image_to_list(config_setting_t *config,
369                         struct rrd_image *image)
370 {
371         config_setting_t *setting, *group;
372
373         group = config_setting_add(config, "image", CONFIG_TYPE_GROUP);
374
375         CONFIG_ADD_STRING(group, setting, "rrd_database", image->rrd_database);
376         CONFIG_ADD_STRING(group, setting, "filename", image->image_filename);
377         CONFIG_ADD_INT(group, setting, "width", image->width);
378         CONFIG_ADD_INT(group, setting, "height", image->height);
379         CONFIG_ADD_STRING(group, setting, "timestart", image->timestart);
380         CONFIG_ADD_STRING(group, setting, "timeend", image->timeend);
381         CONFIG_ADD_STRING(group, setting, "imageformat", image->imageformat);
382
383         put_strings_to_list(group, "options", image->options);
384
385         CONFIG_ADD_INT(group, setting, "text_lead", image->text_lead);
386
387         put_strings_to_list(group, "text", image->text);
388 }
389
390 static void put_data_source_to_list(config_setting_t *list,
391                                 struct rrd_data_source *source)
392 {
393         config_setting_t *setting, *group;
394
395         group = config_setting_add(list, "data_source", CONFIG_TYPE_GROUP);
396
397         CONFIG_ADD_STRING(group, setting, "type", source->type);
398         CONFIG_ADD_STRING(group, setting, "name", source->name);
399         CONFIG_ADD_INT(group, setting, "heartbeat", source->heartbeat);
400         CONFIG_ADD_FLOAT(group, setting, "min", source->min);
401         CONFIG_ADD_FLOAT(group, setting, "max", source->max);
402 }
403
404 static void put_archive_to_list(config_setting_t *list,
405                                 struct rrd_archive *archive)
406 {
407         config_setting_t *setting, *group;
408
409         group = config_setting_add(list, "archive", CONFIG_TYPE_GROUP);
410
411         CONFIG_ADD_STRING(group, setting, "type", archive->type);
412         CONFIG_ADD_FLOAT(group, setting, "xff", archive->xff);
413         CONFIG_ADD_INT(group, setting, "steps", archive->steps);
414         CONFIG_ADD_INT(group, setting, "rows", archive->rows);
415 }
416
417 static char *parser_to_str(int (*parser)(char *rrd_data, const char **parser_data))
418 {
419         if (parser == cpu_parser)
420                 return "cpu";
421
422         if (parser == mem_parser)
423                 return "mem";
424
425         if (parser == cpu_mem_parser)
426                 return "cpu_mem";
427
428         if (parser == digitemp_parser)
429                 return "digitemp";
430
431         if (parser == digitemp_parser_mod)
432                 return "digitemp_mod";
433
434         if (parser == script_parser)
435                 return "script";
436
437         if (parser == netstats_parser)
438                 return "netstats";
439
440         if (parser == onewire_parser)
441                 return "onewire";
442
443         return NULL;
444 }
445
446 static void put_database_to_list(config_setting_t *config,
447                                 struct rrd_database *db)
448 {
449         config_setting_t *setting;
450         config_setting_t *list, *group;
451         char *str = parser_to_str(db->parse);
452         int i;
453
454         group = config_setting_add(config, RRD_DATABASE_LIST,
455                                 CONFIG_TYPE_GROUP);
456
457         CONFIG_ADD_STRING(group, setting, "name", db->name);
458         CONFIG_ADD_STRING(group, setting, "filename", db->filename);
459         CONFIG_ADD_INT(group, setting, "interval", db->interval);
460         CONFIG_ADD_STRING(group, setting, "parser", str);
461
462         if (db->parser_data)
463                 put_strings_to_list(group, "parser_data", db->parser_data);
464
465         list = config_setting_add(group, "image", CONFIG_TYPE_LIST);
466         for (i = 0; db->images[i]; i++) {
467                 put_image_to_list(list, db->images[i]);
468         }
469
470         if (db->sources) {
471                 list = config_setting_add(group, "sources", CONFIG_TYPE_LIST);
472                 for (i = 0; db->sources[i].type; i++) {
473                         put_data_source_to_list(list, &db->sources[i]);
474                 }
475         }
476
477         if (db->archives) {
478                 list = config_setting_add(group, "archives", CONFIG_TYPE_LIST);
479                 for (i = 0; db->archives[i].type; i++) {
480                         put_archive_to_list(list, &db->archives[i]);
481                 }
482         }
483 }
484
485 int write_database(const char *conffile, struct rrd_database **rrd_db)
486 {
487         config_t config;
488         config_setting_t *root, *rrd_database_list;
489         int i;
490         int ret;
491
492         config_init(&config);
493
494         config_set_tab_width(&config, 4);
495
496         root = config_root_setting(&config);
497
498         rrd_database_list = config_setting_add(root, RRD_DATABASE_LIST,
499                                         CONFIG_TYPE_LIST);
500         for (i = 0; rrd_db[i]; i++) {
501                 put_database_to_list(rrd_database_list, rrd_db[i]);
502         }
503
504         ret = !config_write_file(&config, conffile);
505         if (ret)
506                 pr_err("Error while writing file.\n");
507
508         config_destroy(&config);
509
510         return ret;
511 }