root/src/noit_conf_checks.c

Revision 8ad126b7390d75e24ecc859efb01570b01bbcdc1, 39.2 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 5 years ago)

This is pretty intrusive.

Here we refactor the console initalization in noit_conf_checks to have
the reusable parts pulled into the noit_conf directly so that stratcon
can make use of them. noit_conf_checks is retooled to extend that and
override the 'ls' command to have it's old form and function.

stratcon_jlog_streamer extends the noit_conf console syntax to allow
adding and removing of noits within the 'configure terminal' mode.

# conf t
# noit 10.1.2.3
# noit 10.1.5.5:12345
# no noit 10.1.2.3
# no noit 10.1.5.5:12345

This should not change the operation of noitd's console in any way;
however, the changes were quite substantial, so we should keep an eye
out for collateral breakage.

refs #195

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