root/src/noit_conf.c

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

inverted error condition, refs #34

  • 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)
153       if(realpath(path, master_config_file) == NULL)
154         noitL(noit_error, "realpath failed: %s\n", strerror(errno));
155     noit_conf_mark_changed();
156     return 0;
157   }
158   return -1;
159 }
160 int noit_conf_xml_xpath(xmlDocPtr *mc, xmlXPathContextPtr *xp) {
161   if(mc) *mc = master_config;
162   if(xp) *xp = xpath_ctxt;
163   return 0;
164 }
165 int noit_conf_save(const char *path) {
166   return -1;
167 }
168
169 void noit_conf_get_elements_into_hash(noit_conf_section_t section,
170                                       const char *path,
171                                       noit_hash_table *table) {
172   int i, cnt;
173   xmlXPathObjectPtr pobj = NULL;
174   xmlXPathContextPtr current_ctxt;
175   xmlNodePtr current_node = (xmlNodePtr)section;
176   xmlNodePtr node;
177
178   current_ctxt = xpath_ctxt;
179   if(current_node) {
180     current_ctxt = xmlXPathNewContext(master_config);
181     current_ctxt->node = current_node;
182   }
183   pobj = xmlXPathEval((xmlChar *)path, current_ctxt);
184   if(!pobj) goto out;
185   if(pobj->type != XPATH_NODESET) goto out;
186   if(xmlXPathNodeSetIsEmpty(pobj->nodesetval)) goto out;
187   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
188   for(i=0; i<cnt; i++) {
189     char *value;
190     node = xmlXPathNodeSetItem(pobj->nodesetval, i);
191     value = (char *)xmlXPathCastNodeToString(node);
192     noit_hash_replace(table,
193                       strdup((char *)node->name), strlen((char *)node->name),
194                       strdup(value), free, free);
195     xmlFree(value);
196   }
197  out:
198   if(pobj) xmlXPathFreeObject(pobj);
199   if(current_ctxt && current_ctxt != xpath_ctxt)
200     xmlXPathFreeContext(current_ctxt);
201 }
202 void noit_conf_get_into_hash(noit_conf_section_t section,
203                              const char *path,
204                              noit_hash_table *table) {
205   int cnt;
206   xmlXPathObjectPtr pobj = NULL;
207   xmlXPathContextPtr current_ctxt;
208   xmlNodePtr current_node = (xmlNodePtr)section;
209   xmlNodePtr node, parent_node;
210   char xpath_expr[1024];
211   char *inheritid;
212
213   current_ctxt = xpath_ctxt;
214   if(current_node) {
215     current_ctxt = xmlXPathNewContext(master_config);
216     current_ctxt->node = current_node;
217   }
218   if(path[0] == '/')
219     strlcpy(xpath_expr, path, sizeof(xpath_expr));
220   else
221     snprintf(xpath_expr, sizeof(xpath_expr),
222              "ancestor-or-self::node()/%s", path);
223   pobj = xmlXPathEval((xmlChar *)xpath_expr, current_ctxt);
224   if(!pobj) goto out;
225   if(pobj->type != XPATH_NODESET) goto out;
226   if(xmlXPathNodeSetIsEmpty(pobj->nodesetval)) goto out;
227   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
228   /* These are in the order of root to leaf
229    * We want to recurse... apply:
230    *   1. our parent's config
231    *   2. our "inherit" config if it exists.
232    *   3. our config.
233    */
234   node = xmlXPathNodeSetItem(pobj->nodesetval, cnt-1);
235   /* 1. */
236   if(cnt > 1) {
237     parent_node = xmlXPathNodeSetItem(pobj->nodesetval, cnt-2);
238     if(parent_node != current_node)
239       noit_conf_get_into_hash(parent_node, (const char *)node->name, table);
240   }
241   /* 2. */
242   inheritid = (char *)xmlGetProp(node, (xmlChar *)"inherit");
243   if(inheritid) {
244     snprintf(xpath_expr, sizeof(xpath_expr), "//*[@id=\"%s\"]", inheritid);
245     noit_conf_get_into_hash(NULL, xpath_expr, table);
246   }
247   /* 3. */
248   noit_conf_get_elements_into_hash(node, "*", table);
249
250  out:
251   if(pobj) xmlXPathFreeObject(pobj);
252   if(current_ctxt && current_ctxt != xpath_ctxt)
253     xmlXPathFreeContext(current_ctxt);
254 }
255 noit_hash_table *noit_conf_get_hash(noit_conf_section_t section,
256                                     const char *path) {
257   noit_hash_table *table = NULL;
258
259   table = calloc(1, sizeof(*table));
260   noit_conf_get_into_hash(section, path, table);
261   return table;
262 }
263 noit_conf_section_t noit_conf_get_section(noit_conf_section_t section,
264                                           const char *path) {
265   noit_conf_section_t subsection = NULL;
266   xmlXPathObjectPtr pobj = NULL;
267   xmlXPathContextPtr current_ctxt;
268   xmlNodePtr current_node = (xmlNodePtr)section;
269
270   current_ctxt = xpath_ctxt;
271   if(current_node) {
272     current_ctxt = xmlXPathNewContext(master_config);
273     current_ctxt->node = current_node;
274   }
275   pobj = xmlXPathEval((xmlChar *)path, current_ctxt);
276   if(!pobj) goto out;
277   if(pobj->type != XPATH_NODESET) goto out;
278   if(xmlXPathNodeSetIsEmpty(pobj->nodesetval)) goto out;
279   subsection = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0);
280  out:
281   if(pobj) xmlXPathFreeObject(pobj);
282   if(current_ctxt && current_ctxt != xpath_ctxt)
283     xmlXPathFreeContext(current_ctxt);
284   return subsection;
285 }
286 noit_conf_section_t *noit_conf_get_sections(noit_conf_section_t section,
287                                             const char *path,
288                                             int *cnt) {
289   int i;
290   noit_conf_section_t *sections = NULL;
291   xmlXPathObjectPtr pobj = NULL;
292   xmlXPathContextPtr current_ctxt;
293   xmlNodePtr current_node = (xmlNodePtr)section;
294
295   *cnt = 0;
296   current_ctxt = xpath_ctxt;
297   if(current_node) {
298     current_ctxt = xmlXPathNewContext(master_config);
299     current_ctxt->node = current_node;
300   }
301   pobj = xmlXPathEval((xmlChar *)path, current_ctxt);
302   if(!pobj) goto out;
303   if(pobj->type != XPATH_NODESET) goto out;
304   if(xmlXPathNodeSetIsEmpty(pobj->nodesetval)) goto out;
305   *cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
306   sections = calloc(*cnt, sizeof(*sections));
307   for(i=0; i<*cnt; i++)
308     sections[i] = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i);
309  out:
310   if(pobj) xmlXPathFreeObject(pobj);
311   if(current_ctxt && current_ctxt != xpath_ctxt)
312     xmlXPathFreeContext(current_ctxt);
313   return sections;
314 }
315 int _noit_conf_get_string(noit_conf_section_t section, xmlNodePtr *vnode,
316                           const char *path, char **value) {
317   const char *str;
318   int i, rv = 1;
319   xmlXPathObjectPtr pobj = NULL;
320   xmlXPathContextPtr current_ctxt;
321   xmlNodePtr current_node = (xmlNodePtr)section;
322
323   current_ctxt = xpath_ctxt;
324   if(current_node) {
325     current_ctxt = xmlXPathNewContext(master_config);
326     current_ctxt->node = current_node;
327   }
328   pobj = xmlXPathEval((xmlChar *)path, current_ctxt);
329   if(pobj) {
330     xmlNodePtr node;
331     switch(pobj->type) {
332       case XPATH_NODESET:
333         if(xmlXPathNodeSetIsEmpty(pobj->nodesetval)) goto fallback;
334         i = xmlXPathNodeSetGetLength(pobj->nodesetval);
335         node = xmlXPathNodeSetItem(pobj->nodesetval, i-1);
336         if(vnode) *vnode = node;
337         *value = (char *)xmlXPathCastNodeToString(node);
338         break;
339       default:
340         *value = (char *)xmlXPathCastToString(pobj);
341     }
342     goto found;
343   }
344  fallback:
345   if(noit_hash_retr_str(&_compiled_fallback,
346                         path, strlen(path), &str)) {
347     *value = (char *)xmlStrdup((xmlChar *)str);
348     goto found;
349   }
350   rv = 0;
351  found:
352   if(pobj) xmlXPathFreeObject(pobj);
353   if(current_ctxt && current_ctxt != xpath_ctxt)
354     xmlXPathFreeContext(current_ctxt);
355   return rv;
356 }
357 int noit_conf_get_uuid(noit_conf_section_t section,
358                        const char *path, uuid_t out) {
359   char *str;
360   if(_noit_conf_get_string(section,NULL,path,&str)) {
361     if(uuid_parse(str, out) == 0) return 1;
362     return 0;
363   }
364   return 0;
365 }
366 int noit_conf_get_string(noit_conf_section_t section,
367                          const char *path, char **value) {
368   char *str;
369   if(_noit_conf_get_string(section,NULL,path,&str)) {
370     *value = strdup(str);
371     xmlFree(str);
372     return 1;
373   }
374   return 0;
375 }
376 int noit_conf_get_stringbuf(noit_conf_section_t section,
377                             const char *path, char *buf, int len) {
378   char *str;
379   if(_noit_conf_get_string(section,NULL,path,&str)) {
380     strlcpy(buf, str, len);
381     xmlFree(str);
382     return 1;
383   }
384   return 0;
385 }
386 int noit_conf_set_string(noit_conf_section_t section,
387                          const char *path, const char *value) {
388   noit_hash_replace(&_tmp_config,
389                     strdup(path), strlen(path), (void *)strdup(value),
390                     free, free);
391   return 1;
392 }
393 int noit_conf_get_int(noit_conf_section_t section,
394                       const char *path, int *value) {
395   char *str;
396   long longval;
397   if(_noit_conf_get_string(section,NULL,path,&str)) {
398     int base = 10;
399     if(str[0] == '0') {
400       if(str[1] == 'x') base = 16;
401       else base = 8;
402     }
403     longval = strtol(str, NULL, base);
404     xmlFree(str);
405     *value = (int)longval;
406     return 1;
407   }
408   return 0;
409 }
410 int noit_conf_set_int(noit_conf_section_t section,
411                       const char *path, int value) {
412   char buffer[32];
413   snprintf(buffer, 32, "%d", value);
414   return noit_conf_set_string(section,path,buffer);
415 }
416 int noit_conf_get_float(noit_conf_section_t section,
417                         const char *path, float *value) {
418   char *str;
419   if(_noit_conf_get_string(section,NULL,path,&str)) {
420     *value = atof(str);
421     xmlFree(str);
422     return 1;
423   }
424   return 0;
425 }
426 int noit_conf_set_float(noit_conf_section_t section,
427                         const char *path, float value) {
428   char buffer[32];
429   snprintf(buffer, 32, "%f", value);
430   return noit_conf_set_string(section,path,buffer);
431 }
432 int noit_conf_get_boolean(noit_conf_section_t section,
433                           const char *path, noit_boolean *value) {
434   char *str;
435   if(_noit_conf_get_string(section,NULL,path,&str)) {
436     if(!strcasecmp(str, "true") ||
437        !strcasecmp(str, "on")) *value = noit_true;
438     else *value = noit_false;
439     xmlFree(str);
440     return 1;
441   }
442   return 0;
443 }
444 int noit_conf_set_boolean(noit_conf_section_t section,
445                           const char *path, noit_boolean value) {
446   if(value == noit_true)
447     return noit_conf_set_string(section,path,"true");
448   return noit_conf_set_string(section,path,"false");
449 }
450
451 struct config_line_vstr {
452   char *buff;
453   int raw_len;
454   int len;
455   int allocd;
456   enum { CONFIG_RAW = 0, CONFIG_COMPRESSED, CONFIG_B64 } target, encoded;
457 };
458 static int
459 noit_config_log_write_xml(void *vstr, const char *buffer, int len) {
460   struct config_line_vstr *clv = vstr;
461   assert(clv->encoded == CONFIG_RAW);
462   if(!clv->buff) {
463     clv->allocd = 8192;
464     clv->buff = malloc(clv->allocd);
465   }
466   while(len + clv->len > clv->allocd) {
467     char *newbuff;
468     int newsize = clv->allocd;
469     newsize <<= 1;
470     newbuff = realloc(clv->buff, newsize);
471     if(!newbuff) {
472       return -1;
473     }
474     clv->allocd = newsize;
475     clv->buff = newbuff;
476   }
477   memcpy(clv->buff + clv->len, buffer, len);
478   clv->len += len;
479   return len;
480 }
481 static int
482 noit_config_log_close_xml(void *vstr) {
483   struct config_line_vstr *clv = vstr;
484   uLong initial_dlen, dlen;
485   char *compbuff, *b64buff;
486
487   if(clv->buff == NULL) {
488     clv->encoded = clv->target;
489     return 0;
490   }
491   clv->raw_len = clv->len;
492   assert(clv->encoded == CONFIG_RAW);
493   if(clv->encoded == clv->target) return 0;
494
495   /* Compress */
496   initial_dlen = dlen = compressBound(clv->len);
497   compbuff = malloc(initial_dlen);
498   if(!compbuff) return -1;
499   if(Z_OK != compress2((Bytef *)compbuff, &dlen,
500                        (Bytef *)clv->buff, clv->len, 9)) {
501     noitL(noit_error, "Error compressing config for transmission.\n");
502     free(compbuff);
503     return -1;
504   }
505   free(clv->buff);
506   clv->buff = compbuff;
507   clv->allocd = initial_dlen;
508   clv->len = dlen;
509   clv->encoded = CONFIG_COMPRESSED;
510   if(clv->encoded == clv->target) return 0;
511
512   /* Encode */
513   initial_dlen = ((clv->len + 2) / 3) * 4;
514   b64buff = malloc(initial_dlen);
515   dlen = noit_b64_encode((unsigned char *)clv->buff, clv->len,
516                          b64buff, initial_dlen);
517   if(dlen == 0) {
518     free(b64buff);
519     return -1;
520   }
521   free(clv->buff);
522   clv->buff = b64buff;
523   clv->allocd = initial_dlen;
524   clv->len = dlen;
525   clv->encoded = CONFIG_B64;
526   if(clv->encoded == clv->target) return 0;
527   return -1;
528 }
529
530 int
531 noit_conf_reload(noit_console_closure_t ncct,
532                  int argc, char **argv,
533                  noit_console_state_t *state, void *closure) {
534   if(noit_conf_load(master_config_file)) {
535     nc_printf(ncct, "error loading config\n");
536     return -1;
537   }
538   return 0;
539 }
540 int
541 noit_conf_write_terminal(noit_console_closure_t ncct,
542                          int argc, char **argv,
543                          noit_console_state_t *state, void *closure) {
544   xmlOutputBufferPtr out;
545   xmlCharEncodingHandlerPtr enc;
546   enc = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_UTF8);
547   out = xmlOutputBufferCreateIO(noit_console_write_xml,
548                                 noit_console_close_xml,
549                                 ncct, enc);
550   xmlSaveFormatFileTo(out, master_config, "utf8", 1);
551   return 0;
552 }
553 int
554 noit_conf_write_file(noit_console_closure_t ncct,
555                      int argc, char **argv,
556                      noit_console_state_t *state, void *closure) {
557   int fd, len;
558   char master_file_tmp[PATH_MAX];
559   xmlOutputBufferPtr out;
560   xmlCharEncodingHandlerPtr enc;
561
562   snprintf(master_file_tmp, sizeof(master_file_tmp),
563            "%s.tmp", master_config_file);
564   unlink(master_file_tmp);
565   fd = open(master_file_tmp, O_CREAT|O_EXCL|O_WRONLY, 0640);
566   if(fd < 0) {
567     nc_printf(ncct, "Failed to open tmp file: %s\n", strerror(errno));
568     return -1;
569   }
570   enc = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_UTF8);
571   out = xmlOutputBufferCreateFd(fd, enc);
572   if(!out) {
573     close(fd);
574     unlink(master_file_tmp);
575     nc_printf(ncct, "internal error: OutputBufferCreate failed\n");
576     return -1;
577   }
578   len = xmlSaveFormatFileTo(out, master_config, "utf8", 1);
579   close(fd);
580   if(len <= 0) {
581     nc_printf(ncct, "internal error: writing to tmp file failed.\n");
582     return -1;
583   }
584   if(rename(master_file_tmp, master_config_file) != 0) {
585     nc_printf(ncct, "Failed to replace file: %s\n", strerror(errno));
586     return -1;
587   }
588   nc_printf(ncct, "%d bytes written.\n", len);
589   return 0;
590 }
591 char *
592 noit_conf_xml_in_mem(size_t *len) {
593   struct config_line_vstr *clv;
594   xmlOutputBufferPtr out;
595   xmlCharEncodingHandlerPtr enc;
596   char *rv;
597
598   clv = calloc(1, sizeof(*clv));
599   clv->target = CONFIG_RAW;
600   enc = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_UTF8);
601   out = xmlOutputBufferCreateIO(noit_config_log_write_xml,
602                                 noit_config_log_close_xml,
603                                 clv, enc);
604   xmlSaveFormatFileTo(out, master_config, "utf8", 1);
605   if(clv->encoded != CONFIG_RAW) {
606     noitL(noit_error, "Error logging configuration\n");
607     if(clv->buff) free(clv->buff);
608     free(clv);
609     return NULL;
610   }
611   rv = clv->buff;
612   *len = clv->len;
613   free(clv);
614   return rv;
615 }
616
617 int
618 noit_conf_write_log() {
619   static u_int32_t last_write_gen = 0;
620   static noit_log_stream_t config_log = NULL;
621   struct timeval __now;
622   xmlOutputBufferPtr out;
623   xmlCharEncodingHandlerPtr enc;
624   struct config_line_vstr *clv;
625   SETUP_LOG(config, return -1);
626
627   /* We know we haven't changed */
628   if(last_write_gen == __config_gen) return 0;
629
630   gettimeofday(&__now, NULL);
631   clv = calloc(1, sizeof(*clv));
632   clv->target = CONFIG_B64;
633   enc = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_UTF8);
634   out = xmlOutputBufferCreateIO(noit_config_log_write_xml,
635                                 noit_config_log_close_xml,
636                                 clv, enc);
637   xmlSaveFormatFileTo(out, master_config, "utf8", 1);
638   if(clv->encoded != CONFIG_B64) {
639     noitL(noit_error, "Error logging configuration\n");
640     if(clv->buff) free(clv->buff);
641     free(clv);
642     return -1;
643   }
644   noitL(config_log, "n\t%lu.%03lu\t%d\t%.*s\n",
645         __now.tv_sec, __now.tv_usec / 1000UL, clv->raw_len,
646         clv->len, clv->buff);
647   free(clv->buff);
648   free(clv);
649   last_write_gen = __config_gen;
650   return 0;
651 }
652
653 void
654 noit_conf_log_init(const char *toplevel) {
655   int i, cnt = 0, o, ocnt = 0;
656   noit_conf_section_t *log_configs, *outlets;
657   char path[256];
658
659   snprintf(path, sizeof(path), "/%s/logs//log", toplevel);
660   log_configs = noit_conf_get_sections(NULL, path, &cnt);
661   noitL(noit_stderr, "Found %d %s stanzas\n", cnt, path);
662   for(i=0; i<cnt; i++) {
663     noit_log_stream_t ls;
664     char name[256], type[256], path[256];
665     noit_hash_table *config;
666     noit_boolean disabled;
667     noit_boolean debug;
668
669     if(!noit_conf_get_stringbuf(log_configs[i],
670                                 "ancestor-or-self::node()/@name",
671                                 name, sizeof(name))) {
672       noitL(noit_error, "log section %d does not have a name attribute\n", i+1);
673       exit(-1);
674     }
675     if(!noit_conf_get_stringbuf(log_configs[i],
676                                 "ancestor-or-self::node()/@type",
677                                 type, sizeof(type))) {
678       type[0] = '\0';
679     }
680     if(!noit_conf_get_stringbuf(log_configs[i],
681                                 "ancestor-or-self::node()/@path",
682                                 path, sizeof(path))) {
683       path[0] = '\0';
684     }
685     config = noit_conf_get_hash(log_configs[i],
686                                 "ancestor-or-self::node()/config/*");
687     ls = noit_log_stream_new(name, type[0] ? type : NULL,
688                              path[0] ? path : NULL, NULL, config);
689     if(!ls) {
690       fprintf(stderr, "Error configuring log: %s[%s:%s]\n", name, type, path);
691       exit(-1);
692     }
693
694     if(noit_conf_get_boolean(log_configs[i],
695                              "ancestor-or-self::node()/@disabled",
696                              &disabled) && disabled)
697       ls->enabled = 0;
698      
699     if(noit_conf_get_boolean(log_configs[i],
700                              "ancestor-or-self::node()/@debug",
701                              &debug) && debug)
702       ls->debug = 1;
703      
704     outlets = noit_conf_get_sections(log_configs[i],
705                                      "ancestor-or-self::node()/outlet", &ocnt);
706     noitL(noit_debug, "Found %d outlets for log '%s'\n", ocnt, name);
707
708     for(o=0; o<ocnt; o++) {
709       noit_log_stream_t outlet;
710       char oname[256];
711       noit_conf_get_stringbuf(outlets[o], "@name",
712                               oname, sizeof(oname));
713       outlet = noit_log_stream_find(oname);
714       if(!outlet) {
715         fprintf(stderr, "Cannot find outlet '%s' for %s[%s:%s]\n", oname,
716               name, type, path);
717         exit(-1);
718       }
719       else
720         noit_log_stream_add_stream(ls, outlet);
721     }
722     if(outlets) free(outlets);
723   }
724   if(log_configs) free(log_configs);
725 }
Note: See TracBrowser for help on using the browser.