root/src/noit_conf.c

Revision 9613f81962bb60dc317bf9765468f2c96d7e7c9a, 16.1 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 6 years ago)

This is annoying... remove

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