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