root/src/noit_conf.c

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

make it 'cd'.. I can't seemt to type 'section'. Nav and listing.

  • 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 <assert.h>
10 #include <libxml/parser.h>
11 #include <libxml/tree.h>
12 #include <libxml/xpath.h>
13
14 #include "noit_conf.h"
15 #include "noit_check.h"
16 #include "noit_console.h"
17 #include "utils/noit_hash.h"
18 #include "utils/noit_log.h"
19
20 /* tmp hash impl, replace this with something nice */
21 static noit_hash_table _tmp_config = NOIT_HASH_EMPTY;
22 static xmlDocPtr master_config = NULL;
23 static xmlXPathContextPtr xpath_ctxt = NULL;
24
25 static noit_hash_table _compiled_fallback = NOIT_HASH_EMPTY;
26 static struct {
27   const char *key;
28   const char *val;
29 } config_info[] = {
30   /*
31    * These are compile-time fallbacks to be used in the event
32    * that the current running config does not have values for
33    * these config paths.
34    *
35    * PLEASE: keep them alphabetically sorted.
36    */
37   { "/noit/modules/directory", MODULES_DIR },
38
39   { NULL, NULL }
40 };
41
42 static void register_console_config_commands();
43
44 void noit_conf_init() {
45   int i;
46   for(i = 0; config_info[i].key != NULL; i++) {
47     noit_hash_store(&_compiled_fallback,
48                     strdup(config_info[i].key), strlen(config_info[i].key),
49                     (void *)strdup(config_info[i].val));
50   }
51   xmlInitParser();
52   xmlXPathInit();
53   register_console_config_commands();
54 }
55
56 int noit_conf_load(const char *path) {
57   xmlDocPtr new_config;
58   new_config = xmlParseFile(path);
59   if(new_config) {
60     if(master_config) xmlFreeDoc(master_config);
61     if(xpath_ctxt) xmlXPathFreeContext(xpath_ctxt);
62
63     master_config = new_config;
64     xpath_ctxt = xmlXPathNewContext(master_config);
65     return 0;
66   }
67   return -1;
68 }
69 int noit_conf_save(const char *path) {
70   return -1;
71 }
72
73 noit_hash_table *noit_conf_get_hash(noit_conf_section_t section,
74                                     const char *path) {
75   int i, cnt;
76   noit_hash_table *table = NULL;
77   xmlXPathObjectPtr pobj = NULL;
78   xmlXPathContextPtr current_ctxt;
79   xmlNodePtr current_node = (xmlNodePtr)section;
80   xmlNodePtr node;
81
82   current_ctxt = xpath_ctxt;
83   if(current_node) {
84     current_ctxt = xmlXPathNewContext(master_config);
85     current_ctxt->node = current_node;
86   }
87   pobj = xmlXPathEval((xmlChar *)path, current_ctxt);
88   if(!pobj) goto out;
89   if(pobj->type != XPATH_NODESET) goto out;
90   if(xmlXPathNodeSetIsEmpty(pobj->nodesetval)) goto out;
91   table = calloc(1, sizeof(*table));
92   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
93   for(i=0; i<cnt; i++) {
94     char *value;
95     node = xmlXPathNodeSetItem(pobj->nodesetval, i);
96     value = (char *)xmlXPathCastNodeToString(node);
97     noit_hash_replace(table,
98                       strdup((char *)node->name), strlen((char *)node->name),
99                       strdup(value), free, free);
100   }
101  out:
102   if(pobj) xmlXPathFreeObject(pobj);
103   if(current_ctxt && current_ctxt != xpath_ctxt)
104     xmlXPathFreeContext(current_ctxt);
105   return table;
106 }
107 noit_conf_section_t noit_conf_get_section(noit_conf_section_t section,
108                                           const char *path) {
109   noit_conf_section_t subsection = NULL;
110   xmlXPathObjectPtr pobj = NULL;
111   xmlXPathContextPtr current_ctxt;
112   xmlNodePtr current_node = (xmlNodePtr)section;
113
114   current_ctxt = xpath_ctxt;
115   if(current_node) {
116     current_ctxt = xmlXPathNewContext(master_config);
117     current_ctxt->node = current_node;
118   }
119   pobj = xmlXPathEval((xmlChar *)path, current_ctxt);
120   if(!pobj) goto out;
121   if(pobj->type != XPATH_NODESET) goto out;
122   if(xmlXPathNodeSetIsEmpty(pobj->nodesetval)) goto out;
123   subsection = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0);
124  out:
125   if(pobj) xmlXPathFreeObject(pobj);
126   if(current_ctxt && current_ctxt != xpath_ctxt)
127     xmlXPathFreeContext(current_ctxt);
128   return subsection;
129 }
130 noit_conf_section_t *noit_conf_get_sections(noit_conf_section_t section,
131                                             const char *path,
132                                             int *cnt) {
133   int i;
134   noit_conf_section_t *sections = NULL;
135   xmlXPathObjectPtr pobj = NULL;
136   xmlXPathContextPtr current_ctxt;
137   xmlNodePtr current_node = (xmlNodePtr)section;
138
139   *cnt = 0;
140   current_ctxt = xpath_ctxt;
141   if(current_node) {
142     current_ctxt = xmlXPathNewContext(master_config);
143     current_ctxt->node = current_node;
144   }
145   pobj = xmlXPathEval((xmlChar *)path, current_ctxt);
146   if(!pobj) goto out;
147   if(pobj->type != XPATH_NODESET) goto out;
148   if(xmlXPathNodeSetIsEmpty(pobj->nodesetval)) goto out;
149   *cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
150   sections = calloc(*cnt, sizeof(*sections));
151   for(i=0; i<*cnt; i++)
152     sections[i] = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i);
153  out:
154   if(pobj) xmlXPathFreeObject(pobj);
155   if(current_ctxt && current_ctxt != xpath_ctxt)
156     xmlXPathFreeContext(current_ctxt);
157   return sections;
158 }
159 int _noit_conf_get_string(noit_conf_section_t section,
160                           const char *path, char **value) {
161   char *str;
162   int i;
163   xmlXPathObjectPtr pobj;
164   xmlXPathContextPtr current_ctxt;
165   xmlNodePtr current_node = (xmlNodePtr)section;
166
167   current_ctxt = xpath_ctxt;
168   if(current_node) {
169     current_ctxt = xmlXPathNewContext(master_config);
170     current_ctxt->node = current_node;
171   }
172   pobj = xmlXPathEval((xmlChar *)path, current_ctxt);
173   if(pobj) {
174     xmlNodePtr node;
175     switch(pobj->type) {
176       case XPATH_NODESET:
177         if(xmlXPathNodeSetIsEmpty(pobj->nodesetval)) return 0;
178         i = xmlXPathNodeSetGetLength(pobj->nodesetval);
179         node = xmlXPathNodeSetItem(pobj->nodesetval, i-1);
180         *value = (char *)xmlXPathCastNodeToString(node);
181         break;
182       default:
183         *value = (char *)xmlXPathCastToString(pobj);
184     }
185     goto found;
186   }
187   if(noit_hash_retrieve(&_compiled_fallback,
188                         path, strlen(path), (void **)&str)) {
189     *value = str;
190     goto found;
191   }
192   return 0;
193  found:
194   if(current_ctxt && current_ctxt != xpath_ctxt)
195     xmlXPathFreeContext(current_ctxt);
196   return 1;
197 }
198 int noit_conf_get_string(noit_conf_section_t section,
199                          const char *path, char **value) {
200   char *str;
201   if(_noit_conf_get_string(section,path,&str)) {
202     *value = strdup(str);
203     return 1;
204   }
205   return 0;
206 }
207 int noit_conf_get_stringbuf(noit_conf_section_t section,
208                             const char *path, char *buf, int len) {
209   char *str;
210   if(_noit_conf_get_string(section,path,&str)) {
211     strlcpy(buf, str, len);
212     return 1;
213   }
214   return 0;
215 }
216 int noit_conf_set_string(noit_conf_section_t section,
217                          const char *path, const char *value) {
218   noit_hash_replace(&_tmp_config,
219                     strdup(path), strlen(path), (void *)strdup(value),
220                     free, free);
221   return 1;
222 }
223 int noit_conf_get_int(noit_conf_section_t section,
224                       const char *path, int *value) {
225   char *str;
226   long longval;
227   if(noit_conf_get_string(section,path,&str)) {
228     int base = 10;
229     if(str[0] == '0') {
230       if(str[1] == 'x') base = 16;
231       else base = 8;
232     }
233     longval = strtol(str, NULL, base);
234     free(str);
235     *value = (int)longval;
236     return 1;
237   }
238   return 0;
239 }
240 int noit_conf_set_int(noit_conf_section_t section,
241                       const char *path, int value) {
242   char buffer[32];
243   snprintf(buffer, 32, "%d", value);
244   return noit_conf_set_string(section,path,buffer);
245 }
246 int noit_conf_get_float(noit_conf_section_t section,
247                         const char *path, float *value) {
248   char *str;
249   if(noit_conf_get_string(section,path,&str)) {
250     *value = atof(str);
251     free(str);
252     return 1;
253   }
254   return 0;
255 }
256 int noit_conf_set_float(noit_conf_section_t section,
257                         const char *path, float value) {
258   char buffer[32];
259   snprintf(buffer, 32, "%f", value);
260   return noit_conf_set_string(section,path,buffer);
261 }
262 int noit_conf_get_boolean(noit_conf_section_t section,
263                           const char *path, noit_conf_boolean *value) {
264   char *str;
265   if(noit_conf_get_string(section,path,&str)) {
266     if(!strcasecmp(str, "true")) *value = noit_true;
267     else *value = noit_false;
268     free(str);
269     return 1;
270   }
271   return 0;
272 }
273 int noit_conf_set_boolean(noit_conf_section_t section,
274                           const char *path, noit_conf_boolean value) {
275   if(value == noit_true)
276     return noit_conf_set_string(section,path,"true");
277   return noit_conf_set_string(section,path,"false");
278 }
279
280 static void
281 conf_t_userdata_free(void *data) {
282   noit_conf_t_userdata_t *info = data;
283   if(info) {
284     if(info->path) free(info->path);
285     free(info);
286   }
287 }
288 static int
289 noit_console_state_conf_terminal(noit_console_closure_t ncct,
290                                  int argc, char **argv,
291                                  noit_console_state_t *state, void *closure) {
292   noit_conf_t_userdata_t *info;
293   if(argc) {
294     nc_printf(ncct, "extra arguments not expected.\n");
295     return -1;
296   }
297   info = calloc(1, sizeof(*info));
298   info->path = strdup("/");
299   noit_console_userdata_set(ncct, NOIT_CONF_T_USERDATA, info,
300                             conf_t_userdata_free);
301   noit_console_state_push_state(ncct, state);
302   noit_console_state_init(ncct);
303   return 0;
304 }
305
306 static int
307 noit_console_config_cd(noit_console_closure_t ncct,
308                        int argc, char **argv,
309                        noit_console_state_t *state, void *closure) {
310   const char *err = "internal error";
311   char *path, xpath[1024];
312   noit_conf_t_userdata_t *info;
313   xmlXPathObjectPtr pobj = NULL;
314   xmlXPathContextPtr current_ctxt;
315   xmlNodePtr node = NULL;
316
317   if(argc != 1) {
318     nc_printf(ncct, "requires one argument\n");
319     return -1;
320   }
321   info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
322   if(argv[0][0] == '/')
323     snprintf(xpath, sizeof(xpath), "/noit%s", argv[0]);
324   else {
325     snprintf(xpath, sizeof(xpath), "/noit%s/%s", info->path, argv[0]);
326   }
327   if(xpath[strlen(xpath)-1] == '/') xpath[strlen(xpath)-1] = '\0';
328
329   current_ctxt = xpath_ctxt;
330   pobj = xmlXPathEval((xmlChar *)xpath, current_ctxt);
331   if(!pobj || pobj->type != XPATH_NODESET ||
332      xmlXPathNodeSetIsEmpty(pobj->nodesetval)) {
333     err = "no such section";
334     goto bad;
335   }
336   if(xmlXPathNodeSetGetLength(pobj->nodesetval) > 1) {
337     err = "ambiguous section";
338     goto bad;
339   }
340
341   node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0);
342   path = (char *)xmlGetNodePath(node);
343   if(strncmp(path, "/noit/", strlen("/noit/")) && strcmp(path, "/noit")) {
344     err = "new path outside out tree";
345     goto bad;
346   }
347   free(info->path);
348   if(!strcmp(path, "/noit"))
349     info->path = strdup("/");
350   else
351     info->path = strdup((char *)xmlGetNodePath(node) + strlen("/noit"));
352   if(pobj) xmlXPathFreeObject(pobj);
353   return 0;
354  bad:
355   if(pobj) xmlXPathFreeObject(pobj);
356   nc_printf(ncct, "%s\n", err);
357   return -1;
358 }
359 static int
360 noit_console_config_show(noit_console_closure_t ncct,
361                          int argc, char **argv,
362                          noit_console_state_t *state, void *closure) {
363   int i, cnt, titled = 0, cliplen = 0;
364   const char *path;
365   char xpath[1024];
366   noit_conf_t_userdata_t *info;
367   xmlXPathObjectPtr pobj = NULL;
368   xmlXPathContextPtr current_ctxt;
369   xmlNodePtr node;
370
371   if(argc > 1) {
372     nc_printf(ncct, "too many arguments\n");
373     return -1;
374   }
375   if(argc == 1) {
376     path = argv[0];
377   }
378   else {
379     info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
380     if(!info) {
381       nc_printf(ncct, "argument required when not in configuration mode\n");
382       return -1;
383     }
384     path = info->path;
385   }
386   if(!master_config) {
387     nc_printf(ncct, "no config\n");
388     return -1;
389   }
390
391   /* { / } is the only path that will end with a /
392    * in XPath { / / * } means something _entirely different than { / * }
393    * Ever notice how it is hard to describe xpath in C comments?
394    */
395   cliplen = strlen("/noit/");
396   if(!strcmp(path, "/"))
397     snprintf(xpath, sizeof(xpath), "/noit/*");
398   else {
399     if(argc == 0) cliplen = strlen("/noit/") + strlen(path);
400     snprintf(xpath, sizeof(xpath), "/noit%s/*", path);
401   }
402
403   current_ctxt = xpath_ctxt;
404   pobj = xmlXPathEval((xmlChar *)xpath, current_ctxt);
405   if(!pobj || pobj->type != XPATH_NODESET) {
406     nc_printf(ncct, "no such object\n");
407     goto bad;
408   }
409   if(xmlXPathNodeSetIsEmpty(pobj->nodesetval)) {
410     nc_printf(ncct, "empty\n");
411   }
412   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
413
414   titled = 0;
415   for(i=0; i<cnt; i++) {
416     node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i);
417     if(!strcmp((char *)node->name, "check")) continue;
418     if(node->children && node->children == xmlGetLastChild(node) &&
419       xmlNodeIsText(node->children)) {
420       if(!titled++) nc_printf(ncct, "== Section Settings ==\n");
421       nc_printf(ncct, "%s: %s\n", xmlGetNodePath(node) + cliplen,
422                 xmlXPathCastNodeToString(node->children));
423     }
424   }
425
426   titled = 0;
427   for(i=0; i<cnt; i++) {
428     node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i);
429     if(!strcmp((char *)node->name, "check")) continue;
430     if(!(node->children && node->children == xmlGetLastChild(node) &&
431          xmlNodeIsText(node->children))) {
432       if(!titled++) nc_printf(ncct, "== Subsections ==\n");
433       nc_printf(ncct, "%s\n", xmlGetNodePath(node) + cliplen);
434     }
435   }
436
437   titled = 0;
438   for(i=0; i<cnt; i++) {
439     node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i);
440     if(!strcmp((char *)node->name, "check")) {
441       int busted = 1;
442       xmlAttr *attr;
443       char *uuid_str = "undefined";;
444
445       if(!titled++) nc_printf(ncct, "== Checks ==\n");
446
447       for(attr=node->properties; attr; attr = attr->next) {
448         if(!strcmp((char *)attr->name, "uuid"))
449           uuid_str = (char *)xmlXPathCastNodeToString(attr->children);
450       }
451       if(uuid_str) {
452         uuid_t checkid;
453         nc_printf(ncct, "check[@uuid=\"%s\"] ", uuid_str);
454         if(uuid_parse(uuid_str, checkid) == 0) {
455           noit_check_t *check;
456           check = noit_poller_lookup(checkid);
457           if(check) {
458             busted = 0;
459             nc_printf(ncct, "%s`%s", check->target, check->name);
460           }
461         }
462       }
463       else
464         nc_printf(ncct, "%s ", xmlGetNodePath(node) + cliplen);
465       if(busted) nc_printf(ncct, "[check not in running system]");
466       nc_write(ncct, "\n", 1);
467     }
468   }
469   xmlXPathFreeObject(pobj);
470   return 0;
471  bad:
472   if(pobj) xmlXPathFreeObject(pobj);
473   return -1;
474 }
475
476 static char *
477 conf_t_prompt(EditLine *el) {
478   noit_console_closure_t ncct;
479   noit_conf_t_userdata_t *info;
480   static char *tl = "noit(conf)# ";
481   static char *pfmt = "noit(conf:%s%s)# ";
482   int path_len, max_len;
483
484   el_get(el, EL_USERDATA, (void *)&ncct);
485   if(!ncct) return tl;
486   info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
487   if(!info) return tl;
488
489   path_len = strlen(info->path);
490   max_len = strlen(pfmt) - 4 /* %s%s */ - 1 /* \0 */;
491   if(path_len > max_len)
492     snprintf(info->prompt, sizeof(info->prompt),
493              pfmt, "...", info->path + max_len - 3 /* ... */);
494   else
495     snprintf(info->prompt, sizeof(info->prompt), pfmt, "", info->path);
496   return info->prompt;
497 }
498
499 static
500 void register_console_config_commands() {
501   noit_console_state_t *tl, *_conf_state, *_conf_t_state;
502
503   tl = noit_console_state_initial();
504
505   _conf_t_state = calloc(1, sizeof(*_conf_t_state));
506   _conf_t_state->console_prompt_function = conf_t_prompt;
507   noit_console_state_add_cmd(_conf_t_state, &console_command_exit);
508   noit_console_state_add_cmd(_conf_t_state,
509     NCSCMD("ls", noit_console_config_show, NULL, NULL));
510   noit_console_state_add_cmd(_conf_t_state,
511     NCSCMD("cd", noit_console_config_cd, NULL, NULL));
512
513   _conf_state = calloc(1, sizeof(*_conf_state));
514   noit_console_state_add_cmd(_conf_state,
515     NCSCMD("terminal", noit_console_state_conf_terminal, _conf_t_state, NULL));
516
517   noit_console_state_add_cmd(tl,
518     NCSCMD("configure", noit_console_state_delegate, _conf_state, NULL));
519 }
Note: See TracBrowser for help on using the browser.