root/src/noit_conf.c

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

implements stratcon configuration storage in DB, refs #27

  • 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 #include <zlib.h>
17
18 #include "noit_conf.h"
19 #include "noit_check.h"
20 #include "noit_console.h"
21 #include "utils/noit_hash.h"
22 #include "utils/noit_log.h"
23 #include "utils/noit_b64.h"
24
25 /* tmp hash impl, replace this with something nice */
26 static noit_hash_table _tmp_config = NOIT_HASH_EMPTY;
27 static xmlDocPtr master_config = NULL;
28 static char master_config_file[PATH_MAX] = "";
29 static xmlXPathContextPtr xpath_ctxt = NULL;
30
31 /* This is used to notice config changes and journal the config out
32  * using a user-specified function.  It supports allowing multiple config
33  * changed to coalesce so you don't write out 1000 changes in a few seconds.
34  */
35 static u_int32_t __config_gen = 0;
36 static u_int32_t __config_coalesce = 0;
37 static u_int32_t __config_coalesce_time = 0;
38 void noit_conf_coalesce_changes(u_int32_t seconds) {
39   __config_coalesce_time = seconds;
40 }
41 void noit_conf_mark_changed() {
42   /* increment the change counter -- in case anyone cares */
43   __config_gen++;
44   /* reset the coalesce counter.  It is decremented each second and
45    * the journal function fires on a transition from 1 => 0
46    */
47   __config_coalesce = __config_coalesce_time;
48 }
49 struct recurrent_journaler {
50   int (*journal_config)(void *);
51   void *jc_closure;
52 };
53 static int
54 noit_conf_watch_config_and_journal(eventer_t e, int mask, void *closure,
55                                    struct timeval *now) {
56   struct recurrent_journaler *rj = closure;
57   eventer_t newe;
58
59   if(__config_coalesce == 1)
60     rj->journal_config(rj->jc_closure);
61   if(__config_coalesce > 0)
62     __config_coalesce--;
63
64   /* Schedule the same event to fire a second form now */
65   newe = eventer_alloc();
66   gettimeofday(&newe->whence, NULL);
67   newe->whence.tv_sec += 1;
68   newe->mask = EVENTER_TIMER;
69   newe->callback = noit_conf_watch_config_and_journal;
70   newe->closure = closure;
71   eventer_add(newe);
72   return 0;
73 }
74 void
75 noit_conf_watch_and_journal_watchdog(int (*f)(void *), void *c) {
76   struct recurrent_journaler *rj;
77   struct timeval __now;
78   rj = calloc(1, sizeof(*rj));
79   rj->journal_config = f;
80   rj->jc_closure = c;
81   gettimeofday(&__now, NULL);
82   noit_conf_watch_config_and_journal(NULL, EVENTER_TIMER, rj, &__now);
83 }
84
85 static noit_hash_table _compiled_fallback = NOIT_HASH_EMPTY;
86 static struct {
87   const char *key;
88   const char *val;
89 } config_info[] = {
90   /*
91    * These are compile-time fallbacks to be used in the event
92    * that the current running config does not have values for
93    * these config paths.
94    *
95    * PLEASE: keep them alphabetically sorted.
96    */
97   { "/%s/eventer/@implementation", DEFAULT_EVENTER },
98   { "/%s/modules/@directory", MODULES_DIR },
99
100   { NULL, NULL }
101 };
102
103 void noit_conf_xml_error_func(void *ctx, const char *format, ...) {
104   struct timeval __now;
105   noit_log_stream_t ls = ctx;
106   va_list arg;
107   if(!ls) return;
108   va_start(arg, format);
109   gettimeofday(&__now,  NULL);
110   noit_vlog(ls, &__now, __FILE__, __LINE__, format, arg);
111   va_end(arg);
112 }
113 void noit_conf_xml_error_ext_func(void *ctx, xmlErrorPtr err) {
114   struct timeval __now;
115   noit_log_stream_t ls = ctx;
116   if(!ls) return;
117   gettimeofday(&__now,  NULL);
118   if(err->file)
119     noit_log(ls, &__now, err->file, err->line,
120              "XML error [%d/%d] in %s on line %d %s\n",
121              err->domain, err->code, err->file, err->line, err->message);
122   else
123     noit_log(ls, &__now, err->file, err->line,
124              "XML error [%d/%d] %s\n",
125              err->domain, err->code, err->message);
126 }
127 void noit_conf_init(const char *toplevel) {
128   int i;
129   char keystr[256];
130   xmlSetGenericErrorFunc(noit_error, noit_conf_xml_error_func);
131   xmlSetStructuredErrorFunc(noit_error, noit_conf_xml_error_ext_func);
132   for(i = 0; config_info[i].key != NULL; i++) {
133     snprintf(keystr, sizeof(keystr), config_info[i].key, toplevel);
134     noit_hash_store(&_compiled_fallback,
135                     strdup(keystr), strlen(keystr),
136                     (void *)strdup(config_info[i].val));
137   }
138   xmlKeepBlanksDefault(0);
139   xmlInitParser();
140   xmlXPathInit();
141 }
142
143 int noit_conf_load(const char *path) {
144   xmlDocPtr new_config;
145   new_config = xmlParseFile(path);
146   if(new_config) {
147     if(master_config) xmlFreeDoc(master_config);
148     if(xpath_ctxt) xmlXPathFreeContext(xpath_ctxt);
149
150     master_config = new_config;
151     xpath_ctxt = xmlXPathNewContext(master_config);
152     if(path != master_config_file) realpath(path, master_config_file);
153     noit_conf_mark_changed();
154     return 0;
155   }
156   return -1;
157 }
158 int noit_conf_xml_xpath(xmlDocPtr *mc, xmlXPathContextPtr *xp) {
159   if(mc) *mc = master_config;
160   if(xp) *xp = xpath_ctxt;
161   return 0;
162 }
163 int noit_conf_save(const char *path) {
164   return -1;
165 }
166
167 void noit_conf_get_elements_into_hash(noit_conf_section_t section,
168                                       const char *path,
169                                       noit_hash_table *table) {
170   int i, cnt;
171   xmlXPathObjectPtr pobj = NULL;
172   xmlXPathContextPtr current_ctxt;
173   xmlNodePtr current_node = (xmlNodePtr)section;
174   xmlNodePtr node;
175
176   current_ctxt = xpath_ctxt;
177   if(current_node) {
178     current_ctxt = xmlXPathNewContext(master_config);
179     current_ctxt->node = current_node;
180   }
181   pobj = xmlXPathEval((xmlChar *)path, current_ctxt);
182   if(!pobj) goto out;
183   if(pobj->type != XPATH_NODESET) goto out;
184   if(xmlXPathNodeSetIsEmpty(pobj->nodesetval)) goto out;
185   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
186   for(i=0; i<cnt; i++) {
187     char *value;
188     node = xmlXPathNodeSetItem(pobj->nodesetval, i);
189     value = (char *)xmlXPathCastNodeToString(node);
190     noit_hash_replace(table,
191                       strdup((char *)node->name), strlen((char *)node->name),
192                       strdup(value), free, free);
193     xmlFree(value);
194   }
195  out:
196   if(pobj) xmlXPathFreeObject(pobj);
197   if(current_ctxt && current_ctxt != xpath_ctxt)
198     xmlXPathFreeContext(current_ctxt);
199 }
200 void noit_conf_get_into_hash(noit_conf_section_t section,
201                              const char *path,
202                              noit_hash_table *table) {
203   int cnt;
204   xmlXPathObjectPtr pobj = NULL;
205   xmlXPathContextPtr current_ctxt;
206   xmlNodePtr current_node = (xmlNodePtr)section;
207   xmlNodePtr node, parent_node;
208   char xpath_expr[1024];
209   char *inheritid;
210
211   current_ctxt = xpath_ctxt;
212   if(current_node) {
213     current_ctxt = xmlXPathNewContext(master_config);
214     current_ctxt->node = current_node;
215   }
216   if(path[0] == '/')
217     strlcpy(xpath_expr, path, sizeof(xpath_expr));
218   else
219     snprintf(xpath_expr, sizeof(xpath_expr),
220              "ancestor-or-self::node()/%s", path);
221   pobj = xmlXPathEval((xmlChar *)xpath_expr, current_ctxt);
222   if(!pobj) goto out;
223   if(pobj->type != XPATH_NODESET) goto out;
224   if(xmlXPathNodeSetIsEmpty(pobj->nodesetval)) goto out;
225   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
226   /* These are in the order of root to leaf
227    * We want to recurse... apply:
228    *   1. our parent's config
229    *   2. our "inherit" config if it exists.
230    *   3. our config.
231    */
232   node = xmlXPathNodeSetItem(pobj->nodesetval, cnt-1);
233   /* 1. */
234   if(cnt > 1) {
235     parent_node = xmlXPathNodeSetItem(pobj->nodesetval, cnt-2);
236     if(parent_node != current_node)
237       noit_conf_get_into_hash(parent_node, (const char *)node->name, table);
238   }
239   /* 2. */
240   inheritid = (char *)xmlGetProp(node, (xmlChar *)"inherit");
241   if(inheritid) {
242     snprintf(xpath_expr, sizeof(xpath_expr), "//*[@id=\"%s\"]", inheritid);
243     noit_conf_get_into_hash(NULL, xpath_expr, table);
244   }
245   /* 3. */
246   noit_conf_get_elements_into_hash(node, "*", table);
247
248  out:
249   if(pobj) xmlXPathFreeObject(pobj);
250   if(current_ctxt && current_ctxt != xpath_ctxt)
251     xmlXPathFreeContext(current_ctxt);
252 }
253 noit_hash_table *noit_conf_get_hash(noit_conf_section_t section,
254                                     const char *path) {
255   noit_hash_table *table = NULL;
256
257   table = calloc(1, sizeof(*table));
258   noit_conf_get_into_hash(section, path, table);
259   return table;
260 }
261 noit_conf_section_t noit_conf_get_section(noit_conf_section_t section,
262                                           const char *path) {
263   noit_conf_section_t subsection = NULL;
264   xmlXPathObjectPtr pobj = NULL;
265   xmlXPathContextPtr current_ctxt;
266   xmlNodePtr current_node = (xmlNodePtr)section;
267
268   current_ctxt = xpath_ctxt;
269   if(current_node) {
270     current_ctxt = xmlXPathNewContext(master_config);
271     current_ctxt->node = current_node;
272   }
273   pobj = xmlXPathEval((xmlChar *)path, current_ctxt);
274   if(!pobj) goto out;
275   if(pobj->type != XPATH_NODESET) goto out;
276   if(xmlXPathNodeSetIsEmpty(pobj->nodesetval)) goto out;
277   subsection = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0);
278  out:
279   if(pobj) xmlXPathFreeObject(pobj);
280   if(current_ctxt && current_ctxt != xpath_ctxt)
281     xmlXPathFreeContext(current_ctxt);
282   return subsection;
283 }
284 noit_conf_section_t *noit_conf_get_sections(noit_conf_section_t section,
285                                             const char *path,
286                                             int *cnt) {
287   int i;
288   noit_conf_section_t *sections = NULL;
289   xmlXPathObjectPtr pobj = NULL;
290   xmlXPathContextPtr current_ctxt;
291   xmlNodePtr current_node = (xmlNodePtr)section;
292
293   *cnt = 0;
294   current_ctxt = xpath_ctxt;
295   if(current_node) {
296     current_ctxt = xmlXPathNewContext(master_config);
297     current_ctxt->node = current_node;
298   }
299   pobj = xmlXPathEval((xmlChar *)path, current_ctxt);
300   if(!pobj) goto out;
301   if(pobj->type != XPATH_NODESET) goto out;
302   if(xmlXPathNodeSetIsEmpty(pobj->nodesetval)) goto out;
303   *cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
304   sections = calloc(*cnt, sizeof(*sections));
305   for(i=0; i<*cnt; i++)
306     sections[i] = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i);
307  out:
308   if(pobj) xmlXPathFreeObject(pobj);
309   if(current_ctxt && current_ctxt != xpath_ctxt)
310     xmlXPathFreeContext(current_ctxt);
311   return sections;
312 }
313 int _noit_conf_get_string(noit_conf_section_t section, xmlNodePtr *vnode,
314                           const char *path, char **value) {
315   char *str;
316   int i, rv = 1;
317   xmlXPathObjectPtr pobj = NULL;
318   xmlXPathContextPtr current_ctxt;
319   xmlNodePtr current_node = (xmlNodePtr)section;
320
321   current_ctxt = xpath_ctxt;
322   if(current_node) {
323     current_ctxt = xmlXPathNewContext(master_config);
324     current_ctxt->node = current_node;
325   }
326   pobj = xmlXPathEval((xmlChar *)path, current_ctxt);
327   if(pobj) {
328     xmlNodePtr node;
329     switch(pobj->type) {
330       case XPATH_NODESET:
331         if(xmlXPathNodeSetIsEmpty(pobj->nodesetval)) goto fallback;
332         i = xmlXPathNodeSetGetLength(pobj->nodesetval);
333         node = xmlXPathNodeSetItem(pobj->nodesetval, i-1);
334         if(vnode) *vnode = node;
335         *value = (char *)xmlXPathCastNodeToString(node);
336         break;
337       default:
338         *value = (char *)xmlXPathCastToString(pobj);
339     }
340     goto found;
341   }
342  fallback:
343   if(noit_hash_retrieve(&_compiled_fallback,
344                         path, strlen(path), (void **)&str)) {
345     *value = (char *)xmlStrdup((xmlChar *)str);
346     goto found;
347   }
348   rv = 0;
349  found:
350   if(pobj) xmlXPathFreeObject(pobj);
351   if(current_ctxt && current_ctxt != xpath_ctxt)
352     xmlXPathFreeContext(current_ctxt);
353   return rv;
354 }
355 int noit_conf_get_uuid(noit_conf_section_t section,
356                        const char *path, uuid_t out) {
357   char *str;
358   if(_noit_conf_get_string(section,NULL,path,&str)) {
359     if(uuid_parse(str, out) == 0) return 1;
360     return 0;
361   }
362   return 0;
363 }
364 int noit_conf_get_string(noit_conf_section_t section,
365                          const char *path, char **value) {
366   char *str;
367   if(_noit_conf_get_string(section,NULL,path,&str)) {
368     *value = strdup(str);
369     xmlFree(str);
370     return 1;
371   }
372   return 0;
373 }
374 int noit_conf_get_stringbuf(noit_conf_section_t section,
375                             const char *path, char *buf, int len) {
376   char *str;
377   if(_noit_conf_get_string(section,NULL,path,&str)) {
378     strlcpy(buf, str, len);
379     xmlFree(str);
380     return 1;
381   }
382   return 0;
383 }
384 int noit_conf_set_string(noit_conf_section_t section,
385                          const char *path, const char *value) {
386   noit_hash_replace(&_tmp_config,
387                     strdup(path), strlen(path), (void *)strdup(value),
388                     free, free);
389   return 1;
390 }
391 int noit_conf_get_int(noit_conf_section_t section,
392                       const char *path, int *value) {
393   char *str;
394   long longval;
395   if(_noit_conf_get_string(section,NULL,path,&str)) {
396     int base = 10;
397     if(str[0] == '0') {
398       if(str[1] == 'x') base = 16;
399       else base = 8;
400     }
401     longval = strtol(str, NULL, base);
402     xmlFree(str);
403     *value = (int)longval;
404     return 1;
405   }
406   return 0;
407 }
408 int noit_conf_set_int(noit_conf_section_t section,
409                       const char *path, int value) {
410   char buffer[32];
411   snprintf(buffer, 32, "%d", value);
412   return noit_conf_set_string(section,path,buffer);
413 }
414 int noit_conf_get_float(noit_conf_section_t section,
415                         const char *path, float *value) {
416   char *str;
417   if(_noit_conf_get_string(section,NULL,path,&str)) {
418     *value = atof(str);
419     xmlFree(str);
420     return 1;
421   }
422   return 0;
423 }
424 int noit_conf_set_float(noit_conf_section_t section,
425                         const char *path, float value) {
426   char buffer[32];
427   snprintf(buffer, 32, "%f", value);
428   return noit_conf_set_string(section,path,buffer);
429 }
430 int noit_conf_get_boolean(noit_conf_section_t section,
431                           const char *path, noit_conf_boolean *value) {
432   char *str;
433   if(_noit_conf_get_string(section,NULL,path,&str)) {
434     if(!strcasecmp(str, "true") ||
435        !strcasecmp(str, "on")) *value = noit_true;
436     else *value = noit_false;
437     xmlFree(str);
438     return 1;
439   }
440   return 0;
441 }
442 int noit_conf_set_boolean(noit_conf_section_t section,
443                           const char *path, noit_conf_boolean value) {
444   if(value == noit_true)
445     return noit_conf_set_string(section,path,"true");
446   return noit_conf_set_string(section,path,"false");
447 }
448
449 static int
450 noit_console_write_xml(void *vncct, const char *buffer, int len) {
451   noit_console_closure_t ncct = vncct;
452   return nc_write(ncct, buffer, len);
453 }
454 static int
455 noit_console_close_xml(void *vncct) {
456   return 0;
457 }
458
459 struct config_line_vstr {
460   char *buff;
461   int raw_len;
462   int len;
463   int allocd;
464   enum { CONFIG_RAW = 0, CONFIG_COMPRESSED, CONFIG_B64 } target, encoded;
465 };
466 static int
467 noit_config_log_write_xml(void *vstr, const char *buffer, int len) {
468   struct config_line_vstr *clv = vstr;
469   assert(clv->encoded == CONFIG_RAW);
470   if(!clv->buff) {
471     clv->allocd = 8192;
472     clv->buff = malloc(clv->allocd);
473   }
474   while(len + clv->len > clv->allocd) {
475     char *newbuff;
476     int newsize = clv->allocd;
477     newsize <<= 1;
478     newbuff = realloc(clv->buff, newsize);
479     if(!newbuff) {
480       return -1;
481     }
482     clv->allocd = newsize;
483     clv->buff = newbuff;
484   }
485   memcpy(clv->buff + clv->len, buffer, len);
486   clv->len += len;
487   return len;
488 }
489 static int
490 noit_config_log_close_xml(void *vstr) {
491   struct config_line_vstr *clv = vstr;
492   uLong initial_dlen, dlen;
493   char *compbuff, *b64buff;
494
495   if(clv->buff == NULL) {
496     clv->encoded = clv->target;
497     return 0;
498   }
499   clv->raw_len = clv->len;
500   assert(clv->encoded == CONFIG_RAW);
501   if(clv->encoded == clv->target) return 0;
502
503   /* Compress */
504   initial_dlen = dlen = compressBound(clv->len);
505   compbuff = malloc(initial_dlen);
506   if(!compbuff) return -1;
507   if(Z_OK != compress2((Bytef *)compbuff, &dlen,
508                        (Bytef *)clv->buff, clv->len, 9)) {
509     noitL(noit_error, "Error compressing config for transmission.\n");
510     free(compbuff);
511     return -1;
512   }
513   free(clv->buff);
514   clv->buff = compbuff;
515   clv->allocd = initial_dlen;
516   clv->len = dlen;
517   clv->encoded = CONFIG_COMPRESSED;
518   if(clv->encoded == clv->target) return 0;
519
520   /* Encode */
521   initial_dlen = ((clv->len + 2) / 3) * 4;
522   b64buff = malloc(initial_dlen);
523   dlen = noit_b64_encode((unsigned char *)clv->buff, clv->len,
524                          b64buff, initial_dlen);
525   if(dlen == 0) {
526     free(b64buff);
527     return -1;
528   }
529   free(clv->buff);
530   clv->buff = b64buff;
531   clv->allocd = initial_dlen;
532   clv->len = dlen;
533   clv->encoded = CONFIG_B64;
534   if(clv->encoded == clv->target) return 0;
535   return -1;
536 }
537
538 int
539 noit_conf_reload(noit_console_closure_t ncct,
540                  int argc, char **argv,
541                  noit_console_state_t *state, void *closure) {
542   if(noit_conf_load(master_config_file)) {
543     nc_printf(ncct, "error loading config\n");
544     return -1;
545   }
546   return 0;
547 }
548 int
549 noit_conf_write_terminal(noit_console_closure_t ncct,
550                          int argc, char **argv,
551                          noit_console_state_t *state, void *closure) {
552   xmlOutputBufferPtr out;
553   xmlCharEncodingHandlerPtr enc;
554   enc = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_UTF8);
555   out = xmlOutputBufferCreateIO(noit_console_write_xml,
556                                 noit_console_close_xml,
557                                 ncct, enc);
558   xmlSaveFormatFileTo(out, master_config, "utf8", 1);
559   return 0;
560 }
561 int
562 noit_conf_write_file(noit_console_closure_t ncct,
563                      int argc, char **argv,
564                      noit_console_state_t *state, void *closure) {
565   int fd, len;
566   char master_file_tmp[PATH_MAX];
567   xmlOutputBufferPtr out;
568   xmlCharEncodingHandlerPtr enc;
569
570   snprintf(master_file_tmp, sizeof(master_file_tmp),
571            "%s.tmp", master_config_file);
572   unlink(master_file_tmp);
573   fd = open(master_file_tmp, O_CREAT|O_EXCL|O_WRONLY, 0640);
574   if(fd < 0) {
575     nc_printf(ncct, "Failed to open tmp file: %s\n", strerror(errno));
576     return -1;
577   }
578   enc = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_UTF8);
579   out = xmlOutputBufferCreateFd(fd, enc);
580   if(!out) {
581     close(fd);
582     unlink(master_file_tmp);
583     nc_printf(ncct, "internal error: OutputBufferCreate failed\n");
584     return -1;
585   }
586   len = xmlSaveFormatFileTo(out, master_config, "utf8", 1);
587   close(fd);
588   if(len <= 0) {
589     nc_printf(ncct, "internal error: writing to tmp file failed.\n");
590     return -1;
591   }
592   if(rename(master_file_tmp, master_config_file) != 0) {
593     nc_printf(ncct, "Failed to replace file: %s\n", strerror(errno));
594     return -1;
595   }
596   nc_printf(ncct, "%d bytes written.\n", len);
597   return 0;
598 }
599 char *
600 noit_conf_xml_in_mem(size_t *len) {
601   struct config_line_vstr *clv;
602   xmlOutputBufferPtr out;
603   xmlCharEncodingHandlerPtr enc;
604   char *rv;
605
606   clv = calloc(1, sizeof(*clv));
607   clv->target = CONFIG_RAW;
608   enc = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_UTF8);
609   out = xmlOutputBufferCreateIO(noit_config_log_write_xml,
610                                 noit_config_log_close_xml,
611                                 clv, enc);
612   xmlSaveFormatFileTo(out, master_config, "utf8", 1);
613   if(clv->encoded != CONFIG_RAW) {
614     noitL(noit_error, "Error logging configuration\n");
615     if(clv->buff) free(clv->buff);
616     free(clv);
617     return NULL;
618   }
619   rv = clv->buff;
620   *len = clv->len;
621   free(clv);
622   return rv;
623 }
624
625 int
626 noit_conf_write_log() {
627   static u_int32_t last_write_gen = 0;
628   static noit_log_stream_t config_log = NULL;
629   struct timeval __now;
630   xmlOutputBufferPtr out;
631   xmlCharEncodingHandlerPtr enc;
632   struct config_line_vstr *clv;
633   SETUP_LOG(config, return -1);
634
635   /* We know we haven't changed */
636   if(last_write_gen == __config_gen) return 0;
637
638   gettimeofday(&__now, NULL);
639   clv = calloc(1, sizeof(*clv));
640   clv->target = CONFIG_B64;
641   enc = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_UTF8);
642   out = xmlOutputBufferCreateIO(noit_config_log_write_xml,
643                                 noit_config_log_close_xml,
644                                 clv, enc);
645   xmlSaveFormatFileTo(out, master_config, "utf8", 1);
646   if(clv->encoded != CONFIG_B64) {
647     noitL(noit_error, "Error logging configuration\n");
648     if(clv->buff) free(clv->buff);
649     free(clv);
650     return -1;
651   }
652   noitL(config_log, "n\t%lu.%03lu\t%d\t%.*s\n",
653         __now.tv_sec, __now.tv_usec / 1000UL, clv->raw_len,
654         clv->len, clv->buff);
655   free(clv->buff);
656   free(clv);
657   last_write_gen = __config_gen;
658   return 0;
659 }
660
661 void
662 noit_conf_log_init(const char *toplevel) {
663   int i, cnt = 0, o, ocnt = 0;
664   noit_conf_section_t *log_configs, *outlets;
665   char path[256];
666
667   snprintf(path, sizeof(path), "/%s/logs//log", toplevel);
668   log_configs = noit_conf_get_sections(NULL, path, &cnt);
669   noitL(noit_stderr, "Found %d %s stanzas\n", cnt, path);
670   for(i=0; i<cnt; i++) {
671     noit_log_stream_t ls;
672     char name[256], type[256], path[256];
673     noit_hash_table *config;
674     noit_conf_boolean disabled;
675
676     if(!noit_conf_get_stringbuf(log_configs[i],
677                                 "ancestor-or-self::node()/@name",
678                                 name, sizeof(name))) {
679       noitL(noit_error, "log section %d does not have a name attribute\n", i+1);
680       exit(-1);
681     }
682     if(!noit_conf_get_stringbuf(log_configs[i],
683                                 "ancestor-or-self::node()/@type",
684                                 type, sizeof(type))) {
685       type[0] = '\0';
686     }
687     if(!noit_conf_get_stringbuf(log_configs[i],
688                                 "ancestor-or-self::node()/@path",
689                                 path, sizeof(path))) {
690       path[0] = '\0';
691     }
692     config = noit_conf_get_hash(log_configs[i],
693                                 "ancestor-or-self::node()/config/*");
694     ls = noit_log_stream_new(name, type[0] ? type : NULL,
695                              path[0] ? path : NULL, config);
696     if(!ls) {
697       fprintf(stderr, "Error configuring log: %s[%s:%s]\n", name, type, path);
698       exit(-1);
699     }
700
701     if(noit_conf_get_boolean(log_configs[i],
702                              "ancestor-or-self::node()/@disabled",
703                              &disabled) && disabled)
704       ls->enabled = 0;
705      
706     outlets = noit_conf_get_sections(log_configs[i],
707                                      "ancestor-or-self::node()/outlet", &ocnt);
708     noitL(noit_debug, "found %d outlets for log '%s'\n", ocnt, name);
709
710     for(o=0; o<ocnt; o++) {
711       noit_log_stream_t outlet;
712       char oname[256];
713       noit_conf_get_stringbuf(outlets[o], "@name",
714                               oname, sizeof(oname));
715       outlet = noit_log_stream_find(oname);
716       if(!outlet) {
717         fprintf(stderr, "Cannot find outlet '%s' for %s[%s:%s]\n", oname,
718               name, type, path);
719         exit(-1);
720       }
721       else
722         noit_log_stream_add_stream(ls, outlet);
723     }
724     if(outlets) free(outlets);
725   }
726   if(log_configs) free(log_configs);
727 }
Note: See TracBrowser for help on using the browser.