root/src/noit_conf_checks.c

Revision 8e9cf57ebf8fd9d4375a893d47cef1aaecce0662, 40.7 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 3 years ago)

on-disk backing store implementation

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