root/src/noit_conf_checks.c

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

progress (perhaps complete) work on check enhancements, refs #18

  • Property mode set to 100644
Line 
1
2 /*
3  * Copyright (c) 2007, OmniTI Computer Consulting, Inc.
4  * All rights reserved.
5  */
6
7 #include "noit_defines.h"
8
9 #include <stdio.h>
10 #include <unistd.h>
11 #include <fcntl.h>
12 #include <errno.h>
13 #include <assert.h>
14 #include <libxml/parser.h>
15 #include <libxml/tree.h>
16 #include <libxml/xpath.h>
17
18 #include "noit_conf.h"
19 #include "noit_conf_private.h"
20 #include "noit_check.h"
21 #include "noit_console.h"
22 #include "utils/noit_hash.h"
23 #include "utils/noit_log.h"
24
25 static void register_console_config_commands();
26 static int noit_console_config_cd(noit_console_closure_t ncct,
27                                   int argc, char **argv,
28                                   noit_console_state_t *state, void *closure);
29
30 static struct _valid_attr_t {
31   const char *scope;
32   const char *name;
33   const char *xpath;
34   int checks_fixate;
35 } valid_attrs[] = {
36   { "/checks", "name", "@name", 0 },
37   { "/checks", "target", "@target", 0 },
38   { "/checks", "period", "@period", 0 },
39   { "/checks", "timeout", "@timeout", 0 },
40   { "/checks", "oncheck", "@oncheck", 0 },
41   { "/checks", "disable", "@disable", 0 },
42   { "/checks", "module", "@module", 1 },
43 };
44
45 void
46 noit_console_state_add_check_attrs(noit_console_state_t *state,
47                                    console_cmd_func_t f) {
48   int i;
49   for(i = 0;
50       i < sizeof(valid_attrs)/sizeof(valid_attrs[0]);
51       i++) {
52     noit_console_state_add_cmd(state,
53       NCSCMD(valid_attrs[i].name, f,
54              NULL, &valid_attrs[i]));
55   }
56 }
57 static noit_hash_table check_attrs = NOIT_HASH_EMPTY;
58 void noit_conf_checks_init(const char *toplevel) {
59   int i;
60   for(i=0;i<sizeof(valid_attrs)/sizeof(*valid_attrs);i++) {
61     noit_hash_store(&check_attrs,
62                     valid_attrs[i].name, strlen(valid_attrs[i].name),
63                     &valid_attrs[i]);
64   }
65   register_console_config_commands();
66 }
67
68 static void
69 conf_t_userdata_free(void *data) {
70   noit_conf_t_userdata_t *info = data;
71   if(info) {
72     if(info->path) free(info->path);
73     free(info);
74   }
75 }
76
77 static int
78 noit_console_mkcheck_xpath(char *xpath, int len,
79                            noit_conf_t_userdata_t *info,
80                            const char *arg) {
81   uuid_t checkid;
82   char argcopy[1024], *target, *module, *name;
83
84   argcopy[0] = '\0';
85   if(arg) strlcpy(argcopy, arg, sizeof(argcopy));
86
87   if(uuid_parse(argcopy, checkid) == 0) {
88     /* If they kill by uuid, we'll seek and destroy -- find it anywhere */
89     snprintf(xpath, len, "/noit/checks//check[@uuid=\"%s\"]",
90              argcopy);
91   }
92   else if((module = strchr(argcopy, '`')) != NULL) {
93     noit_check_t *check;
94     char uuid_str[37];
95     target = argcopy;
96     *module++ = '\0';
97     if((name = strchr(module+1, '`')) == NULL)
98       name = module;
99     else
100       name++;
101     check = noit_poller_lookup_by_name(target, name);
102     if(!check) {
103       return -1;
104     }
105     uuid_unparse_lower(check->checkid, uuid_str);
106     snprintf(xpath, len, "/noit/checks//check[@uuid=\"%s\"]",
107              uuid_str);
108   }
109   else {
110     char *path = (!info || !strcmp(info->path, "/")) ? "" : info->path;
111     snprintf(xpath, len, "/noit%s%s%s[@uuid]",
112              path, arg ? "/" : "", arg ? arg : "");
113   }
114   return 0;
115 }
116 static void
117 nc_attr_show(noit_console_closure_t ncct, const char *name, xmlNodePtr cnode,
118              xmlNodePtr anode, const char *value) {
119   const char *cpath, *apath;
120   cpath = cnode ? (char *)xmlGetNodePath(cnode) : "";
121   apath = anode ? (char *)xmlGetNodePath(anode) : "";
122   nc_printf(ncct, " %s: %s", name, value ? value : "[undef]");
123   if(value && cpath && apath) {
124     int clen = strlen(cpath);
125     int plen = strlen("/noit/checks/");
126     if(!strncmp(cpath, apath, clen) && apath[clen] == '/') {
127       /* we have a match, which means it isn't inherited */
128     }
129     else {
130       nc_printf(ncct, " [inherited from %s]",
131                 strlen(apath) > plen ? apath + plen : apath);
132     }
133   }
134   nc_write(ncct, "\n", 1);
135 }
136 static void
137 refresh_subchecks(noit_console_closure_t ncct,
138                   noit_conf_t_userdata_t *info) {
139   char *path;
140   char xpath[1024];
141  
142   path = info->path;
143   if(!strcmp(path, "/")) path = "";
144
145   /* The first one is just a process_checks, the second is the reload.
146    * Reload does a lot of work and there is no need to do it twice.
147    */
148   snprintf(xpath, sizeof(xpath), "/noit/%s[@uuid]", path);
149   noit_poller_process_checks(xpath);
150   snprintf(xpath, sizeof(xpath), "/noit/%s//check[@uuid]", path);
151   noit_poller_reload(xpath);
152 }
153 static int
154 noit_config_check_update_attrs(xmlNodePtr node, int argc, char **argv) {
155   int i, error = 0;
156   if(argc % 2) return -1;
157
158   for(i=0; i<argc; i+=2) {
159     struct _valid_attr_t *attrinfo;
160     char *attr = argv[i], *val = NULL;
161     if(!strcasecmp(argv[i], "no")) attr = argv[i+1];
162     else val = argv[i+1];
163     if(!noit_hash_retrieve(&check_attrs, attr, strlen(attr),
164                            (void **)&attrinfo)) {
165       error = 1;
166       break;
167     }
168     /* The fixation stuff doesn't matter here, this check is brand-new */
169     xmlUnsetProp(node, (xmlChar *)attrinfo->name);
170     if(val)
171       xmlSetProp(node, (xmlChar *)attrinfo->name, (xmlChar *)val);
172   }
173   return error;
174 }
175
176 static int
177 noit_conf_mkcheck_under(const char *ppath, int argc, char **argv, uuid_t out) {
178   int rv = -1;
179   const char *path;
180   char xpath[1024];
181   xmlXPathContextPtr xpath_ctxt = NULL;
182   xmlXPathObjectPtr pobj = NULL;
183   xmlNodePtr node = NULL, newnode;
184
185   /* attr val [or] no attr (sets of two) */
186   if(argc % 2) goto out;
187
188   noit_conf_xml_xpath(NULL, &xpath_ctxt);
189   path = strcmp(ppath, "/") ? ppath : "";
190   snprintf(xpath, sizeof(xpath), "/noit%s", path);
191   pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
192   if(!pobj || pobj->type != XPATH_NODESET ||
193      xmlXPathNodeSetGetLength(pobj->nodesetval) != 1) {
194     goto out;
195   }
196   node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0);
197   if((newnode = xmlNewChild(node, NULL, (xmlChar *)"check", NULL)) != NULL) {
198     char outstr[37];
199     uuid_generate(out);
200     uuid_unparse_lower(out, outstr);
201     xmlSetProp(newnode, (xmlChar *)"uuid", (xmlChar *)outstr);
202     xmlSetProp(newnode, (xmlChar *)"disable", (xmlChar *)"true");
203
204     /* No risk of running off the end (we checked this above) */
205     if(noit_config_check_update_attrs(newnode, argc, argv)) {
206       /* Something went wrong, remove the node */
207       xmlUnlinkNode(newnode);
208     }
209     else
210       rv = 0;
211   }
212  out:
213   if(pobj) xmlXPathFreeObject(pobj);
214   return rv;
215 }
216 static int
217 noit_console_check(noit_console_closure_t ncct,
218                    int argc, char **argv,
219                    noit_console_state_t *state, void *closure) {
220   int cnt;
221   noit_conf_t_userdata_t *info;
222   char xpath[1024], newuuid_str[37];
223   char *uuid_conf, *wanted;
224   uuid_t checkid;
225   xmlXPathContextPtr xpath_ctxt = NULL;
226   xmlXPathObjectPtr pobj = NULL;
227   xmlNodePtr node = NULL;
228   noit_conf_boolean creating_new = noit_false;
229
230   if(closure) {
231     char *fake_argv[1] = { ".." };
232     noit_console_state_pop(ncct, 0, argv, NULL, NULL);
233     noit_console_config_cd(ncct, 1, fake_argv, NULL, NULL);
234   }
235
236   noit_conf_xml_xpath(NULL, &xpath_ctxt);
237   if(argc < 1) {
238     nc_printf(ncct, "requires at least one argument\n");
239     return -1;
240   }
241   if(argc % 2 == 0) {
242     nc_printf(ncct, "wrong number of arguments\n");
243     return -1;
244   }
245
246   info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
247   wanted = strcmp(argv[0], "new") ? argv[0] : NULL;
248   if(info && !wanted) {
249     /* We are creating a new node */
250     uuid_t out;
251     creating_new = noit_true;
252     if(noit_conf_mkcheck_under(info->path, argc - 1, argv + 1, out)) {
253       nc_printf(ncct, "Error creating new check\n");
254       return -1;
255     }
256     newuuid_str[0] = '\0';
257     uuid_unparse_lower(out, newuuid_str);
258     wanted = newuuid_str;
259   }
260   /* We many not be in conf-t mode -- that's fine */
261   if(noit_console_mkcheck_xpath(xpath, sizeof(xpath), info, wanted)) {
262     nc_printf(ncct, "could not find check '%s'\n", wanted);
263     return -1;
264   }
265
266   pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
267   if(!pobj || pobj->type != XPATH_NODESET ||
268      xmlXPathNodeSetIsEmpty(pobj->nodesetval)) {
269     nc_printf(ncct, "no checks found for '%s'\n", wanted);
270     goto out;
271   }
272   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
273   if(info && cnt != 1) {
274     nc_printf(ncct, "Ambiguous check specified\n");
275     goto out;
276   }
277   node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0);
278   uuid_conf = (char *)xmlGetProp(node, (xmlChar *)"uuid");
279   if(!uuid_conf || uuid_parse(uuid_conf, checkid)) {
280     nc_printf(ncct, "%s has invalid or missing UUID!\n",
281               (char *)xmlGetNodePath(node) + strlen("/noit"));
282     goto out;
283   }
284   if(argc > 1 && !creating_new)
285     if(noit_config_check_update_attrs(node, argc - 1, argv + 1))
286       nc_printf(ncct, "Partially successful, error setting some attributes\n");
287
288   if(info) {
289     if(info->path) free(info->path);
290     info->path = strdup((char *)xmlGetNodePath(node) + strlen("/noit"));
291     uuid_copy(info->current_check, checkid);
292     if(argc > 1) refresh_subchecks(ncct, info);
293     if(state) {
294       noit_console_state_push_state(ncct, state);
295       noit_console_state_init(ncct);
296     }
297     goto out;
298   }
299  out:
300   if(pobj) xmlXPathFreeObject(pobj);
301   return 0;
302 }
303 static int
304 noit_console_show_check(noit_console_closure_t ncct,
305                         int argc, char **argv,
306                         noit_console_state_t *state, void *closure) {
307   int i, cnt;
308   noit_conf_t_userdata_t *info;
309   char xpath[1024];
310   xmlXPathObjectPtr pobj = NULL;
311   xmlXPathContextPtr xpath_ctxt = NULL;
312
313   noit_conf_xml_xpath(NULL, &xpath_ctxt);
314   if(argc > 1) {
315     nc_printf(ncct, "requires zero or one arguments\n");
316     return -1;
317   }
318
319   info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
320   /* We many not be in conf-t mode -- that's fine */
321   if(noit_console_mkcheck_xpath(xpath, sizeof(xpath), info,
322                                 argc ? argv[0] : NULL)) {
323     nc_printf(ncct, "could not find check '%s'\n", argv[0]);
324     return -1;
325   }
326
327   pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
328   if(!pobj || pobj->type != XPATH_NODESET ||
329      xmlXPathNodeSetIsEmpty(pobj->nodesetval)) {
330     nc_printf(ncct, "no checks found\n");
331     goto out;
332   }
333   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
334   if(info && cnt != 1) {
335     nc_printf(ncct, "Ambiguous check specified\n");
336     goto out;
337   }
338   for(i=0; i<cnt; i++) {
339     noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
340     const char *k;
341     int klen;
342     void *data;
343     uuid_t checkid;
344     noit_check_t *check;
345     noit_hash_table *config;
346     xmlNodePtr node, anode, mnode = NULL;
347     char *uuid_conf;
348     char *module, *value;
349
350     node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i);
351     uuid_conf = (char *)xmlGetProp(node, (xmlChar *)"uuid");
352     if(!uuid_conf || uuid_parse(uuid_conf, checkid)) {
353       nc_printf(ncct, "%s has invalid or missing UUID!\n",
354                 (char *)xmlGetNodePath(node) + strlen("/noit"));
355       continue;
356     }
357     nc_printf(ncct, "==== %s ====\n", uuid_conf);
358
359 #define MYATTR(a,n,b) _noit_conf_get_string(node, &(n), "@" #a, &(b))
360 #define INHERIT(a,n,b) \
361   _noit_conf_get_string(node, &(n), "ancestor-or-self::node()/@" #a, &(b))
362 #define SHOW_ATTR(a) do { \
363   anode = NULL; \
364   value = NULL; \
365   INHERIT(a, anode, value); \
366   nc_attr_show(ncct, #a, node, anode, value); \
367 } while(0)
368
369     if(!INHERIT(module, mnode, module)) module = NULL;
370     if(MYATTR(name, anode, value))
371       nc_printf(ncct, " name: %s\n", value);
372     else
373       nc_printf(ncct, " name: %s [from module]\n", module ? module : "[undef]");
374     nc_attr_show(ncct, "module", node, mnode, module);
375     SHOW_ATTR(target);
376     SHOW_ATTR(period);
377     SHOW_ATTR(timeout);
378     SHOW_ATTR(oncheck);
379     SHOW_ATTR(disable);
380     /* Print out all the config settings */
381     config = noit_conf_get_hash(node, "config");
382     while(noit_hash_next(config, &iter, &k, &klen, &data)) {
383       nc_printf(ncct, " config::%s: %s\n", k, (const char *)data);
384     }
385     noit_hash_destroy(config, free, free);
386     free(config);
387
388     check = noit_poller_lookup(checkid);
389     if(!check) {
390       nc_printf(ncct, " ERROR: not in running system\n");
391     }
392     else {
393       int idx = 0;
394       nc_printf(ncct, " currently: ");
395       if(NOIT_CHECK_RUNNING(check)) nc_printf(ncct, "%srunning", idx++?",":"");
396       if(NOIT_CHECK_KILLED(check)) nc_printf(ncct, "%skilled", idx++?",":"");
397       if(!NOIT_CHECK_CONFIGURED(check)) nc_printf(ncct, "%sunconfig", idx++?",":"");
398       if(NOIT_CHECK_DISABLED(check)) nc_printf(ncct, "%sdisabled", idx++?",":"");
399       if(!idx) nc_printf(ncct, "idle");
400       nc_write(ncct, "\n", 1);
401       if(check->stats.current.status)
402         nc_printf(ncct, " recently: %s\n", check->stats.current.status);
403     }
404   }
405  out:
406   if(pobj) xmlXPathFreeObject(pobj);
407   return 0;
408 }
409 static int
410 noit_console_config_nocheck(noit_console_closure_t ncct,
411                             int argc, char **argv,
412                             noit_console_state_t *state, void *closure) {
413   int i, cnt;
414   const char *err = "internal error";
415   noit_conf_t_userdata_t *info;
416   xmlXPathObjectPtr pobj = NULL;
417   xmlXPathContextPtr xpath_ctxt = NULL;
418   char xpath[1024];
419   uuid_t checkid;
420
421   noit_conf_xml_xpath(NULL, &xpath_ctxt);
422   if(argc < 1) {
423     nc_printf(ncct, "requires one argument\n");
424     return -1;
425   }
426
427   info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
428   if(noit_console_mkcheck_xpath(xpath, sizeof(xpath), info, argv[0])) {
429     nc_printf(ncct, "could not find check '%s'\n", argv[0]);
430     return -1;
431   }
432   pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
433   if(!pobj || pobj->type != XPATH_NODESET ||
434      xmlXPathNodeSetIsEmpty(pobj->nodesetval)) {
435     err = "no checks found";
436     goto bad;
437   }
438   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
439   for(i=0; i<cnt; i++) {
440     xmlNodePtr node;
441     char *uuid_conf;
442     node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i);
443     uuid_conf = (char *)xmlGetProp(node, (xmlChar *)"uuid");
444     if(!uuid_conf || uuid_parse(uuid_conf, checkid)) {
445       nc_printf(ncct, "%s has invalid or missing UUID!\n",
446                 (char *)xmlGetNodePath(node) + strlen("/noit"));
447     }
448     else {
449       if(argc > 1) {
450         int j;
451         for(j=1;j<argc;j++)
452           xmlUnsetProp(node, (xmlChar *)argv[j]);
453       } else {
454         nc_printf(ncct, "descheduling %s\n", uuid_conf);
455         noit_poller_deschedule(checkid);
456         xmlUnlinkNode(node);
457       }
458     }
459   }
460   if(argc > 1) {
461     noit_poller_process_checks(xpath);
462     noit_poller_reload(xpath);
463   }
464   nc_printf(ncct, "rebuilding causal map...\n");
465   noit_poller_make_causal_map();
466   if(pobj) xmlXPathFreeObject(pobj);
467   return 0;
468  bad:
469   if(pobj) xmlXPathFreeObject(pobj);
470   nc_printf(ncct, "%s\n", err);
471   return -1;
472 }
473 static int
474 noit_console_state_conf_terminal(noit_console_closure_t ncct,
475                                  int argc, char **argv,
476                                  noit_console_state_t *state, void *closure) {
477   noit_conf_t_userdata_t *info;
478   if(argc) {
479     nc_printf(ncct, "extra arguments not expected.\n");
480     return -1;
481   }
482   info = calloc(1, sizeof(*info));
483   info->path = strdup("/");
484   noit_console_userdata_set(ncct, NOIT_CONF_T_USERDATA, info,
485                             conf_t_userdata_free);
486   noit_console_state_push_state(ncct, state);
487   noit_console_state_init(ncct);
488   return 0;
489 }
490 static int
491 noit_console_config_section(noit_console_closure_t ncct,
492                             int argc, char **argv,
493                             noit_console_state_t *state, void *closure) {
494   const char *err = "internal error";
495   char *path, xpath[1024];
496   noit_conf_t_userdata_t *info;
497   xmlXPathObjectPtr pobj = NULL;
498   xmlXPathContextPtr xpath_ctxt = NULL;
499   xmlNodePtr node = NULL, newnode;
500   vpsized_int delete = (vpsized_int)closure;
501
502   noit_conf_xml_xpath(NULL, &xpath_ctxt);
503   if(argc != 1) {
504     nc_printf(ncct, "requires one argument\n");
505     return -1;
506   }
507   if(strchr(argv[0], '/')) {
508     nc_printf(ncct, "invalid section name\n");
509     return -1;
510   }
511   if(!strcmp(argv[0], "check")) {
512     nc_printf(ncct, "use 'check' to create checks\n");
513     return -1;
514   }
515   if(!strcmp(argv[0], "config")) {
516     nc_printf(ncct, "use 'config' to set check config options\n");
517     return -1;
518   }
519   info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
520   if(!strcmp(info->path, "/")) {
521     nc_printf(ncct, "manipulation of toplevel section disallowed\n");
522     return -1;
523   }
524
525   if(delete) {
526     /* We cannot delete if we have checks */
527     snprintf(xpath, sizeof(xpath), "/noit%s/%s//check", info->path, argv[0]);
528     pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
529     if(!pobj || pobj->type != XPATH_NODESET ||
530        !xmlXPathNodeSetIsEmpty(pobj->nodesetval)) {
531       err = "cannot delete section, has checks";
532       goto bad;
533     }
534     if(pobj) xmlXPathFreeObject(pobj);
535   }
536
537   snprintf(xpath, sizeof(xpath), "/noit%s/%s", info->path, argv[0]);
538   pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
539   if(!pobj || pobj->type != XPATH_NODESET) {
540     err = "internal error: cannot detect section";
541     goto bad;
542   }
543   if(!delete && !xmlXPathNodeSetIsEmpty(pobj->nodesetval)) {
544     if(xmlXPathNodeSetGetLength(pobj->nodesetval) == 1) {
545       node = xmlXPathNodeSetItem(pobj->nodesetval, 0);
546       if(info->path) free(info->path);
547       info->path = strdup((char *)xmlGetNodePath(node) + strlen("/noit"));
548       goto cdout;
549     }
550     err = "cannot create section";
551     goto bad;
552   }
553   if(delete && xmlXPathNodeSetIsEmpty(pobj->nodesetval)) {
554     err = "no such section";
555     goto bad;
556   }
557   if(delete) {
558     node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0);
559     xmlUnlinkNode(node);
560     return 0;
561   }
562   if(pobj) xmlXPathFreeObject(pobj);
563
564   path = strcmp(info->path, "/") ? info->path : "";
565   snprintf(xpath, sizeof(xpath), "/noit%s", path);
566   pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
567   if(!pobj || pobj->type != XPATH_NODESET ||
568      xmlXPathNodeSetGetLength(pobj->nodesetval) != 1) {
569     err = "path invalid?";
570     goto bad;
571   }
572   node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0);
573   if((newnode = xmlNewChild(node, NULL, (xmlChar *)argv[0], NULL)) != NULL) {
574     if(info->path) free(info->path);
575     info->path = strdup((char *)xmlGetNodePath(newnode) + strlen("/noit"));
576   }
577   else {
578     err = "failed to create section";
579     goto bad;
580   }
581  cdout:
582   if(pobj) xmlXPathFreeObject(pobj);
583   return 0;
584  bad:
585   if(pobj) xmlXPathFreeObject(pobj);
586   nc_printf(ncct, "%s\n", err);
587   return -1;
588 }
589
590 static int
591 noit_console_config_cd(noit_console_closure_t ncct,
592                        int argc, char **argv,
593                        noit_console_state_t *state, void *closure) {
594   const char *err = "internal error";
595   char *path, xpath[1024];
596   noit_conf_t_userdata_t *info;
597   xmlXPathObjectPtr pobj = NULL;
598   xmlXPathContextPtr xpath_ctxt = NULL, current_ctxt;
599   xmlNodePtr node = NULL;
600   char *dest;
601
602   noit_conf_xml_xpath(NULL, &xpath_ctxt);
603   if(argc != 1 && !closure) {
604     nc_printf(ncct, "requires one argument\n");
605     return -1;
606   }
607   dest = argc ? argv[0] : (char *)closure;
608   info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
609   if(dest[0] == '/')
610     snprintf(xpath, sizeof(xpath), "/noit%s", dest);
611   else {
612     snprintf(xpath, sizeof(xpath), "/noit%s/%s", info->path, dest);
613   }
614   if(xpath[strlen(xpath)-1] == '/') xpath[strlen(xpath)-1] = '\0';
615
616   current_ctxt = xpath_ctxt;
617   pobj = xmlXPathEval((xmlChar *)xpath, current_ctxt);
618   if(!pobj || pobj->type != XPATH_NODESET ||
619      xmlXPathNodeSetIsEmpty(pobj->nodesetval)) {
620     err = "no such section";
621     goto bad;
622   }
623   if(xmlXPathNodeSetGetLength(pobj->nodesetval) > 1) {
624     err = "ambiguous section";
625     goto bad;
626   }
627
628   node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0);
629   if(!strcmp((char *)node->name, "check")) {
630     err = "can't cd into a check, use 'check' instead";
631     goto bad;
632   }
633   path = (char *)xmlGetNodePath(node);
634   if(strncmp(path, "/noit/", strlen("/noit/")) && strcmp(path, "/noit")) {
635     err = "new path outside out tree";
636     goto bad;
637   }
638   free(info->path);
639   if(!strcmp(path, "/noit"))
640     info->path = strdup("/");
641   else
642     info->path = strdup((char *)xmlGetNodePath(node) + strlen("/noit"));
643   if(pobj) xmlXPathFreeObject(pobj);
644   if(closure) noit_console_state_pop(ncct, argc, argv, NULL, NULL);
645   return 0;
646  bad:
647   if(pobj) xmlXPathFreeObject(pobj);
648   nc_printf(ncct, "%s [%s]\n", err, xpath);
649   return -1;
650 }
651 static int
652 noit_console_config_show(noit_console_closure_t ncct,
653                          int argc, char **argv,
654                          noit_console_state_t *state, void *closure) {
655   noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
656   const char *k;
657   int klen;
658   void *data;
659   int i, cnt, titled = 0, cliplen = 0;
660   const char *path = "", *basepath = NULL;
661   char xpath[1024];
662   noit_conf_t_userdata_t *info = NULL;
663   noit_hash_table *config;
664   xmlXPathObjectPtr pobj = NULL;
665   xmlXPathContextPtr xpath_ctxt = NULL, current_ctxt;
666   xmlDocPtr master_config = NULL;
667   xmlNodePtr node;
668
669   noit_conf_xml_xpath(&master_config, &xpath_ctxt);
670   if(argc > 1) {
671     nc_printf(ncct, "too many arguments\n");
672     return -1;
673   }
674
675   info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
676   if(info) path = basepath = info->path;
677   if(!info && argc == 0) {
678     nc_printf(ncct, "argument required when not in configuration mode\n");
679     return -1;
680   }
681
682   if(argc == 1) path = argv[0];
683   if(!basepath) basepath = path;
684
685   /* { / } is a special case */
686   if(!strcmp(basepath, "/")) basepath = "";
687   if(!strcmp(path, "/")) path = "";
688
689   if(!master_config) {
690     nc_printf(ncct, "no config\n");
691     return -1;
692   }
693
694   /* { / } is the only path that will end with a /
695    * in XPath { / / * } means something _entirely different than { / * }
696    * Ever notice how it is hard to describe xpath in C comments?
697    */
698   /* We don't want to show the root node */
699   cliplen = strlen("/noit/");
700
701   /* If we are in configuration mode
702    * and we are without an argument or the argument is absolute,
703    * clip the current path off */
704   if(info && (argc == 0 || path[0] != '/')) cliplen += strlen(basepath);
705   if(!path[0] || path[0] == '/') /* base only, or absolute path requested */
706     snprintf(xpath, sizeof(xpath), "/noit%s/@*", path);
707   else
708     snprintf(xpath, sizeof(xpath), "/noit%s/%s/@*", basepath, path);
709
710   current_ctxt = xpath_ctxt;
711   pobj = xmlXPathEval((xmlChar *)xpath, current_ctxt);
712   if(!pobj || pobj->type != XPATH_NODESET) {
713     nc_printf(ncct, "no such object\n");
714     goto bad;
715   }
716   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
717   titled = 0;
718   for(i=0; i<cnt; i++) {
719     node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i);
720     if(!strcmp((char *)node->name, "check")) continue;
721     if(node->children && node->children == xmlGetLastChild(node) &&
722       xmlNodeIsText(node->children)) {
723       if(!titled++) nc_printf(ncct, "== Section Settings ==\n");
724       nc_printf(ncct, "%s: %s\n", xmlGetNodePath(node) + cliplen,
725                 xmlXPathCastNodeToString(node->children));
726     }
727   }
728   xmlXPathFreeObject(pobj);
729
730   /* Print out all the config settings */
731   titled = 0;
732   config = noit_conf_get_hash(node, "config");
733   while(noit_hash_next(config, &iter, &k, &klen, &data)) {
734     if(!titled++) nc_printf(ncct, "== Section [Aggregated] Config ==\n");
735     nc_printf(ncct, "config::%s: %s\n", k, (const char *)data);
736   }
737   noit_hash_destroy(config, free, free);
738   free(config);
739
740   /* _shorten string_ turning last { / @ * } to { / * } */
741   strlcpy(xpath + strlen(xpath) - 2, "*", 2);
742   pobj = xmlXPathEval((xmlChar *)xpath, current_ctxt);
743   if(!pobj || pobj->type != XPATH_NODESET) {
744     nc_printf(ncct, "no such object\n");
745     goto bad;
746   }
747   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
748   titled = 0;
749   for(i=0; i<cnt; i++) {
750     node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i);
751     if(!strcmp((char *)node->name, "check")) continue;
752     if(!strcmp((char *)xmlGetNodePath(node) + cliplen, "config")) continue;
753     if(!(node->children && node->children == xmlGetLastChild(node) &&
754          xmlNodeIsText(node->children))) {
755       if(!titled++) nc_printf(ncct, "== Subsections ==\n");
756       nc_printf(ncct, "%s\n", xmlGetNodePath(node) + cliplen);
757     }
758   }
759
760   titled = 0;
761   for(i=0; i<cnt; i++) {
762     node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i);
763     if(!strcmp((char *)node->name, "check")) {
764       int busted = 1;
765       xmlAttr *attr;
766       char *uuid_str = "undefined";
767
768       if(!titled++) nc_printf(ncct, "== Checks ==\n");
769
770       for(attr=node->properties; attr; attr = attr->next) {
771         if(!strcmp((char *)attr->name, "uuid"))
772           uuid_str = (char *)xmlXPathCastNodeToString(attr->children);
773       }
774       if(uuid_str) {
775         uuid_t checkid;
776         nc_printf(ncct, "check[@uuid=\"%s\"] ", uuid_str);
777         if(uuid_parse(uuid_str, checkid) == 0) {
778           noit_check_t *check;
779           check = noit_poller_lookup(checkid);
780           if(check) {
781             busted = 0;
782             nc_printf(ncct, "%s`%s`%s", check->target, check->module, check->name);
783           }
784         }
785       }
786       else
787         nc_printf(ncct, "%s ", xmlGetNodePath(node) + cliplen);
788       if(busted) nc_printf(ncct, "[check not in running system]");
789       nc_write(ncct, "\n", 1);
790     }
791   }
792   xmlXPathFreeObject(pobj);
793   return 0;
794  bad:
795   if(pobj) xmlXPathFreeObject(pobj);
796   return -1;
797 }
798
799 static char *
800 conf_t_check_prompt(EditLine *el) {
801   noit_console_closure_t ncct;
802   noit_conf_t_userdata_t *info;
803   noit_check_t *check;
804   static char *tl = "noit(conf)# ";
805   static char *pfmt = "noit(conf:%s%s%s)# ";
806
807   el_get(el, EL_USERDATA, (void *)&ncct);
808   if(!ncct) return tl;
809   info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
810   if(!info) return tl;
811
812   check = noit_poller_lookup(info->current_check);
813   if(check &&
814      check->target && check->target[0] &&
815      check->name && check->name[0])
816     snprintf(info->prompt, sizeof(info->prompt),
817              pfmt, check->target, "`", check->name);
818   else {
819     char uuid_str[37];
820     uuid_unparse_lower(info->current_check, uuid_str);
821     snprintf(info->prompt, sizeof(info->prompt), pfmt, "[", uuid_str, "]");
822   }
823   return info->prompt;
824 }
825 static char *
826 conf_t_prompt(EditLine *el) {
827   noit_console_closure_t ncct;
828   noit_conf_t_userdata_t *info;
829   static char *tl = "noit(conf)# ";
830   static char *pfmt = "noit(conf:%s%s)# ";
831   int path_len, max_len;
832
833   el_get(el, EL_USERDATA, (void *)&ncct);
834   if(!ncct) return tl;
835   info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
836   if(!info) return tl;
837
838   path_len = strlen(info->path);
839   max_len = sizeof(info->prompt) - (strlen(pfmt) - 4 /* %s%s */) - 1 /* \0 */;
840   if(path_len > max_len)
841     snprintf(info->prompt, sizeof(info->prompt),
842              pfmt, "...", info->path + path_len - max_len + 3 /* ... */);
843   else
844     snprintf(info->prompt, sizeof(info->prompt), pfmt, "", info->path);
845   return info->prompt;
846 }
847 static int
848 noit_conf_checks_reload(noit_console_closure_t ncct,
849                         int argc, char **argv,
850                         noit_console_state_t *state, void *closure) {
851   if(noit_conf_reload(ncct, argc, argv, state, closure)) return -1;
852   noit_poller_reload(NULL);
853   return 0;
854 }
855
856 static int
857 validate_attr_set_scope(noit_conf_t_userdata_t *info,
858                         struct _valid_attr_t *attrinfo) {
859   int len;
860   len = strlen(attrinfo->scope);
861   if(strncmp(info->path, attrinfo->scope, len) ||
862      (info->path[len] != '\0' && info->path[len] != '/')) {
863     return -1;
864   }
865   return 0;
866 }
867 static int
868 replace_config(noit_console_closure_t ncct,
869                noit_conf_t_userdata_t *info, const char *name,
870                const char *value) {
871   int i, cnt, rv = -1, active = 0;
872   xmlXPathObjectPtr pobj = NULL;
873   xmlXPathContextPtr xpath_ctxt = NULL;
874   xmlNodePtr node, confignode;
875   char xpath[1024], *path;
876
877   path = info->path;
878   if(!strcmp(path, "/")) path = "";
879
880   noit_conf_xml_xpath(NULL, &xpath_ctxt);
881
882   /* Only if checks will fixate this attribute shall we check for
883    * child <check> nodes.
884    * NOTE: this return nothing and "seems" okay if we are _in_
885    *       a <check> node.  That case is handled below.
886    */
887   snprintf(xpath, sizeof(xpath), "/noit/%s//check[@uuid]", path);
888   pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
889   if(!pobj || pobj->type != XPATH_NODESET) goto out;
890   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
891   for(i=0; i<cnt; i++) {
892     uuid_t checkid;
893     node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i);
894     if(noit_conf_get_uuid(node, "@uuid", checkid)) {
895       noit_check_t *check;
896       check = noit_poller_lookup(checkid);
897       if(NOIT_CHECK_LIVE(check)) active++;
898     }
899   }
900   if(pobj) xmlXPathFreeObject(pobj);
901
902   snprintf(xpath, sizeof(xpath), "/noit/%s", path);
903   pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
904   if(!pobj || pobj->type != XPATH_NODESET) goto out;
905   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
906   if(cnt != 1) {
907     nc_printf(ncct, "Internal error: context node disappeared\n");
908     goto out;
909   }
910   node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0);
911   if(strcmp((const char *)node->name, "check")) {
912     uuid_t checkid;
913     /* Detect if  we are actually a <check> node and attempting to
914      * change something we shouldn't.
915      * This is the counterpart noted above.
916      */
917     if(noit_conf_get_uuid(node, "@uuid", checkid)) {
918       noit_check_t *check;
919       check = noit_poller_lookup(checkid);
920       if(NOIT_CHECK_LIVE(check)) active++;
921     }
922   }
923 #ifdef UNSAFE_RECONFIG
924   if(active) {
925     nc_printf(ncct, "Cannot set '%s', it would effect %d live check(s)\n",
926               name, active);
927     goto out;
928   }
929 #endif
930   if(pobj) xmlXPathFreeObject(pobj);
931
932   /* Here we want to remove /noit/path/config/name */
933   snprintf(xpath, sizeof(xpath), "/noit/%s/config/%s", path, name);
934   pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
935   if(!pobj || pobj->type != XPATH_NODESET) goto out;
936   if(xmlXPathNodeSetGetLength(pobj->nodesetval) > 0) {
937     xmlNodePtr toremove;
938     toremove = xmlXPathNodeSetItem(pobj->nodesetval, 0);
939     xmlUnlinkNode(toremove);
940   }
941   /* TODO: if there are no more children of config, remove config? */
942   if(value) {
943     if(pobj) xmlXPathFreeObject(pobj);
944     /* He we create config if needed and place a child node under it */
945     snprintf(xpath, sizeof(xpath), "/noit/%s/config", path);
946     pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
947     if(!pobj || pobj->type != XPATH_NODESET) goto out;
948     if(xmlXPathNodeSetGetLength(pobj->nodesetval) == 0) {
949       if(pobj) xmlXPathFreeObject(pobj);
950       snprintf(xpath, sizeof(xpath), "/noit/%s", path);
951       pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
952       if(!pobj || pobj->type != XPATH_NODESET) goto out;
953       if(xmlXPathNodeSetGetLength(pobj->nodesetval) != 1) {
954         nc_printf(ncct, "Node disappeared from under you!\n");
955         goto out;
956       }
957       confignode = xmlNewChild(xmlXPathNodeSetItem(pobj->nodesetval, 0),
958                                NULL, (xmlChar *)"config", NULL);
959       if(confignode == NULL) {
960         nc_printf(ncct, "Error creating config child node.\n");
961         goto out;
962       }
963     }
964     else confignode = xmlXPathNodeSetItem(pobj->nodesetval, 0);
965
966     assert(confignode);
967     /* Now we create a child */
968     xmlNewChild(confignode, NULL, (xmlChar *)name, (xmlChar *)value);
969    
970   }
971   rv = 0;
972  out:
973   if(pobj) xmlXPathFreeObject(pobj);
974   return rv;
975 }
976 static int
977 replace_attr(noit_console_closure_t ncct,
978              noit_conf_t_userdata_t *info, struct _valid_attr_t *attrinfo,
979              const char *value) {
980   int i, cnt, rv = -1, active = 0;
981   xmlXPathObjectPtr pobj = NULL;
982   xmlXPathContextPtr xpath_ctxt = NULL;
983   xmlNodePtr node;
984   char xpath[1024], *path;
985
986   path = info->path;
987   if(!strcmp(path, "/")) path = "";
988
989   noit_conf_xml_xpath(NULL, &xpath_ctxt);
990   if(attrinfo->checks_fixate) {
991     /* Only if checks will fixate this attribute shall we check for
992      * child <check> nodes.
993      * NOTE: this return nothing and "seems" okay if we are _in_
994      *       a <check> node.  That case is handled below.
995      */
996     snprintf(xpath, sizeof(xpath), "/noit/%s//check[@uuid]", path);
997     pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
998     if(!pobj || pobj->type != XPATH_NODESET) goto out;
999     cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
1000     for(i=0; i<cnt; i++) {
1001       uuid_t checkid;
1002       node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i);
1003       if(noit_conf_get_uuid(node, "@uuid", checkid)) {
1004         noit_check_t *check;
1005         check = noit_poller_lookup(checkid);
1006         if(NOIT_CHECK_LIVE(check)) active++;
1007       }
1008     }
1009     if(pobj) xmlXPathFreeObject(pobj);
1010   }
1011   snprintf(xpath, sizeof(xpath), "/noit/%s", path);
1012   pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
1013   if(!pobj || pobj->type != XPATH_NODESET) goto out;
1014   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
1015   if(cnt != 1) {
1016     nc_printf(ncct, "Internal error: context node disappeared\n");
1017     goto out;
1018   }
1019   node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0);
1020   if(attrinfo->checks_fixate &&
1021      !strcmp((const char *)node->name, "check")) {
1022     uuid_t checkid;
1023     /* Detect if  we are actually a <check> node and attempting to
1024      * change something we shouldn't.
1025      * This is the counterpart noted above.
1026      */
1027     if(noit_conf_get_uuid(node, "@uuid", checkid)) {
1028       noit_check_t *check;
1029       check = noit_poller_lookup(checkid);
1030       if(NOIT_CHECK_LIVE(check)) active++;
1031     }
1032   }
1033   if(active) {
1034     nc_printf(ncct, "Cannot set '%s', it would effect %d live check(s)\n",
1035               attrinfo->name, active);
1036     goto out;
1037   }
1038   xmlUnsetProp(node, (xmlChar *)attrinfo->name);
1039   if(value)
1040     xmlSetProp(node, (xmlChar *)attrinfo->name, (xmlChar *)value);
1041   rv = 0;
1042  out:
1043   if(pobj) xmlXPathFreeObject(pobj);
1044   return rv;
1045 }
1046 int
1047 noit_conf_check_set_attr(noit_console_closure_t ncct,
1048                          int argc, char **argv,
1049                          noit_console_state_t *state, void *closure) {
1050   struct _valid_attr_t *attrinfo = closure;
1051   noit_conf_t_userdata_t *info;
1052
1053   info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
1054   if(!info || validate_attr_set_scope(info, attrinfo)) {
1055     nc_printf(ncct, "'%s' attribute only valid in %s scope\n",
1056               attrinfo->name, attrinfo->scope);
1057     return -1;
1058   }
1059
1060   if(argc != 1) {
1061     nc_printf(ncct, "set requires exactly one value\n");
1062     return -1;
1063   }
1064   /* Okay, we have an attribute and it should be set/replaced on the
1065    * current path.
1066    */
1067   if(replace_attr(ncct, info, attrinfo, argv[0])) {
1068     return -1;
1069   }
1070
1071   /* So, we updated an attribute, so we need to reload all checks
1072    * that are descendent-or-self of this node.
1073    */
1074   refresh_subchecks(ncct, info);
1075   return 0;
1076 }
1077
1078 int
1079 noit_conf_check_unset_attr(noit_console_closure_t ncct,
1080                            int argc, char **argv,
1081                            noit_console_state_t *state, void *closure) {
1082   struct _valid_attr_t *attrinfo = closure;
1083   noit_conf_t_userdata_t *info;
1084
1085   info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
1086   if(!info || validate_attr_set_scope(info, attrinfo)) {
1087     nc_printf(ncct, "'%s' attribute only valid in %s scope\n",
1088               attrinfo->name, attrinfo->scope);
1089     return -1;
1090   }
1091
1092   if(argc != 0) {
1093     nc_printf(ncct, "no arguments allowed to this command.\n");
1094     return -1;
1095   }
1096   /* Okay, we have an attribute and it should be set/replaced on the
1097    * current path.
1098    */
1099   if(replace_attr(ncct, info, attrinfo, NULL)) {
1100     return -1;
1101   }
1102
1103   /* So, we updated an attribute, so we need to reload all checks
1104    * that are descendent-or-self of this node.
1105    */
1106   refresh_subchecks(ncct, info);
1107   return 0;
1108 }
1109
1110 int
1111 noit_console_config_setconfig(noit_console_closure_t ncct,
1112                                 int argc, char **argv,
1113                                 noit_console_state_t *state, void *closure) {
1114   noit_conf_t_userdata_t *info;
1115
1116   info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
1117
1118   if(argc != 2) {
1119     nc_printf(ncct, "two arguments required.\n");
1120     return -1;
1121   }
1122   /* Okay, we have an child name and it should be culled from
1123    * current path/config.
1124    */
1125   if(replace_config(ncct, info, argv[0], argv[1])) {
1126     return -1;
1127   }
1128
1129   /* So, we updated an attribute, so we need to reload all checks
1130    * that are descendent-or-self of this node.
1131    */
1132   refresh_subchecks(ncct, info);
1133   return 0;
1134 }
1135
1136 int
1137 noit_console_config_unsetconfig(noit_console_closure_t ncct,
1138                                 int argc, char **argv,
1139                                 noit_console_state_t *state, void *closure) {
1140   noit_conf_t_userdata_t *info;
1141
1142   info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
1143
1144   if(argc != 1) {
1145     nc_printf(ncct, "one argument required.\n");
1146     return -1;
1147   }
1148   /* Okay, we have an child name and it should be culled from
1149    * current path/config.
1150    */
1151   if(replace_config(ncct, info, argv[0], NULL)) {
1152     return -1;
1153   }
1154
1155   /* So, we updated an attribute, so we need to reload all checks
1156    * that are descendent-or-self of this node.
1157    */
1158   refresh_subchecks(ncct, info);
1159   return 0;
1160 }
1161
1162
1163 #define NEW_STATE(a) (a) = noit_console_state_alloc()
1164 #define ADD_CMD(a,cmd,func,ss,c) \
1165   noit_console_state_add_cmd((a), \
1166     NCSCMD(cmd, func, ss, c))
1167 #define DELEGATE_CMD(a,cmd,ss) \
1168   noit_console_state_add_cmd((a), \
1169     NCSCMD(cmd, noit_console_state_delegate, ss, NULL))
1170
1171 static
1172 void register_console_config_commands() {
1173   cmd_info_t *showcmd;
1174   noit_console_state_t *tl, *_conf_state, *_conf_t_state,
1175                        *_conf_t_check_state,
1176                        *_write_state, *_attr_state,
1177                        *_unset_state, *_uattr_state;
1178
1179   tl = noit_console_state_initial();
1180
1181   /* write <terimal|memory|file> */
1182   NEW_STATE(_write_state);
1183   ADD_CMD(_write_state, "terminal", noit_conf_write_terminal, NULL, NULL);
1184   ADD_CMD(_write_state, "file", noit_conf_write_file, NULL, NULL);
1185   /* write memory?  It's to a file, but I like router syntax */
1186   ADD_CMD(_write_state, "memory", noit_conf_write_file, NULL, NULL);
1187
1188   /* attribute <attrname> <value> */
1189   NEW_STATE(_attr_state);
1190   noit_console_state_add_check_attrs(_attr_state, noit_conf_check_set_attr);
1191  
1192   /* no attribute <attrname> <value> */
1193   NEW_STATE(_uattr_state);
1194   noit_console_state_add_check_attrs(_uattr_state, noit_conf_check_unset_attr);
1195
1196   NEW_STATE(_unset_state);
1197   DELEGATE_CMD(_unset_state, "attribute", _uattr_state);
1198   ADD_CMD(_unset_state, "section", noit_console_config_section, NULL, (void *)1);
1199   ADD_CMD(_unset_state, "config", noit_console_config_unsetconfig, NULL, NULL);
1200   ADD_CMD(_unset_state, "check", noit_console_config_nocheck, NULL, NULL);
1201  
1202   NEW_STATE(_conf_t_check_state);
1203   _conf_t_check_state->console_prompt_function = conf_t_check_prompt;
1204   DELEGATE_CMD(_conf_t_check_state, "attribute", _attr_state);
1205   DELEGATE_CMD(_conf_t_check_state, "no", _unset_state);
1206   ADD_CMD(_conf_t_check_state, "config", noit_console_config_setconfig, NULL, NULL);
1207   ADD_CMD(_conf_t_check_state, "status", noit_console_show_check, NULL, NULL);
1208   ADD_CMD(_conf_t_check_state, "exit", noit_console_config_cd, NULL, "..");
1209   ADD_CMD(_conf_t_check_state, "check", noit_console_check, _conf_t_check_state, "..");
1210
1211   NEW_STATE(_conf_t_state);
1212   _conf_t_state->console_prompt_function = conf_t_prompt;
1213   noit_console_state_add_cmd(_conf_t_state, &console_command_exit);
1214   ADD_CMD(_conf_t_state, "ls", noit_console_config_show, NULL, NULL);
1215   ADD_CMD(_conf_t_state, "cd", noit_console_config_cd, NULL, NULL);
1216   ADD_CMD(_conf_t_state, "config", noit_console_config_setconfig, NULL, NULL);
1217   ADD_CMD(_conf_t_state, "section", noit_console_config_section, NULL, (void *)0);
1218   ADD_CMD(_conf_t_state, "check", noit_console_check, _conf_t_check_state, NULL);
1219
1220   showcmd = noit_console_state_get_cmd(tl, "show");
1221   ADD_CMD(showcmd->dstate, "check", noit_console_show_check, NULL, NULL);
1222
1223   DELEGATE_CMD(_conf_t_state, "write", _write_state);
1224   DELEGATE_CMD(_conf_t_state, "attribute", _attr_state);
1225   DELEGATE_CMD(_conf_t_state, "no", _unset_state);
1226
1227   NEW_STATE(_conf_state);
1228   ADD_CMD(_conf_state, "terminal", noit_console_state_conf_terminal, _conf_t_state, NULL);
1229
1230   ADD_CMD(tl, "configure", noit_console_state_delegate, _conf_state, NULL);
1231   ADD_CMD(tl, "write", noit_console_state_delegate, _write_state, NULL);
1232   ADD_CMD(tl, "reload", noit_conf_checks_reload, NULL, NULL);
1233 }
1234
Note: See TracBrowser for help on using the browser.