root/src/noit_conf.c

Revision 5f388ee20a06c319202cb070628c7bc827ffbb0a, 15.3 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 6 years ago)

split out the noit(check) specific conf stuff into its own file

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2007, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  */
5
6 #include "noit_defines.h"
7
8 #include <stdio.h>
9 #include <unistd.h>
10 #include <fcntl.h>
11 #include <errno.h>
12 #include <assert.h>
13 #include <libxml/parser.h>
14 #include <libxml/tree.h>
15 #include <libxml/xpath.h>
16
17 #include "noit_conf.h"
18 #include "noit_check.h"
19 #include "noit_console.h"
20 #include "utils/noit_hash.h"
21 #include "utils/noit_log.h"
22
23 /* tmp hash impl, replace this with something nice */
24 static noit_hash_table _tmp_config = NOIT_HASH_EMPTY;
25 static xmlDocPtr master_config = NULL;
26 static char master_config_file[PATH_MAX] = "";
27 static xmlXPathContextPtr xpath_ctxt = NULL;
28
29 static noit_hash_table _compiled_fallback = NOIT_HASH_EMPTY;
30 static struct {
31   const char *key;
32   const char *val;
33 } config_info[] = {
34   /*
35    * These are compile-time fallbacks to be used in the event
36    * that the current running config does not have values for
37    * these config paths.
38    *
39    * PLEASE: keep them alphabetically sorted.
40    */
41   { "/%s/modules/@directory", MODULES_DIR },
42
43   { NULL, NULL }
44 };
45
46 void noit_conf_init(const char *toplevel) {
47   int i;
48   char keystr[256];
49   for(i = 0; config_info[i].key != NULL; i++) {
50     snprintf(keystr, sizeof(keystr), config_info[i].key, toplevel);
51     noit_hash_store(&_compiled_fallback,
52                     strdup(keystr), strlen(keystr),
53                     (void *)strdup(config_info[i].val));
54   }
55   xmlInitParser();
56   xmlXPathInit();
57 }
58
59 int noit_conf_load(const char *path) {
60   xmlDocPtr new_config;
61   new_config = xmlParseFile(path);
62   if(new_config) {
63     if(master_config) xmlFreeDoc(master_config);
64     if(xpath_ctxt) xmlXPathFreeContext(xpath_ctxt);
65
66     master_config = new_config;
67     xpath_ctxt = xmlXPathNewContext(master_config);
68     if(path != master_config_file) realpath(path, master_config_file);
69     return 0;
70   }
71   return -1;
72 }
73 int noit_conf_xml_xpath(xmlDocPtr *mc, xmlXPathContextPtr *xp) {
74   if(mc) *mc = master_config;
75   if(xp) *xp = xpath_ctxt;
76   return 0;
77 }
78 int noit_conf_save(const char *path) {
79   return -1;
80 }
81
82 void noit_conf_get_elements_into_hash(noit_conf_section_t section,
83                                       const char *path,
84                                       noit_hash_table *table) {
85   int i, cnt;
86   xmlXPathObjectPtr pobj = NULL;
87   xmlXPathContextPtr current_ctxt;
88   xmlNodePtr current_node = (xmlNodePtr)section;
89   xmlNodePtr node;
90
91   current_ctxt = xpath_ctxt;
92   if(current_node) {
93     current_ctxt = xmlXPathNewContext(master_config);
94     current_ctxt->node = current_node;
95   }
96   pobj = xmlXPathEval((xmlChar *)path, current_ctxt);
97   if(!pobj) goto out;
98   if(pobj->type != XPATH_NODESET) goto out;
99   if(xmlXPathNodeSetIsEmpty(pobj->nodesetval)) goto out;
100   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
101   for(i=0; i<cnt; i++) {
102     char *value;
103     node = xmlXPathNodeSetItem(pobj->nodesetval, i);
104     value = (char *)xmlXPathCastNodeToString(node);
105     noit_hash_replace(table,
106                       strdup((char *)node->name), strlen((char *)node->name),
107                       strdup(value), free, free);
108   }
109  out:
110   if(pobj) xmlXPathFreeObject(pobj);
111   if(current_ctxt && current_ctxt != xpath_ctxt)
112     xmlXPathFreeContext(current_ctxt);
113 }
114 void noit_conf_get_into_hash(noit_conf_section_t section,
115                              const char *path,
116                              noit_hash_table *table) {
117   int cnt;
118   xmlXPathObjectPtr pobj = NULL;
119   xmlXPathContextPtr current_ctxt;
120   xmlNodePtr current_node = (xmlNodePtr)section;
121   xmlNodePtr node, parent_node;
122   char xpath_expr[1024];
123   char *inheritid;
124
125   current_ctxt = xpath_ctxt;
126   if(current_node) {
127     current_ctxt = xmlXPathNewContext(master_config);
128     current_ctxt->node = current_node;
129   }
130   if(path[0] == '/')
131     strlcpy(xpath_expr, path, sizeof(xpath_expr));
132   else
133     snprintf(xpath_expr, sizeof(xpath_expr),
134              "ancestor-or-self::node()/%s", path);
135   pobj = xmlXPathEval((xmlChar *)xpath_expr, current_ctxt);
136   if(!pobj) goto out;
137   if(pobj->type != XPATH_NODESET) goto out;
138   if(xmlXPathNodeSetIsEmpty(pobj->nodesetval)) goto out;
139   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
140   /* These are in the order of root to leaf
141    * We want to recurse... apply:
142    *   1. our parent's config
143    *   2. our "inherit" config if it exists.
144    *   3. our config.
145    */
146   node = xmlXPathNodeSetItem(pobj->nodesetval, cnt-1);
147   /* 1. */
148   if(cnt > 1) {
149     parent_node = xmlXPathNodeSetItem(pobj->nodesetval, cnt-2);
150     noit_conf_get_into_hash(parent_node, (const char *)node->name, table);
151   }
152   /* 2. */
153   inheritid = (char *)xmlGetProp(node, (xmlChar *)"inherit");
154   if(inheritid) {
155     snprintf(xpath_expr, sizeof(xpath_expr), "//*[@id=\"%s\"]", inheritid);
156     noit_conf_get_into_hash(NULL, xpath_expr, table);
157   }
158   /* 3. */
159   noit_conf_get_elements_into_hash(node, "*", table);
160
161  out:
162   if(pobj) xmlXPathFreeObject(pobj);
163   if(current_ctxt && current_ctxt != xpath_ctxt)
164     xmlXPathFreeContext(current_ctxt);
165 }
166 noit_hash_table *noit_conf_get_hash(noit_conf_section_t section,
167                                     const char *path) {
168   noit_hash_table *table = NULL;
169
170   table = calloc(1, sizeof(*table));
171   noit_conf_get_into_hash(section, path, table);
172   return table;
173 }
174 noit_conf_section_t noit_conf_get_section(noit_conf_section_t section,
175                                           const char *path) {
176   noit_conf_section_t subsection = NULL;
177   xmlXPathObjectPtr pobj = NULL;
178   xmlXPathContextPtr current_ctxt;
179   xmlNodePtr current_node = (xmlNodePtr)section;
180
181   current_ctxt = xpath_ctxt;
182   if(current_node) {
183     current_ctxt = xmlXPathNewContext(master_config);
184     current_ctxt->node = current_node;
185   }
186   pobj = xmlXPathEval((xmlChar *)path, current_ctxt);
187   if(!pobj) goto out;
188   if(pobj->type != XPATH_NODESET) goto out;
189   if(xmlXPathNodeSetIsEmpty(pobj->nodesetval)) goto out;
190   subsection = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0);
191  out:
192   if(pobj) xmlXPathFreeObject(pobj);
193   if(current_ctxt && current_ctxt != xpath_ctxt)
194     xmlXPathFreeContext(current_ctxt);
195   return subsection;
196 }
197 noit_conf_section_t *noit_conf_get_sections(noit_conf_section_t section,
198                                             const char *path,
199                                             int *cnt) {
200   int i;
201   noit_conf_section_t *sections = NULL;
202   xmlXPathObjectPtr pobj = NULL;
203   xmlXPathContextPtr current_ctxt;
204   xmlNodePtr current_node = (xmlNodePtr)section;
205
206   *cnt = 0;
207   current_ctxt = xpath_ctxt;
208   if(current_node) {
209     current_ctxt = xmlXPathNewContext(master_config);
210     current_ctxt->node = current_node;
211   }
212   pobj = xmlXPathEval((xmlChar *)path, current_ctxt);
213   if(!pobj) goto out;
214   if(pobj->type != XPATH_NODESET) goto out;
215   if(xmlXPathNodeSetIsEmpty(pobj->nodesetval)) goto out;
216   *cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
217   sections = calloc(*cnt, sizeof(*sections));
218   for(i=0; i<*cnt; i++)
219     sections[i] = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i);
220  out:
221   if(pobj) xmlXPathFreeObject(pobj);
222   if(current_ctxt && current_ctxt != xpath_ctxt)
223     xmlXPathFreeContext(current_ctxt);
224   return sections;
225 }
226 int _noit_conf_get_string(noit_conf_section_t section, xmlNodePtr *vnode,
227                           const char *path, char **value) {
228   char *str;
229   int i;
230   xmlXPathObjectPtr pobj;
231   xmlXPathContextPtr current_ctxt;
232   xmlNodePtr current_node = (xmlNodePtr)section;
233
234   current_ctxt = xpath_ctxt;
235   if(current_node) {
236     current_ctxt = xmlXPathNewContext(master_config);
237     current_ctxt->node = current_node;
238   }
239   pobj = xmlXPathEval((xmlChar *)path, current_ctxt);
240   if(pobj) {
241     xmlNodePtr node;
242     switch(pobj->type) {
243       case XPATH_NODESET:
244         if(xmlXPathNodeSetIsEmpty(pobj->nodesetval)) return 0;
245         i = xmlXPathNodeSetGetLength(pobj->nodesetval);
246         node = xmlXPathNodeSetItem(pobj->nodesetval, i-1);
247         if(vnode) *vnode = node;
248         *value = (char *)xmlXPathCastNodeToString(node);
249         break;
250       default:
251         *value = (char *)xmlXPathCastToString(pobj);
252     }
253     goto found;
254   }
255   if(noit_hash_retrieve(&_compiled_fallback,
256                         path, strlen(path), (void **)&str)) {
257     *value = str;
258     goto found;
259   }
260   return 0;
261  found:
262   if(current_ctxt && current_ctxt != xpath_ctxt)
263     xmlXPathFreeContext(current_ctxt);
264   return 1;
265 }
266 int noit_conf_get_uuid(noit_conf_section_t section,
267                        const char *path, uuid_t out) {
268   char *str;
269   if(_noit_conf_get_string(section,NULL,path,&str)) {
270     if(uuid_parse(str, out) == 0) return 1;
271     return 0;
272   }
273   return 0;
274 }
275 int noit_conf_get_string(noit_conf_section_t section,
276                          const char *path, char **value) {
277   char *str;
278   if(_noit_conf_get_string(section,NULL,path,&str)) {
279     *value = strdup(str);
280     return 1;
281   }
282   return 0;
283 }
284 int noit_conf_get_stringbuf(noit_conf_section_t section,
285                             const char *path, char *buf, int len) {
286   char *str;
287   if(_noit_conf_get_string(section,NULL,path,&str)) {
288     strlcpy(buf, str, len);
289     return 1;
290   }
291   return 0;
292 }
293 int noit_conf_set_string(noit_conf_section_t section,
294                          const char *path, const char *value) {
295   noit_hash_replace(&_tmp_config,
296                     strdup(path), strlen(path), (void *)strdup(value),
297                     free, free);
298   return 1;
299 }
300 int noit_conf_get_int(noit_conf_section_t section,
301                       const char *path, int *value) {
302   char *str;
303   long longval;
304   if(_noit_conf_get_string(section,NULL,path,&str)) {
305     int base = 10;
306     if(str[0] == '0') {
307       if(str[1] == 'x') base = 16;
308       else base = 8;
309     }
310     longval = strtol(str, NULL, base);
311     *value = (int)longval;
312     return 1;
313   }
314   return 0;
315 }
316 int noit_conf_set_int(noit_conf_section_t section,
317                       const char *path, int value) {
318   char buffer[32];
319   snprintf(buffer, 32, "%d", value);
320   return noit_conf_set_string(section,path,buffer);
321 }
322 int noit_conf_get_float(noit_conf_section_t section,
323                         const char *path, float *value) {
324   char *str;
325   if(_noit_conf_get_string(section,NULL,path,&str)) {
326     *value = atof(str);
327     return 1;
328   }
329   return 0;
330 }
331 int noit_conf_set_float(noit_conf_section_t section,
332                         const char *path, float value) {
333   char buffer[32];
334   snprintf(buffer, 32, "%f", value);
335   return noit_conf_set_string(section,path,buffer);
336 }
337 int noit_conf_get_boolean(noit_conf_section_t section,
338                           const char *path, noit_conf_boolean *value) {
339   char *str;
340   if(_noit_conf_get_string(section,NULL,path,&str)) {
341     if(!strcasecmp(str, "true")) *value = noit_true;
342     else *value = noit_false;
343     return 1;
344   }
345   return 0;
346 }
347 int noit_conf_set_boolean(noit_conf_section_t section,
348                           const char *path, noit_conf_boolean value) {
349   if(value == noit_true)
350     return noit_conf_set_string(section,path,"true");
351   return noit_conf_set_string(section,path,"false");
352 }
353
354 static int
355 noit_console_write_xml(void *vncct, const char *buffer, int len) {
356   noit_console_closure_t ncct = vncct;
357   return nc_write(ncct, buffer, len);
358 }
359 static int
360 noit_console_close_xml(void *vncct) {
361   return 0;
362 }
363
364 int
365 noit_conf_reload(noit_console_closure_t ncct,
366                  int argc, char **argv,
367                  noit_console_state_t *state, void *closure) {
368   if(noit_conf_load(master_config_file)) {
369     nc_printf(ncct, "error loading config\n");
370     return -1;
371   }
372   return 0;
373 }
374 int
375 noit_conf_write_terminal(noit_console_closure_t ncct,
376                          int argc, char **argv,
377                          noit_console_state_t *state, void *closure) {
378   xmlOutputBufferPtr out;
379   xmlCharEncodingHandlerPtr enc;
380   enc = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_UTF8);
381   out = xmlOutputBufferCreateIO(noit_console_write_xml,
382                                 noit_console_close_xml,
383                                 ncct, enc);
384   xmlSaveFileTo(out, master_config, "utf8");
385   return 0;
386 }
387 int
388 noit_conf_write_file(noit_console_closure_t ncct,
389                      int argc, char **argv,
390                      noit_console_state_t *state, void *closure) {
391   int fd, len;
392   char master_file_tmp[PATH_MAX];
393   xmlOutputBufferPtr out;
394   xmlCharEncodingHandlerPtr enc;
395
396   snprintf(master_file_tmp, sizeof(master_file_tmp),
397            "%s.tmp", master_config_file);
398   unlink(master_file_tmp);
399   fd = open(master_file_tmp, O_CREAT|O_EXCL|O_WRONLY, 0640);
400   if(fd < 0) {
401     nc_printf(ncct, "Failed to open tmp file: %s\n", strerror(errno));
402     return -1;
403   }
404   enc = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_UTF8);
405   out = xmlOutputBufferCreateFd(fd, enc);
406   if(!out) {
407     close(fd);
408     unlink(master_file_tmp);
409     nc_printf(ncct, "internal error: OutputBufferCreate failed\n");
410     return -1;
411   }
412   len = xmlSaveFileTo(out, master_config, "utf8");
413   close(fd);
414   if(len <= 0) {
415     nc_printf(ncct, "internal error: writing to tmp file failed.\n");
416     return -1;
417   }
418   if(rename(master_file_tmp, master_config_file) != 0) {
419     nc_printf(ncct, "Failed to replace file: %s\n", strerror(errno));
420     return -1;
421   }
422   nc_printf(ncct, "%d bytes written.\n", len);
423   return 0;
424 }
425
426 void
427 noit_conf_log_init(const char *toplevel) {
428   int i, cnt = 0, o, ocnt = 0;
429   noit_conf_section_t *log_configs, *outlets;
430   char path[256];
431
432   snprintf(path, sizeof(path), "/%s/logs//log", toplevel);
433   log_configs = noit_conf_get_sections(NULL, path, &cnt);
434   noitL(noit_stderr, "Found %d %s stanzas\n", cnt, path);
435   for(i=0; i<cnt; i++) {
436     noit_log_stream_t ls;
437     char name[256], type[256], path[256];
438     noit_hash_table *config;
439     noit_conf_boolean disabled;
440
441     if(!noit_conf_get_stringbuf(log_configs[i],
442                                 "ancestor-or-self::node()/@name",
443                                 name, sizeof(name))) {
444       noitL(noit_error, "log section %d does not have a name attribute\n", i+1);
445       exit(-1);
446     }
447     if(!noit_conf_get_stringbuf(log_configs[i],
448                                 "ancestor-or-self::node()/@type",
449                                 type, sizeof(type))) {
450       type[0] = '\0';
451     }
452     if(!noit_conf_get_stringbuf(log_configs[i],
453                                 "ancestor-or-self::node()/@path",
454                                 path, sizeof(path))) {
455       path[0] = '\0';
456     }
457     config = noit_conf_get_hash(log_configs[i],
458                                 "ancestor-or-self::node()/config/*");
459     ls = noit_log_stream_new(name, type[0] ? type : NULL,
460                              path[0] ? path : NULL, config);
461     if(!ls) {
462       fprintf(stderr, "Error configuring log: %s[%s:%s]\n", name, type, path);
463       exit(-1);
464     }
465
466     if(noit_conf_get_boolean(log_configs[i],
467                              "ancestor-or-self::node()/@disabled",
468                              &disabled) && disabled)
469       ls->enabled = 0;
470      
471     outlets = noit_conf_get_sections(log_configs[i],
472                                      "ancestor-or-self::node()/outlet", &ocnt);
473     noitL(noit_debug, "found %d outlets for log '%s'\n", ocnt, name);
474
475     for(o=0; o<ocnt; o++) {
476       noit_log_stream_t outlet;
477       char oname[256];
478       noit_conf_get_stringbuf(outlets[o], "@name",
479                               oname, sizeof(oname));
480       outlet = noit_log_stream_find(oname);
481       noitL(noit_debug, "log(%s) => log(%s)\n", name, oname);
482       if(!outlet) {
483         fprintf(stderr, "Cannot find outlet '%s' for %s[%s:%s]\n", oname,
484               name, type, path);
485         exit(-1);
486       }
487       else
488         noit_log_stream_add_stream(ls, outlet);
489     }
490     if(outlets) free(outlets);
491   }
492   if(log_configs) free(log_configs);
493 }
Note: See TracBrowser for help on using the browser.