root/src/noit_conf.c

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

This is a hack, refs #87.

I don't like the way this is done. The problem here is that the log
log string is fixated for the first log stream and output vectors
use their own. So, you get all or nothing and can't debug at lower
tiers.

Ideally, the log API must change to accept (time, file, line) for
all the writes. That way they can do what they like with it and
we can create a maintainer/debug logger that brings crazy detailed
information.

We only have a few loggers now, it should be very easy.

  • 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_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_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 struct config_line_vstr {
450   char *buff;
451   int raw_len;
452   int len;
453   int allocd;
454   enum { CONFIG_RAW = 0, CONFIG_COMPRESSED, CONFIG_B64 } target, encoded;
455 };
456 static int
457 noit_config_log_write_xml(void *vstr, const char *buffer, int len) {
458   struct config_line_vstr *clv = vstr;
459   assert(clv->encoded == CONFIG_RAW);
460   if(!clv->buff) {
461     clv->allocd = 8192;
462     clv->buff = malloc(clv->allocd);
463   }
464   while(len + clv->len > clv->allocd) {
465     char *newbuff;
466     int newsize = clv->allocd;
467     newsize <<= 1;
468     newbuff = realloc(clv->buff, newsize);
469     if(!newbuff) {
470       return -1;
471     }
472     clv->allocd = newsize;
473     clv->buff = newbuff;
474   }
475   memcpy(clv->buff + clv->len, buffer, len);
476   clv->len += len;
477   return len;
478 }
479 static int
480 noit_config_log_close_xml(void *vstr) {
481   struct config_line_vstr *clv = vstr;
482   uLong initial_dlen, dlen;
483   char *compbuff, *b64buff;
484
485   if(clv->buff == NULL) {
486     clv->encoded = clv->target;
487     return 0;
488   }
489   clv->raw_len = clv->len;
490   assert(clv->encoded == CONFIG_RAW);
491   if(clv->encoded == clv->target) return 0;
492
493   /* Compress */
494   initial_dlen = dlen = compressBound(clv->len);
495   compbuff = malloc(initial_dlen);
496   if(!compbuff) return -1;
497   if(Z_OK != compress2((Bytef *)compbuff, &dlen,
498                        (Bytef *)clv->buff, clv->len, 9)) {
499     noitL(noit_error, "Error compressing config for transmission.\n");
500     free(compbuff);
501     return -1;
502   }
503   free(clv->buff);
504   clv->buff = compbuff;
505   clv->allocd = initial_dlen;
506   clv->len = dlen;
507   clv->encoded = CONFIG_COMPRESSED;
508   if(clv->encoded == clv->target) return 0;
509
510   /* Encode */
511   initial_dlen = ((clv->len + 2) / 3) * 4;
512   b64buff = malloc(initial_dlen);
513   dlen = noit_b64_encode((unsigned char *)clv->buff, clv->len,
514                          b64buff, initial_dlen);
515   if(dlen == 0) {
516     free(b64buff);
517     return -1;
518   }
519   free(clv->buff);
520   clv->buff = b64buff;
521   clv->allocd = initial_dlen;
522   clv->len = dlen;
523   clv->encoded = CONFIG_B64;
524   if(clv->encoded == clv->target) return 0;
525   return -1;
526 }
527
528 int
529 noit_conf_reload(noit_console_closure_t ncct,
530                  int argc, char **argv,
531                  noit_console_state_t *state, void *closure) {
532   if(noit_conf_load(master_config_file)) {
533     nc_printf(ncct, "error loading config\n");
534     return -1;
535   }
536   return 0;
537 }
538 int
539 noit_conf_write_terminal(noit_console_closure_t ncct,
540                          int argc, char **argv,
541                          noit_console_state_t *state, void *closure) {
542   xmlOutputBufferPtr out;
543   xmlCharEncodingHandlerPtr enc;
544   enc = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_UTF8);
545   out = xmlOutputBufferCreateIO(noit_console_write_xml,
546                                 noit_console_close_xml,
547                                 ncct, enc);
548   xmlSaveFormatFileTo(out, master_config, "utf8", 1);
549   return 0;
550 }
551 int
552 noit_conf_write_file(noit_console_closure_t ncct,
553                      int argc, char **argv,
554                      noit_console_state_t *state, void *closure) {
555   int fd, len;
556   char master_file_tmp[PATH_MAX];
557   xmlOutputBufferPtr out;
558   xmlCharEncodingHandlerPtr enc;
559
560   snprintf(master_file_tmp, sizeof(master_file_tmp),
561            "%s.tmp", master_config_file);
562   unlink(master_file_tmp);
563   fd = open(master_file_tmp, O_CREAT|O_EXCL|O_WRONLY, 0640);
564   if(fd < 0) {
565     nc_printf(ncct, "Failed to open tmp file: %s\n", strerror(errno));
566     return -1;
567   }
568   enc = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_UTF8);
569   out = xmlOutputBufferCreateFd(fd, enc);
570   if(!out) {
571     close(fd);
572     unlink(master_file_tmp);
573     nc_printf(ncct, "internal error: OutputBufferCreate failed\n");
574     return -1;
575   }
576   len = xmlSaveFormatFileTo(out, master_config, "utf8", 1);
577   close(fd);
578   if(len <= 0) {
579     nc_printf(ncct, "internal error: writing to tmp file failed.\n");
580     return -1;
581   }
582   if(rename(master_file_tmp, master_config_file) != 0) {
583     nc_printf(ncct, "Failed to replace file: %s\n", strerror(errno));
584     return -1;
585   }
586   nc_printf(ncct, "%d bytes written.\n", len);
587   return 0;
588 }
589 char *
590 noit_conf_xml_in_mem(size_t *len) {
591   struct config_line_vstr *clv;
592   xmlOutputBufferPtr out;
593   xmlCharEncodingHandlerPtr enc;
594   char *rv;
595
596   clv = calloc(1, sizeof(*clv));
597   clv->target = CONFIG_RAW;
598   enc = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_UTF8);
599   out = xmlOutputBufferCreateIO(noit_config_log_write_xml,
600                                 noit_config_log_close_xml,
601                                 clv, enc);
602   xmlSaveFormatFileTo(out, master_config, "utf8", 1);
603   if(clv->encoded != CONFIG_RAW) {
604     noitL(noit_error, "Error logging configuration\n");
605     if(clv->buff) free(clv->buff);
606     free(clv);
607     return NULL;
608   }
609   rv = clv->buff;
610   *len = clv->len;
611   free(clv);
612   return rv;
613 }
614
615 int
616 noit_conf_write_log() {
617   static u_int32_t last_write_gen = 0;
618   static noit_log_stream_t config_log = NULL;
619   struct timeval __now;
620   xmlOutputBufferPtr out;
621   xmlCharEncodingHandlerPtr enc;
622   struct config_line_vstr *clv;
623   SETUP_LOG(config, return -1);
624
625   /* We know we haven't changed */
626   if(last_write_gen == __config_gen) return 0;
627
628   gettimeofday(&__now, NULL);
629   clv = calloc(1, sizeof(*clv));
630   clv->target = CONFIG_B64;
631   enc = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_UTF8);
632   out = xmlOutputBufferCreateIO(noit_config_log_write_xml,
633                                 noit_config_log_close_xml,
634                                 clv, enc);
635   xmlSaveFormatFileTo(out, master_config, "utf8", 1);
636   if(clv->encoded != CONFIG_B64) {
637     noitL(noit_error, "Error logging configuration\n");
638     if(clv->buff) free(clv->buff);
639     free(clv);
640     return -1;
641   }
642   noitL(config_log, "n\t%lu.%03lu\t%d\t%.*s\n",
643         __now.tv_sec, __now.tv_usec / 1000UL, clv->raw_len,
644         clv->len, clv->buff);
645   free(clv->buff);
646   free(clv);
647   last_write_gen = __config_gen;
648   return 0;
649 }
650
651 void
652 noit_conf_log_init(const char *toplevel) {
653   int i, cnt = 0, o, ocnt = 0;
654   noit_conf_section_t *log_configs, *outlets;
655   char path[256];
656
657   snprintf(path, sizeof(path), "/%s/logs//log", toplevel);
658   log_configs = noit_conf_get_sections(NULL, path, &cnt);
659   noitL(noit_stderr, "Found %d %s stanzas\n", cnt, path);
660   for(i=0; i<cnt; i++) {
661     noit_log_stream_t ls;
662     char name[256], type[256], path[256];
663     noit_hash_table *config;
664     noit_boolean disabled;
665     noit_boolean debug;
666
667     if(!noit_conf_get_stringbuf(log_configs[i],
668                                 "ancestor-or-self::node()/@name",
669                                 name, sizeof(name))) {
670       noitL(noit_error, "log section %d does not have a name attribute\n", i+1);
671       exit(-1);
672     }
673     if(!noit_conf_get_stringbuf(log_configs[i],
674                                 "ancestor-or-self::node()/@type",
675                                 type, sizeof(type))) {
676       type[0] = '\0';
677     }
678     if(!noit_conf_get_stringbuf(log_configs[i],
679                                 "ancestor-or-self::node()/@path",
680                                 path, sizeof(path))) {
681       path[0] = '\0';
682     }
683     config = noit_conf_get_hash(log_configs[i],
684                                 "ancestor-or-self::node()/config/*");
685     ls = noit_log_stream_new(name, type[0] ? type : NULL,
686                              path[0] ? path : NULL, NULL, config);
687     if(!ls) {
688       fprintf(stderr, "Error configuring log: %s[%s:%s]\n", name, type, path);
689       exit(-1);
690     }
691
692     if(noit_conf_get_boolean(log_configs[i],
693                              "ancestor-or-self::node()/@disabled",
694                              &disabled) && disabled)
695       ls->enabled = 0;
696      
697     if(noit_conf_get_boolean(log_configs[i],
698                              "ancestor-or-self::node()/@debug",
699                              &debug) && debug)
700       ls->debug = 1;
701      
702     outlets = noit_conf_get_sections(log_configs[i],
703                                      "ancestor-or-self::node()/outlet", &ocnt);
704     noitL(noit_debug, "found %d outlets for log '%s'\n", ocnt, name);
705
706     for(o=0; o<ocnt; o++) {
707       noit_log_stream_t outlet;
708       char oname[256];
709       noit_conf_get_stringbuf(outlets[o], "@name",
710                               oname, sizeof(oname));
711       outlet = noit_log_stream_find(oname);
712       if(!outlet) {
713         fprintf(stderr, "Cannot find outlet '%s' for %s[%s:%s]\n", oname,
714               name, type, path);
715         exit(-1);
716       }
717       else
718         noit_log_stream_add_stream(ls, outlet);
719     }
720     if(outlets) free(outlets);
721   }
722   if(log_configs) free(log_configs);
723 }
Note: See TracBrowser for help on using the browser.