root/src/noit_conf_checks.c

Revision 30b3841abad7acbfffab04c3f0829809791566df, 40.5 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 3 years ago)

This makes the telnet console output for checks
present the metrics in a alphabetical ordering.
Long-standing annoyance fixed.

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