root/src/noit_conf.c

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

epoll eventer implementation

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