Code

store_test: Fixed golden data for tojson() test.
[sysdb.git] / src / daemon / config.c
1 /*
2  * SysDB - src/daemon/config.c
3  * Copyright (C) 2012 Sebastian 'tokkee' Harl <sh@tokkee.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
17  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
28 #include "sysdb.h"
29 #include "core/plugin.h"
30 #include "core/error.h"
31 #include "core/time.h"
33 #include "daemon/config.h"
35 #include "liboconfig/oconfig.h"
36 #include "liboconfig/utils.h"
38 #include <assert.h>
39 #include <errno.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <strings.h>
45 /*
46  * Parser error values:
47  *  - Values less than zero indicate an error in the daemon or libsysdb.
48  *  - Zero indicates success.
49  *  - Any other values indicate parsing errors.
50  */
52 enum {
53         ERR_UNKNOWN_OPTION = 1,
54         ERR_UNKNOWN_ARG    = 2,
55         ERR_INVALID_ARG    = 3,
56         ERR_PARSE_FAILED   = 4,
57 };
59 /*
60  * private variables
61  */
63 static sdb_time_t default_interval = 0;
65 /*
66  * private helper functions
67  */
69 static int
70 config_get_interval(oconfig_item_t *ci, sdb_time_t *interval)
71 {
72         double interval_dbl = 0.0;
74         assert(ci && interval);
76         if (oconfig_get_number(ci, &interval_dbl)) {
77                 sdb_log(SDB_LOG_ERR, "config: Interval requires "
78                                 "a single numeric argument\n"
79                                 "\tUsage: Interval SECONDS");
80                 return ERR_INVALID_ARG;
81         }
83         if (interval_dbl <= 0.0) {
84                 sdb_log(SDB_LOG_ERR, "config: Invalid interval: %f\n"
85                                 "\tInterval may not be less than or equal to zero.",
86                                 interval_dbl);
87                 return ERR_INVALID_ARG;
88         }
90         *interval = DOUBLE_TO_SDB_TIME(interval_dbl);
91         return 0;
92 } /* config_get_interval */
94 /*
95  * public parse results
96  */
98 char **listen_addresses = NULL;
99 size_t listen_addresses_num = 0;
101 /*
102  * token parser
103  */
105 typedef struct {
106         char *name;
107         int (*dispatcher)(oconfig_item_t *);
108 } token_parser_t;
110 static int
111 daemon_add_listener(oconfig_item_t *ci)
113         char **tmp;
114         char *address;
116         if (oconfig_get_string(ci, &address)) {
117                 sdb_log(SDB_LOG_ERR, "config: Listen requires a single "
118                                 "string argument\n"
119                                 "\tUsage: Listen ADDRESS");
120                 return ERR_INVALID_ARG;
121         }
123         tmp = realloc(listen_addresses,
124                         (listen_addresses_num + 1) * sizeof(*listen_addresses));
125         if (! tmp) {
126                 char buf[1024];
127                 sdb_log(SDB_LOG_ERR, "config: Failed to allocate memory: %s",
128                                 sdb_strerror(errno, buf, sizeof(buf)));
129                 return -1;
130         }
132         tmp[listen_addresses_num] = strdup(address);
133         if (! tmp[listen_addresses_num]) {
134                 char buf[1024];
135                 sdb_log(SDB_LOG_ERR, "config: Failed to allocate memory: %s",
136                                 sdb_strerror(errno, buf, sizeof(buf)));
137                 return -1;
138         }
140         listen_addresses = tmp;
141         ++listen_addresses_num;
142         return 0;
143 } /* daemon_add_listener */
145 static int
146 daemon_set_interval(oconfig_item_t *ci)
148         return config_get_interval(ci, &default_interval);
149 } /* daemon_set_interval */
151 static int
152 daemon_load_plugin(oconfig_item_t *ci)
154         char *name;
155         int i;
157         if (oconfig_get_string(ci, &name)) {
158                 sdb_log(SDB_LOG_ERR, "config: LoadPlugin requires a single "
159                                 "string argument\n"
160                                 "\tUsage: LoadPlugin PLUGIN");
161                 return ERR_INVALID_ARG;
162         }
164         for (i = 0; i < ci->children_num; ++i) {
165                 oconfig_item_t *child = ci->children + i;
167                 /* we don't currently support any options */
168                 sdb_log(SDB_LOG_WARNING, "config: Unknown option '%s' "
169                                 "inside 'LoadPlugin' -- see the documentation for "
170                                 "details.", child->key);
171                 continue;
172         }
174         /* returns a negative value on error */
175         return sdb_plugin_load(name, NULL);
176 } /* daemon_load_plugin */
178 static int
179 daemon_load_backend(oconfig_item_t *ci)
181         sdb_plugin_ctx_t ctx = SDB_PLUGIN_CTX_INIT;
183         char  plugin_name[1024];
184         char *name;
186         int i;
188         ctx.interval = default_interval;
190         if (oconfig_get_string(ci, &name)) {
191                 sdb_log(SDB_LOG_ERR, "config: LoadBackend requires a single "
192                                 "string argument\n"
193                                 "\tUsage: LoadBackend BACKEND");
194                 return ERR_INVALID_ARG;
195         }
197         snprintf(plugin_name, sizeof(plugin_name), "backend::%s", name);
199         for (i = 0; i < ci->children_num; ++i) {
200                 oconfig_item_t *child = ci->children + i;
202                 if (! strcasecmp(child->key, "Interval")) {
203                         if (config_get_interval(child, &ctx.interval))
204                                 return ERR_INVALID_ARG;
205                 }
206                 else {
207                         sdb_log(SDB_LOG_WARNING, "config: Unknown option '%s' "
208                                         "inside 'LoadBackend' -- see the documentation for "
209                                         "details.", child->key);
210                         continue;
211                 }
212         }
214         return sdb_plugin_load(plugin_name, &ctx);
215 } /* daemon_load_backend */
217 static int
218 daemon_configure_plugin(oconfig_item_t *ci)
220         char *name;
222         assert(ci);
224         if (oconfig_get_string(ci, &name)) {
225                 sdb_log(SDB_LOG_ERR, "config: %s requires a single "
226                                 "string argument\n"
227                                 "\tUsage: LoadBackend BACKEND",
228                                 ci->key);
229                 return ERR_INVALID_ARG;
230         }
232         return sdb_plugin_configure(name, ci);
233 } /* daemon_configure_backend */
235 static token_parser_t token_parser_list[] = {
236         { "Listen", daemon_add_listener },
237         { "Interval", daemon_set_interval },
238         { "LoadPlugin", daemon_load_plugin },
239         { "LoadBackend", daemon_load_backend },
240         { "Backend", daemon_configure_plugin },
241         { "Plugin", daemon_configure_plugin },
242         { NULL, NULL },
243 };
245 /*
246  * public API
247  */
249 int
250 daemon_parse_config(const char *filename)
252         oconfig_item_t *ci;
253         int retval = 0, i;
255         ci = oconfig_parse_file(filename);
256         if (! ci)
257                 return ERR_PARSE_FAILED;
259         for (i = 0; i < ci->children_num; ++i) {
260                 oconfig_item_t *child = ci->children + i;
261                 int status = ERR_UNKNOWN_OPTION, j;
263                 for (j = 0; token_parser_list[j].name; ++j) {
264                         if (! strcasecmp(token_parser_list[j].name, child->key))
265                                 status = token_parser_list[j].dispatcher(child);
266                 }
268                 if (status) {
269                         sdb_error_set("config: Failed to parse option '%s'\n",
270                                         child->key);
271                         if (status == ERR_UNKNOWN_OPTION)
272                                 sdb_error_append("\tUnknown option '%s' -- "
273                                                 "see the documentation for details\n",
274                                                 child->key);
275                         sdb_error_chomp();
276                         sdb_error_log(SDB_LOG_ERR);
277                         retval = status;
278                 }
279         }
280         return retval;
281 } /* daemon_parse_config */
283 /* vim: set tw=78 sw=4 ts=4 noexpandtab : */