root/src/noit_conf_checks.c

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

refs #340

This is a rather major change. Targets can now be hostnames in addition
to IP addresses so long as //checks/@resolve_targets is not false.

If a target is entered that does not look like an IP (inet_pton fails)
then the check is marked as needing resolution NP_RESOLVE.

A passive look-aside dns cache has been implemented in noit_check_resolver.c
that is used to power the whole system and some reasonably simply console
command have been provided:

show dns_cache [fqdn1 [fqdn2]] -- shows the state
dns_cache <fqdn> [fqdn2 [fqdn3]] -- submits for lookup
no dns_cache <fqdn> [fqdn2 [fqdn3]] -- purges from cache

The big change is that modules that relied on check->target to be an IP
address are going to explode when names are provided. Instead, modules
should now use target for the provided target (possibly a FQDN) and use
target_ip (check->target_ip or check.target_ip) for a resolved IP address
and also check for the case of empty string: (check->target_ip[0] == '\0')
for the case that resolution has failed. In lua, the target_ip will be
presented as nil in the case of failed name resolution.

I believe I've updated all necessary components of the system for this to
"just work" but people that have implemented their own check should update
them before they elect to use non-IP addresses as targets.

The dns subsystem supports both IPv4 and IPv6, but currently prefers IPv4
addresses if any are present.

  • 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 noit_console_show_check(noit_console_closure_t ncct,
387                         int argc, char **argv,
388                         noit_console_state_t *state, void *closure) {
389   int i, cnt;
390   noit_conf_t_userdata_t *info;
391   char xpath[1024];
392   xmlXPathObjectPtr pobj = NULL;
393   xmlXPathContextPtr xpath_ctxt = NULL;
394
395   noit_conf_xml_xpath(NULL, &xpath_ctxt);
396   if(argc > 1) {
397     nc_printf(ncct, "requires zero or one arguments\n");
398     return -1;
399   }
400
401   info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
402   /* We many not be in conf-t mode -- that's fine */
403   if(noit_console_mkcheck_xpath(xpath, sizeof(xpath), info,
404                                 argc ? argv[0] : NULL)) {
405     nc_printf(ncct, "could not find check '%s'\n", argv[0]);
406     return -1;
407   }
408
409   pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
410   if(!pobj || pobj->type != XPATH_NODESET ||
411      xmlXPathNodeSetIsEmpty(pobj->nodesetval)) {
412     nc_printf(ncct, "no checks found\n");
413     goto out;
414   }
415   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
416   if(info && cnt != 1) {
417     nc_printf(ncct, "Ambiguous check specified\n");
418     goto out;
419   }
420   for(i=0; i<cnt; i++) {
421     noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
422     const char *k;
423     int klen;
424     void *data;
425     uuid_t checkid;
426     noit_check_t *check;
427     noit_hash_table *config;
428     xmlNodePtr node, anode, mnode = NULL;
429     char *uuid_conf;
430     char *module, *value;
431
432     node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i);
433     uuid_conf = (char *)xmlGetProp(node, (xmlChar *)"uuid");
434     if(!uuid_conf || uuid_parse(uuid_conf, checkid)) {
435       nc_printf(ncct, "%s has invalid or missing UUID!\n",
436                 (char *)xmlGetNodePath(node) + strlen("/noit"));
437       continue;
438     }
439     nc_printf(ncct, "==== %s ====\n", uuid_conf);
440
441 #define MYATTR(a,n,b) _noit_conf_get_string(node, &(n), "@" #a, &(b))
442 #define INHERIT(a,n,b) \
443   _noit_conf_get_string(node, &(n), "ancestor-or-self::node()/@" #a, &(b))
444 #define SHOW_ATTR(a) do { \
445   anode = NULL; \
446   value = NULL; \
447   INHERIT(a, anode, value); \
448   nc_attr_show(ncct, #a, node, anode, value); \
449 } while(0)
450
451     if(!INHERIT(module, mnode, module)) module = NULL;
452     if(MYATTR(name, anode, value))
453       nc_printf(ncct, " name: %s\n", value);
454     else
455       nc_printf(ncct, " name: %s [from module]\n", module ? module : "[undef]");
456     nc_attr_show(ncct, "module", node, mnode, module);
457     SHOW_ATTR(target);
458     SHOW_ATTR(period);
459     SHOW_ATTR(timeout);
460     SHOW_ATTR(oncheck);
461     SHOW_ATTR(filterset);
462     SHOW_ATTR(disable);
463     /* Print out all the config settings */
464     config = noit_conf_get_hash(node, "config");
465     while(noit_hash_next(config, &iter, &k, &klen, &data)) {
466       nc_printf(ncct, " config::%s: %s\n", k, (const char *)data);
467     }
468     noit_hash_destroy(config, free, free);
469     free(config);
470
471     check = noit_poller_lookup(checkid);
472     if(!check) {
473       nc_printf(ncct, " ERROR: not in running system\n");
474     }
475     else {
476       int idx = 0;
477       nc_printf(ncct, " target_ip: %s\n", check->target_ip);
478       nc_printf(ncct, " currently: ");
479       if(NOIT_CHECK_RUNNING(check)) nc_printf(ncct, "%srunning", idx++?",":"");
480       if(NOIT_CHECK_KILLED(check)) nc_printf(ncct, "%skilled", idx++?",":"");
481       if(!NOIT_CHECK_CONFIGURED(check)) nc_printf(ncct, "%sunconfig", idx++?",":"");
482       if(NOIT_CHECK_DISABLED(check)) nc_printf(ncct, "%sdisabled", idx++?",":"");
483       if(!idx) nc_printf(ncct, "idle");
484       nc_write(ncct, "\n", 1);
485       if(check->stats.current.whence.tv_sec == 0) {
486         nc_printf(ncct, " last run: never\n");
487       }
488       else {
489         stats_t *c = &check->stats.current;
490         struct timeval now, diff;
491         gettimeofday(&now, NULL);
492         sub_timeval(now, c->whence, &diff);
493         nc_printf(ncct, " last run: %0.3f seconds ago\n",
494                   diff.tv_sec + (diff.tv_usec / 1000000.0));
495         nc_printf(ncct, " availability/state: %s/%s\n",
496                   noit_check_available_string(c->available),
497                   noit_check_state_string(c->state));
498         nc_printf(ncct, " status: %s\n", c->status ? c->status : "[[null]]");
499         nc_printf(ncct, " metrics:\n");
500         memset(&iter, 0, sizeof(iter));
501         while(noit_hash_next(&c->metrics, &iter, &k, &klen, &data)) {
502           char buff[256];
503           noit_boolean filtered;
504           noit_stats_snprint_metric(buff, sizeof(buff), (metric_t *)data);
505           filtered = !noit_apply_filterset(check->filterset, check, (metric_t *)data);
506           nc_printf(ncct, "  %c%s\n", filtered ? '*' : ' ', buff);
507         }
508       }
509     }
510   }
511  out:
512   if(pobj) xmlXPathFreeObject(pobj);
513   return 0;
514 }
515 static int
516 noit_console_config_nocheck(noit_console_closure_t ncct,
517                             int argc, char **argv,
518                             noit_console_state_t *state, void *closure) {
519   int i, cnt;
520   const char *err = "internal error";
521   noit_conf_t_userdata_t *info;
522   xmlXPathObjectPtr pobj = NULL;
523   xmlXPathContextPtr xpath_ctxt = NULL;
524   char xpath[1024];
525   uuid_t checkid;
526
527   noit_conf_xml_xpath(NULL, &xpath_ctxt);
528   if(argc < 1) {
529     nc_printf(ncct, "requires one argument\n");
530     return -1;
531   }
532
533   info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
534   if(noit_console_mkcheck_xpath(xpath, sizeof(xpath), info, argv[0])) {
535     nc_printf(ncct, "could not find check '%s'\n", argv[0]);
536     return -1;
537   }
538   pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
539   if(!pobj || pobj->type != XPATH_NODESET ||
540      xmlXPathNodeSetIsEmpty(pobj->nodesetval)) {
541     err = "no checks found";
542     goto bad;
543   }
544   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
545   for(i=0; i<cnt; i++) {
546     xmlNodePtr node;
547     char *uuid_conf;
548     node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i);
549     uuid_conf = (char *)xmlGetProp(node, (xmlChar *)"uuid");
550     if(!uuid_conf || uuid_parse(uuid_conf, checkid)) {
551       nc_printf(ncct, "%s has invalid or missing UUID!\n",
552                 (char *)xmlGetNodePath(node) + strlen("/noit"));
553     }
554     else {
555       if(argc > 1) {
556         int j;
557         for(j=1;j<argc;j++)
558           xmlUnsetProp(node, (xmlChar *)argv[j]);
559       } else {
560         nc_printf(ncct, "descheduling %s\n", uuid_conf);
561         noit_poller_deschedule(checkid);
562         xmlUnlinkNode(node);
563       }
564       noit_conf_mark_changed();
565     }
566   }
567   if(argc > 1) {
568     noit_poller_process_checks(xpath);
569     noit_poller_reload(xpath);
570   }
571   nc_printf(ncct, "rebuilding causal map...\n");
572   noit_poller_make_causal_map();
573   if(pobj) xmlXPathFreeObject(pobj);
574   return 0;
575  bad:
576   if(pobj) xmlXPathFreeObject(pobj);
577   nc_printf(ncct, "%s\n", err);
578   return -1;
579 }
580 static int
581 noit_console_config_show(noit_console_closure_t ncct,
582                          int argc, char **argv,
583                          noit_console_state_t *state, void *closure) {
584   noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
585   const char *k;
586   int klen;
587   void *data;
588   int i, cnt, titled = 0, cliplen = 0;
589   const char *path = "", *basepath = NULL;
590   char xpath[1024];
591   noit_conf_t_userdata_t *info = NULL;
592   noit_hash_table *config;
593   xmlXPathObjectPtr pobj = NULL;
594   xmlXPathContextPtr xpath_ctxt = NULL, current_ctxt;
595   xmlDocPtr master_config = NULL;
596   xmlNodePtr node = NULL;
597
598   noit_conf_xml_xpath(&master_config, &xpath_ctxt);
599   if(argc > 1) {
600     nc_printf(ncct, "too many arguments\n");
601     return -1;
602   }
603
604   info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
605   if(info && info->path) path = basepath = info->path;
606   if(!info && argc == 0) {
607     nc_printf(ncct, "argument required when not in configuration mode\n");
608     return -1;
609   }
610
611   if(argc == 1) path = argv[0];
612   if(!basepath) basepath = path;
613
614   /* { / } is a special case */
615   if(!strcmp(basepath, "/")) basepath = "";
616   if(!strcmp(path, "/")) path = "";
617
618   if(!master_config) {
619     nc_printf(ncct, "no config\n");
620     return -1;
621   }
622
623   /* { / } is the only path that will end with a /
624    * in XPath { / / * } means something _entirely different than { / * }
625    * Ever notice how it is hard to describe xpath in C comments?
626    */
627   /* We don't want to show the root node */
628   cliplen = strlen("/noit/");
629
630   /* If we are in configuration mode
631    * and we are without an argument or the argument is absolute,
632    * clip the current path off */
633   if(info && (argc == 0 || path[0] != '/')) cliplen += strlen(basepath);
634   if(!path[0] || path[0] == '/') /* base only, or absolute path requested */
635     snprintf(xpath, sizeof(xpath), "/noit%s/@*", path);
636   else
637     snprintf(xpath, sizeof(xpath), "/noit%s/%s/@*", basepath, path);
638
639   current_ctxt = xpath_ctxt;
640   pobj = xmlXPathEval((xmlChar *)xpath, current_ctxt);
641   if(!pobj || pobj->type != XPATH_NODESET) {
642     nc_printf(ncct, "no such object\n");
643     goto bad;
644   }
645   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
646   titled = 0;
647   for(i=0; i<cnt; i++) {
648     node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i);
649     if(!strcmp((char *)node->name, "check")) continue;
650     if(node->children && node->children == xmlGetLastChild(node) &&
651       xmlNodeIsText(node->children)) {
652       if(!titled++) nc_printf(ncct, "== Section Settings ==\n");
653       nc_printf(ncct, "%s: %s\n", xmlGetNodePath(node) + cliplen,
654                 xmlXPathCastNodeToString(node->children));
655     }
656   }
657   xmlXPathFreeObject(pobj);
658
659   /* Print out all the config settings */
660   if(!path[0] || path[0] == '/') /* base only, or absolute path requested */
661     snprintf(xpath, sizeof(xpath), "/noit%s", path);
662   else
663     snprintf(xpath, sizeof(xpath), "/noit%s/%s", basepath, path);
664   pobj = xmlXPathEval((xmlChar *)xpath, current_ctxt);
665   if(!pobj || pobj->type != XPATH_NODESET) {
666     nc_printf(ncct, "no such object\n");
667     goto bad;
668   }
669   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
670   if(cnt > 0) {
671     node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0);
672     titled = 0;
673     config = noit_conf_get_hash(node, "config");
674     while(noit_hash_next(config, &iter, &k, &klen, &data)) {
675       if(!titled++) nc_printf(ncct, "== Section [Aggregated] Config ==\n");
676       nc_printf(ncct, "config::%s: %s\n", k, (const char *)data);
677     }
678     noit_hash_destroy(config, free, free);
679     free(config);
680   }
681   xmlXPathFreeObject(pobj);
682
683   /* _shorten string_ turning last { / @ * } to { / * } */
684   if(!path[0] || path[0] == '/') /* base only, or absolute path requested */
685     snprintf(xpath, sizeof(xpath), "/noit%s/*", path);
686   else
687     snprintf(xpath, sizeof(xpath), "/noit%s/%s/*", basepath, path);
688   pobj = xmlXPathEval((xmlChar *)xpath, current_ctxt);
689   if(!pobj || pobj->type != XPATH_NODESET) {
690     nc_printf(ncct, "no such object\n");
691     goto bad;
692   }
693   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
694   titled = 0;
695   for(i=0; i<cnt; i++) {
696     node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i);
697     if(!strcmp((char *)node->name, "check")) continue;
698     if(!strcmp((char *)node->name, "filterset")) continue;
699     if(!strcmp((char *)xmlGetNodePath(node) + cliplen, "config")) continue;
700     if(!(node->children && node->children == xmlGetLastChild(node) &&
701          xmlNodeIsText(node->children))) {
702       if(!titled++) nc_printf(ncct, "== Subsections ==\n");
703       nc_printf(ncct, "%s\n", xmlGetNodePath(node) + cliplen);
704     }
705   }
706
707   titled = 0;
708   for(i=0; i<cnt; i++) {
709     node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i);
710     if(!strcmp((char *)node->name, "filterset")) {
711       xmlAttr *attr;
712       char *filter_name = NULL;
713       for(attr=node->properties; attr; attr = attr->next) {
714         if(!strcmp((char *)attr->name, "name"))
715           filter_name = (char *)xmlXPathCastNodeToString(attr->children);
716       }
717       if(filter_name) {
718         nc_printf(ncct, "filterset[@name=\"%s\"]\n", filter_name);
719         xmlFree(filter_name);
720       }
721       else nc_printf(ncct, "fitlerset\n");
722     }
723     else if(!strcmp((char *)node->name, "check")) {
724       int busted = 1;
725       xmlAttr *attr;
726       char *uuid_str = "undefined";
727
728       if(!titled++) nc_printf(ncct, "== Checks ==\n");
729
730       for(attr=node->properties; attr; attr = attr->next) {
731         if(!strcmp((char *)attr->name, "uuid"))
732           uuid_str = (char *)xmlXPathCastNodeToString(attr->children);
733       }
734       if(uuid_str) {
735         uuid_t checkid;
736         nc_printf(ncct, "check[@uuid=\"%s\"] ", uuid_str);
737         if(uuid_parse(uuid_str, checkid) == 0) {
738           noit_check_t *check;
739           check = noit_poller_lookup(checkid);
740           if(check) {
741             busted = 0;
742             nc_printf(ncct, "%s`%s`%s", check->target, check->module, check->name);
743           }
744         }
745       }
746       else
747         nc_printf(ncct, "%s ", xmlGetNodePath(node) + cliplen);
748       if(busted) nc_printf(ncct, "[check not in running system]");
749       nc_write(ncct, "\n", 1);
750     }
751   }
752   xmlXPathFreeObject(pobj);
753   return 0;
754  bad:
755   if(pobj) xmlXPathFreeObject(pobj);
756   return -1;
757 }
758
759 static char *
760 conf_t_check_prompt(EditLine *el) {
761   noit_console_closure_t ncct;
762   noit_conf_t_userdata_t *info;
763   noit_check_t *check;
764   static char *tl = "noit(conf)# ";
765   static char *pfmt = "noit(conf:%s%s%s)# ";
766
767   el_get(el, EL_USERDATA, (void *)&ncct);
768   if(!ncct) return tl;
769   info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
770   if(!info) return tl;
771
772   check = noit_poller_lookup(info->current_check);
773   if(check &&
774      check->target && check->target[0] &&
775      check->name && check->name[0])
776     snprintf(info->prompt, sizeof(info->prompt),
777              pfmt, check->target, "`", check->name);
778   else {
779     char uuid_str[37];
780     uuid_unparse_lower(info->current_check, uuid_str);
781     snprintf(info->prompt, sizeof(info->prompt), pfmt, "[", uuid_str, "]");
782   }
783   return info->prompt;
784 }
785 static int
786 noit_conf_checks_reload(noit_console_closure_t ncct,
787                         int argc, char **argv,
788                         noit_console_state_t *state, void *closure) {
789   if(noit_conf_reload(ncct, argc, argv, state, closure)) return -1;
790   noit_poller_reload(NULL);
791   return 0;
792 }
793
794 static int
795 validate_attr_set_scope(noit_conf_t_userdata_t *info,
796                         struct _valid_attr_t *attrinfo) {
797   int len;
798   len = strlen(attrinfo->scope);
799   if(strncmp(info->path, attrinfo->scope, len) ||
800      (info->path[len] != '\0' && info->path[len] != '/')) {
801     return -1;
802   }
803   return 0;
804 }
805 static int
806 replace_config(noit_console_closure_t ncct,
807                noit_conf_t_userdata_t *info, const char *name,
808                const char *value) {
809   int i, cnt, rv = -1, active = 0;
810   xmlXPathObjectPtr pobj = NULL;
811   xmlXPathContextPtr xpath_ctxt = NULL;
812   xmlNodePtr node, confignode;
813   char xpath[1024], *path;
814
815   path = info->path;
816   if(!strcmp(path, "/")) path = "";
817
818   noit_conf_xml_xpath(NULL, &xpath_ctxt);
819
820   /* Only if checks will fixate this attribute shall we check for
821    * child <check> nodes.
822    * NOTE: this return nothing and "seems" okay if we are _in_
823    *       a <check> node.  That case is handled below.
824    */
825   snprintf(xpath, sizeof(xpath), "/noit/%s//check[@uuid]", path);
826   pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
827   if(!pobj || pobj->type != XPATH_NODESET) goto out;
828   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
829   for(i=0; i<cnt; i++) {
830     uuid_t checkid;
831     node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i);
832     if(noit_conf_get_uuid(node, "@uuid", checkid)) {
833       noit_check_t *check;
834       check = noit_poller_lookup(checkid);
835       if(check && NOIT_CHECK_LIVE(check)) active++;
836     }
837   }
838   if(pobj) xmlXPathFreeObject(pobj);
839
840 #ifdef UNSAFE_RECONFIG
841   snprintf(xpath, sizeof(xpath), "/noit/%s", path);
842   pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
843   if(!pobj || pobj->type != XPATH_NODESET) goto out;
844   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
845   if(cnt != 1) {
846     nc_printf(ncct, "Internal error: context node disappeared\n");
847     goto out;
848   }
849   node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0);
850   if(strcmp((const char *)node->name, "check")) {
851     uuid_t checkid;
852     /* Detect if  we are actually a <check> node and attempting to
853      * change something we shouldn't.
854      * This is the counterpart noted above.
855      */
856     if(noit_conf_get_uuid(node, "@uuid", checkid)) {
857       noit_check_t *check;
858       check = noit_poller_lookup(checkid);
859       if(NOIT_CHECK_LIVE(check)) active++;
860     }
861   }
862   if(active) {
863     nc_printf(ncct, "Cannot set '%s', it would effect %d live check(s)\n",
864               name, active);
865     goto out;
866   }
867   if(pobj) xmlXPathFreeObject(pobj);
868 #endif
869
870   /* Here we want to remove /noit/path/config/name */
871   snprintf(xpath, sizeof(xpath), "/noit/%s/config/%s", path, name);
872   pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
873   if(!pobj || pobj->type != XPATH_NODESET) goto out;
874   if(xmlXPathNodeSetGetLength(pobj->nodesetval) > 0) {
875     xmlNodePtr toremove;
876     toremove = xmlXPathNodeSetItem(pobj->nodesetval, 0);
877     xmlUnlinkNode(toremove);
878   }
879   /* TODO: if there are no more children of config, remove config? */
880   if(value) {
881     if(pobj) xmlXPathFreeObject(pobj);
882     /* He we create config if needed and place a child node under it */
883     snprintf(xpath, sizeof(xpath), "/noit/%s/config", path);
884     pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
885     if(!pobj || pobj->type != XPATH_NODESET) goto out;
886     if(xmlXPathNodeSetGetLength(pobj->nodesetval) == 0) {
887       if(pobj) xmlXPathFreeObject(pobj);
888       snprintf(xpath, sizeof(xpath), "/noit/%s", path);
889       pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
890       if(!pobj || pobj->type != XPATH_NODESET) goto out;
891       if(xmlXPathNodeSetGetLength(pobj->nodesetval) != 1) {
892         nc_printf(ncct, "Node disappeared from under you!\n");
893         goto out;
894       }
895       confignode = xmlNewChild(xmlXPathNodeSetItem(pobj->nodesetval, 0),
896                                NULL, (xmlChar *)"config", NULL);
897       if(confignode == NULL) {
898         nc_printf(ncct, "Error creating config child node.\n");
899         goto out;
900       }
901     }
902     else confignode = xmlXPathNodeSetItem(pobj->nodesetval, 0);
903
904     assert(confignode);
905     /* Now we create a child */
906     xmlNewChild(confignode, NULL, (xmlChar *)name, (xmlChar *)value);
907   }
908   noit_conf_mark_changed();
909   rv = 0;
910  out:
911   if(pobj) xmlXPathFreeObject(pobj);
912   return rv;
913 }
914 static int
915 replace_attr(noit_console_closure_t ncct,
916              noit_conf_t_userdata_t *info, struct _valid_attr_t *attrinfo,
917              const char *value) {
918   int i, cnt, rv = -1, active = 0;
919   xmlXPathObjectPtr pobj = NULL;
920   xmlXPathContextPtr xpath_ctxt = NULL;
921   xmlNodePtr node;
922   char xpath[1024], *path;
923
924   path = info->path;
925   if(!strcmp(path, "/")) path = "";
926
927   noit_conf_xml_xpath(NULL, &xpath_ctxt);
928   if(attrinfo->checks_fixate) {
929     /* Only if checks will fixate this attribute shall we check for
930      * child <check> nodes.
931      * NOTE: this return nothing and "seems" okay if we are _in_
932      *       a <check> node.  That case is handled below.
933      */
934     snprintf(xpath, sizeof(xpath), "/noit/%s//check[@uuid]", path);
935     pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
936     if(!pobj || pobj->type != XPATH_NODESET) goto out;
937     cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
938     for(i=0; i<cnt; i++) {
939       uuid_t checkid;
940       node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, i);
941       if(noit_conf_get_uuid(node, "@uuid", checkid)) {
942         noit_check_t *check;
943         check = noit_poller_lookup(checkid);
944         if(check && NOIT_CHECK_LIVE(check)) active++;
945       }
946     }
947     if(pobj) xmlXPathFreeObject(pobj);
948   }
949   snprintf(xpath, sizeof(xpath), "/noit/%s", path);
950   pobj = xmlXPathEval((xmlChar *)xpath, xpath_ctxt);
951   if(!pobj || pobj->type != XPATH_NODESET) goto out;
952   cnt = xmlXPathNodeSetGetLength(pobj->nodesetval);
953   if(cnt != 1) {
954     nc_printf(ncct, "Internal error: context node disappeared\n");
955     goto out;
956   }
957   node = (noit_conf_section_t)xmlXPathNodeSetItem(pobj->nodesetval, 0);
958   if(attrinfo->checks_fixate &&
959      !strcmp((const char *)node->name, "check")) {
960     uuid_t checkid;
961     /* Detect if  we are actually a <check> node and attempting to
962      * change something we shouldn't.
963      * This is the counterpart noted above.
964      */
965     if(noit_conf_get_uuid(node, "@uuid", checkid)) {
966       noit_check_t *check;
967       check = noit_poller_lookup(checkid);
968       if(check && NOIT_CHECK_LIVE(check)) active++;
969     }
970   }
971   if(active) {
972     nc_printf(ncct, "Cannot set '%s', it would effect %d live check(s)\n",
973               attrinfo->name, active);
974     goto out;
975   }
976   xmlUnsetProp(node, (xmlChar *)attrinfo->name);
977   if(value)
978     xmlSetProp(node, (xmlChar *)attrinfo->name, (xmlChar *)value);
979   noit_conf_mark_changed();
980   rv = 0;
981  out:
982   if(pobj) xmlXPathFreeObject(pobj);
983   return rv;
984 }
985 int
986 noit_conf_check_set_attr(noit_console_closure_t ncct,
987                          int argc, char **argv,
988                          noit_console_state_t *state, void *closure) {
989   struct _valid_attr_t *attrinfo = closure;
990   noit_conf_t_userdata_t *info;
991
992   info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
993   if(!info || validate_attr_set_scope(info, attrinfo)) {
994     nc_printf(ncct, "'%s' attribute only valid in %s scope\n",
995               attrinfo->name, attrinfo->scope);
996     return -1;
997   }
998
999   if(argc != 1) {
1000     nc_printf(ncct, "set requires exactly one value\n");
1001     return -1;
1002   }
1003   /* Okay, we have an attribute and it should be set/replaced on the
1004    * current path.
1005    */
1006   if(replace_attr(ncct, info, attrinfo, argv[0])) {
1007     return -1;
1008   }
1009
1010   /* So, we updated an attribute, so we need to reload all checks
1011    * that are descendent-or-self of this node.
1012    */
1013   if(!strncmp(info->path, "/checks", strlen("/checks")))
1014     refresh_subchecks(ncct, info);
1015   if(!strncmp(info->path, "/filtersets", strlen("/filtersets")))
1016     noit_refresh_filtersets(ncct, info);
1017   return 0;
1018 }
1019
1020 int
1021 noit_conf_check_unset_attr(noit_console_closure_t ncct,
1022                            int argc, char **argv,
1023                            noit_console_state_t *state, void *closure) {
1024   struct _valid_attr_t *attrinfo = closure;
1025   noit_conf_t_userdata_t *info;
1026
1027   info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
1028   if(!info || validate_attr_set_scope(info, attrinfo)) {
1029     nc_printf(ncct, "'%s' attribute only valid in %s scope\n",
1030               attrinfo->name, attrinfo->scope);
1031     return -1;
1032   }
1033
1034   if(argc != 0) {
1035     nc_printf(ncct, "no arguments allowed to this command.\n");
1036     return -1;
1037   }
1038   /* Okay, we have an attribute and it should be set/replaced on the
1039    * current path.
1040    */
1041   if(replace_attr(ncct, info, attrinfo, NULL)) {
1042     return -1;
1043   }
1044
1045   /* So, we updated an attribute, so we need to reload all checks
1046    * that are descendent-or-self of this node.
1047    */
1048   if(!strncmp(info->path, "/checks", strlen("/checks")))
1049     refresh_subchecks(ncct, info);
1050   if(!strncmp(info->path, "/filterset", strlen("/filterest")))
1051     noit_refresh_filtersets(ncct, info);
1052   return 0;
1053 }
1054
1055 int
1056 noit_console_config_setconfig(noit_console_closure_t ncct,
1057                                 int argc, char **argv,
1058                                 noit_console_state_t *state, void *closure) {
1059   noit_conf_t_userdata_t *info;
1060
1061   info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
1062
1063   if(argc != 2) {
1064     nc_printf(ncct, "two arguments required.\n");
1065     return -1;
1066   }
1067   /* Okay, we have an child name and it should be culled from
1068    * current path/config.
1069    */
1070   if(replace_config(ncct, info, argv[0], argv[1])) {
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   refresh_subchecks(ncct, info);
1078   return 0;
1079 }
1080
1081 int
1082 noit_console_config_unsetconfig(noit_console_closure_t ncct,
1083                                 int argc, char **argv,
1084                                 noit_console_state_t *state, void *closure) {
1085   noit_conf_t_userdata_t *info;
1086
1087   info = noit_console_userdata_get(ncct, NOIT_CONF_T_USERDATA);
1088
1089   if(argc != 1) {
1090     nc_printf(ncct, "one argument required.\n");
1091     return -1;
1092   }
1093   /* Okay, we have an child name and it should be culled from
1094    * current path/config.
1095    */
1096   if(replace_config(ncct, info, argv[0], NULL)) {
1097     return -1;
1098   }
1099
1100   /* So, we updated an attribute, so we need to reload all checks
1101    * that are descendent-or-self of this node.
1102    */
1103   refresh_subchecks(ncct, info);
1104   return 0;
1105 }
1106
1107
1108 #define NEW_STATE(a) (a) = noit_console_state_alloc()
1109 #define ADD_CMD(a,cmd,func,ac,ss,c) \
1110   noit_console_state_add_cmd((a), \
1111     NCSCMD(cmd, func, ac, ss, c))
1112 #define DELEGATE_CMD(a,cmd,ac,ss) \
1113   noit_console_state_add_cmd((a), \
1114     NCSCMD(cmd, noit_console_state_delegate, ac, ss, NULL))
1115
1116 static
1117 void register_console_config_check_commands() {
1118   cmd_info_t *showcmd, *nocmd, *confcmd, *conftcmd, *conftnocmd, *lscmd;
1119   noit_console_state_t *tl, *_conf_t_check_state, *_unset_state,
1120                        *_attr_state, *_uattr_state;
1121
1122   tl = noit_console_state_initial();
1123   showcmd = noit_console_state_get_cmd(tl, "show");
1124   nocmd = noit_console_state_get_cmd(tl, "no");
1125   confcmd = noit_console_state_get_cmd(tl, "configure");
1126   conftcmd = noit_console_state_get_cmd(confcmd->dstate, "terminal");
1127   conftnocmd = noit_console_state_get_cmd(conftcmd->dstate, "no");
1128   lscmd = noit_console_state_get_cmd(conftcmd->dstate, "ls");
1129   lscmd->func = noit_console_config_show;
1130   /* attribute <attrname> <value> */
1131   NEW_STATE(_attr_state);
1132   noit_console_state_add_check_attrs(_attr_state, noit_conf_check_set_attr,
1133                                      "/checks");
1134  
1135   /* no attribute <attrname> <value> */
1136   NEW_STATE(_uattr_state);
1137   noit_console_state_add_check_attrs(_uattr_state, noit_conf_check_unset_attr,
1138                                      "/checks");
1139   NEW_STATE(_unset_state);
1140   DELEGATE_CMD(_unset_state, "attribute",
1141                noit_console_opt_delegate, _uattr_state);
1142   ADD_CMD(_unset_state, "config",
1143           noit_console_config_unsetconfig, NULL, NULL, NULL);
1144
1145   DELEGATE_CMD(conftnocmd->dstate, "attribute",
1146                noit_console_opt_delegate, _uattr_state);
1147   ADD_CMD(conftnocmd->dstate, "config",
1148           noit_console_config_unsetconfig, NULL, NULL, NULL);
1149   ADD_CMD(conftnocmd->dstate, "check",
1150           noit_console_config_nocheck, NULL, NULL, NULL);
1151  
1152   NEW_STATE(_conf_t_check_state);
1153   _conf_t_check_state->console_prompt_function = conf_t_check_prompt;
1154   DELEGATE_CMD(_conf_t_check_state, "attribute",
1155                noit_console_opt_delegate, _attr_state);
1156   DELEGATE_CMD(_conf_t_check_state, "no",
1157                noit_console_opt_delegate, _unset_state);
1158   ADD_CMD(_conf_t_check_state, "config",
1159           noit_console_config_setconfig, NULL, NULL, NULL);
1160   ADD_CMD(_conf_t_check_state, "status",
1161           noit_console_show_check, NULL, NULL, NULL);
1162   ADD_CMD(_conf_t_check_state, "exit",
1163           noit_console_config_cd, NULL, NULL, "..");
1164   ADD_CMD(_conf_t_check_state, "check",
1165           noit_console_check, noit_console_conf_check_opts,
1166           _conf_t_check_state, "..");
1167
1168   ADD_CMD(conftcmd->dstate, "config",
1169           noit_console_config_setconfig, NULL, NULL, NULL);
1170   ADD_CMD(conftcmd->dstate, "check",
1171           noit_console_check, noit_console_conf_check_opts,
1172           _conf_t_check_state, NULL);
1173
1174   ADD_CMD(showcmd->dstate, "check",
1175           noit_console_show_check, noit_console_check_opts, NULL, NULL);
1176
1177   ADD_CMD(tl, "watch",
1178           noit_console_watch_check, noit_console_check_opts, NULL, (void *)1);
1179
1180   ADD_CMD(nocmd->dstate, "watch",
1181           noit_console_watch_check, noit_console_check_opts, NULL, (void *)0);
1182
1183   DELEGATE_CMD(conftcmd->dstate, "attribute",
1184                noit_console_opt_delegate, _attr_state);
1185
1186   ADD_CMD(tl, "reload", noit_conf_checks_reload, NULL, NULL, NULL);
1187 }
1188
Note: See TracBrowser for help on using the browser.