root/src/noit_conf.c

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

fixes #126

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