Changed error messages for calls to `mkdir': Report creation of which directory failed
[collectd.git] / src / configfile.c
1 /**
2  * collectd - src/configfile.c
3  * Copyright (C) 2005  Florian octo Forster
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; either version 2 of the License, or (at your
8  * option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
18  *
19  * Authors:
20  *   Florian octo Forster <octo at verplant.org>
21  **/
22
23 /*
24  * FIXME:
25  * - remove all (I mean *ALL*) calls to `fprintf': `stderr' will have been
26  *   closed.
27  */
28
29 #include "collectd.h"
30
31 #include "libconfig/libconfig.h"
32
33 #include "plugin.h"
34 #include "configfile.h"
35 #include "utils_debug.h"
36
37 #define SHORTOPT_NONE 0
38
39 #define ERR_NOT_NESTED "Sections cannot be nested.\n"
40 #define ERR_SECTION_ONLY "`%s' can only be used as section.\n"
41 #define ERR_NEEDS_ARG "Section `%s' needs an argument.\n"
42 #define ERR_NEEDS_SECTION "`%s' can only be used within a section.\n"
43
44 #ifdef HAVE_LIBRRD
45 extern int operating_mode;
46 #else
47 static int operating_mode = MODE_LOCAL;
48 #endif
49
50 typedef struct cf_callback
51 {
52         char  *type;
53         int  (*callback) (char *, char *);
54         char **keys;
55         int    keys_num;
56         struct cf_callback *next;
57 } cf_callback_t;
58
59 static cf_callback_t *first_callback = NULL;
60
61 static int nesting_depth = 0;
62 static char *current_module = NULL;
63
64 /* cf_register needs this prototype */
65 int cf_callback_general (const char *, const char *, const char *,
66                 const char *, lc_flags_t, void *);
67
68 /*
69  * Functions to handle register/unregister, search, ...
70  */
71 cf_callback_t *cf_search (char *type)
72 {
73         cf_callback_t *cf_cb;
74
75         if (type == NULL)
76                 return (NULL);
77
78         for (cf_cb = first_callback; cf_cb != NULL; cf_cb = cf_cb->next)
79                 if (strcasecmp (cf_cb->type, type) == 0)
80                         break;
81
82         return (cf_cb);
83 }
84
85 int cf_dispatch (char *type, const char *orig_key, const char *orig_value)
86 {
87         cf_callback_t *cf_cb;
88         char *key;
89         char *value;
90         int ret;
91         int i;
92
93         if ((cf_cb = cf_search (type)) == NULL)
94         {
95                 fprintf (stderr, "Plugin `%s' did not register a callback.\n", type);
96                 return (-1);
97         }
98
99         if ((key = strdup (orig_key)) == NULL)
100                 return (1);
101         if ((value = strdup (orig_value)) == NULL)
102         {
103                 free (key);
104                 return (2);
105         }
106
107         ret = -1;
108
109         for (i = 0; i < cf_cb->keys_num; i++)
110         {
111                 if (strcasecmp (cf_cb->keys[i], key) == 0)
112                         ret = (*cf_cb->callback) (key, value);
113         }
114
115         if (i >= cf_cb->keys_num)
116                 fprintf (stderr, "Plugin `%s' did not register for value `%s'.\n", type, key);
117
118         free (key);
119         free (value);
120
121         return (ret);
122 }
123
124 void cf_unregister (char *type)
125 {
126         cf_callback_t *this, *prev;
127
128         for (prev = NULL, this = first_callback;
129                         this != NULL;
130                         prev = this, this = this->next)
131                 if (strcasecmp (this->type, type) == 0)
132                 {
133                         if (prev == NULL)
134                                 first_callback = this->next;
135                         else
136                                 prev->next = this->next;
137
138                         free (this);
139                         break;
140                 }
141 }
142
143 void cf_register (char *type,
144                 int (*callback) (char *, char *),
145                 char **keys, int keys_num)
146 {
147         cf_callback_t *cf_cb;
148         char buf[64];
149         int i;
150
151         /* Remove this module from the list, if it already exists */
152         cf_unregister (type);
153
154         /* This pointer will be free'd in `cf_unregister' */
155         if ((cf_cb = (cf_callback_t *) malloc (sizeof (cf_callback_t))) == NULL)
156                 return;
157
158         cf_cb->type     = type;
159         cf_cb->callback = callback;
160         cf_cb->keys     = keys;
161         cf_cb->keys_num = keys_num;
162
163         cf_cb->next = first_callback;
164         first_callback = cf_cb;
165
166         for (i = 0; i < keys_num; i++)
167         {
168                 if (snprintf (buf, 64, "Module.%s", keys[i]) < 64)
169                 {
170                         /* This may be called multiple times for the same
171                          * `key', but apparently `lc_register_*' can handle
172                          * it.. */
173                         lc_register_callback (buf, SHORTOPT_NONE,
174                                         LC_VAR_STRING, cf_callback_general,
175                                         NULL);
176                 }
177                 else
178                 {
179                         DBG ("Key was truncated: `%s'", keys[i]);
180                 }
181         }
182 }
183
184 /* 
185  * Functions for the actual parsing
186  */
187 int cf_callback_general (const char *shortvar, const char *var,
188                 const char *arguments, const char *value, lc_flags_t flags,
189                 void *extra)
190 {
191         DBG ("shortvar = %s, var = %s, arguments = %s, value = %s, ...",
192                         shortvar, var, arguments, value);
193
194         if ((nesting_depth == 0) || (current_module == NULL))
195         {
196                 fprintf (stderr, ERR_NEEDS_SECTION, shortvar);
197                 return (LC_CBRET_ERROR);
198         }
199
200         /* Send the data to the plugin */
201         if (cf_dispatch (current_module, shortvar, value) < 0)
202                 return (LC_CBRET_ERROR);
203
204         return (LC_CBRET_OKAY);
205 }
206
207 int cf_callback_section_mode (const char *shortvar, const char *var,
208                 const char *arguments, const char *value, lc_flags_t flags,
209                 void *extra)
210 {
211         DBG ("shortvar = %s, var = %s, arguments = %s, value = %s, ...",
212                         shortvar, var, arguments, value);
213
214         if (flags == LC_FLAGS_SECTIONSTART)
215         {
216                 if (nesting_depth != 0)
217                 {
218                         fprintf (stderr, ERR_NOT_NESTED);
219                         return (LC_CBRET_ERROR);
220                 }
221
222                 if (arguments == NULL)
223                 {
224                         fprintf (stderr, ERR_NEEDS_ARG, shortvar);
225                         return (LC_CBRET_ERROR);
226                 }
227
228                 nesting_depth++;
229
230                 if (((operating_mode == MODE_CLIENT)
231                                         && (strcasecmp (arguments, "Client") == 0))
232                                 || ((operating_mode == MODE_SERVER)
233                                         && (strcasecmp (arguments, "Server") == 0))
234                                 || ((operating_mode == MODE_LOCAL)
235                                         && (strcasecmp (arguments, "Local") == 0)))
236                 {
237                         return (LC_CBRET_OKAY);
238                 }
239                 else
240                 {
241                         return (LC_CBRET_IGNORESECTION);
242                 }
243         }
244         else if (flags == LC_FLAGS_SECTIONEND)
245         {
246                 nesting_depth--;
247
248                 return (LC_CBRET_OKAY);
249         }
250         else
251         {
252                 fprintf (stderr, ERR_SECTION_ONLY, shortvar);
253                 return (LC_CBRET_ERROR);
254         }
255
256 }
257
258 int cf_callback_section_module (const char *shortvar, const char *var,
259                 const char *arguments, const char *value, lc_flags_t flags,
260                 void *extra)
261 {
262         DBG ("shortvar = %s, var = %s, arguments = %s, value = %s, ...",
263                         shortvar, var, arguments, value);
264
265         if (flags == LC_FLAGS_SECTIONSTART)
266         {
267                 if (nesting_depth != 0)
268                 {
269                         fprintf (stderr, ERR_NOT_NESTED);
270                         return (LC_CBRET_ERROR);
271                 }
272
273                 if (arguments == NULL)
274                 {
275                         fprintf (stderr, ERR_NEEDS_ARG, shortvar);
276                         return (LC_CBRET_ERROR);
277                 }
278
279                 if ((current_module = strdup (arguments)) == NULL)
280                 {
281                         perror ("strdup");
282                         return (LC_CBRET_ERROR);
283                 }
284
285                 nesting_depth++;
286
287                 if (cf_search (current_module) != NULL)
288                         return (LC_CBRET_OKAY);
289                 else
290                         return (LC_CBRET_IGNORESECTION);
291         }
292         else if (flags == LC_FLAGS_SECTIONEND)
293         {
294                 if (current_module != NULL)
295                 {
296                         free (current_module);
297                         current_module == NULL;
298                 }
299
300                 nesting_depth--;
301
302                 return (LC_CBRET_OKAY);
303         }
304         else
305         {
306                 fprintf (stderr, ERR_SECTION_ONLY, shortvar);
307                 return (LC_CBRET_ERROR);
308         }
309 }
310
311 int cf_callback_loadmodule (const char *shortvar, const char *var,
312                 const char *arguments, const char *value, lc_flags_t flags,
313                 void *extra)
314 {
315         DBG ("shortvar = %s, var = %s, arguments = %s, value = %s, ...",
316                         shortvar, var, arguments, value);
317
318         if (nesting_depth == 0)
319         {
320                 fprintf (stderr, ERR_NEEDS_SECTION, shortvar);
321                 return (LC_CBRET_ERROR);
322         }
323
324         if (plugin_load (value))
325                 syslog (LOG_ERR, "plugin_load (%s): failed to load plugin", shortvar);
326
327         /* Return `okay' even if there was an error, because it's not a syntax
328          * problem.. */
329         return (LC_CBRET_OKAY);
330 }
331
332 int cf_read (char *filename)
333 {
334         if (filename == NULL)
335                 filename = CONFIGFILE;
336
337         lc_register_callback ("Mode", SHORTOPT_NONE, LC_VAR_SECTION,
338                         cf_callback_section_mode, NULL);
339         lc_register_callback ("Module", SHORTOPT_NONE, LC_VAR_SECTION,
340                         cf_callback_section_module, NULL);
341
342         /*
343          * TODO:
344          * - Add more directives, such as `DefaultMode', `DataDir', `PIDFile', ...
345          */
346
347         lc_register_callback ("Mode.LoadModule", SHORTOPT_NONE,
348                         LC_VAR_STRING, cf_callback_loadmodule,
349                         NULL);
350
351         if (lc_process_file ("collectd", filename, LC_CONF_APACHE))
352         {
353                 syslog (LOG_ERR, "lc_process_file (%s): %s", filename, lc_geterrstr ());
354                 return (-1);
355         }
356
357         /* free memory and stuff */
358         lc_cleanup ();
359
360         return (0);
361 }