root/src/noit_conf_checks.c

Revision 022178b72fc213634c638c89545331c05680d374, 40.6 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 3 years ago)

add 'attr resolve_rtype' into the cli console

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