root/src/noit_filters.c

Revision 304ec80b8cf842fc0abe5f9029790908b6455957, 22.5 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 2 months ago)

Convert to libmtev.

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2007, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  * Copyright (c) 2015, Circonus, Inc. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met:
9  *
10  *     * Redistributions of source code must retain the above copyright
11  *       notice, this list of conditions and the following disclaimer.
12  *     * Redistributions in binary form must reproduce the above
13  *       copyright notice, this list of conditions and the following
14  *       disclaimer in the documentation and/or other materials provided
15  *       with the distribution.
16  *     * Neither the name OmniTI Computer Consulting, Inc. nor the names
17  *       of its contributors may be used to endorse or promote products
18  *       derived from this software without specific prior written
19  *       permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <mtev_defines.h>
35
36 #include <mtev_hash.h>
37 #include <mtev_atomic.h>
38 #include <mtev_watchdog.h>
39 #include <mtev_capabilities_listener.h>
40 #include <mtev_conf.h>
41
42 #include "noit_mtev_bridge.h"
43 #include "noit_check.h"
44 #include "noit_conf_checks.h"
45 #include "noit_filters.h"
46
47 #include <pcre.h>
48 #include <assert.h>
49 #include <libxml/tree.h>
50
51 static mtev_hash_table *filtersets = NULL;
52 static pthread_mutex_t filterset_lock;
53 static pcre *fallback_no_match = NULL;
54 #define LOCKFS() pthread_mutex_lock(&filterset_lock)
55 #define UNLOCKFS() pthread_mutex_unlock(&filterset_lock)
56
57 typedef enum { NOIT_FILTER_ACCEPT, NOIT_FILTER_DENY } noit_ruletype_t;
58 typedef struct _filterrule {
59   noit_ruletype_t type;
60   pcre *target_override;
61   pcre *target;
62   pcre_extra *target_e;
63   mtev_hash_table *target_ht;
64   int target_auto_hash_max;
65   pcre *module_override;
66   pcre *module;
67   pcre_extra *module_e;
68   mtev_hash_table *module_ht;
69   int module_auto_hash_max;
70   pcre *name_override;
71   pcre *name;
72   pcre_extra *name_e;
73   mtev_hash_table *name_ht;
74   int name_auto_hash_max;
75   pcre *metric_override;
76   pcre *metric;
77   pcre_extra *metric_e;
78   mtev_hash_table *metric_ht;
79   int metric_auto_hash_max;
80   struct _filterrule *next;
81 } filterrule_t;
82
83 typedef struct {
84   mtev_atomic32_t ref_cnt;
85   char *name;
86   filterrule_t *rules;
87 } filterset_t;
88
89 #define FRF(r,a) do { \
90   if(r->a) pcre_free(r->a); \
91   if(r->a##_e) pcre_free(r->a##_e); \
92   if(r->a##_ht) { \
93     mtev_hash_destroy(r->a##_ht, free, NULL); \
94     free(r->a##_ht); \
95   } \
96 } while(0)
97
98 static void
99 filterrule_free(void *vp) {
100   filterrule_t *r = vp;
101   FRF(r,target);
102   FRF(r,module);
103   FRF(r,name);
104   FRF(r,metric);
105   free(r);
106 }
107 static void
108 filterset_free(void *vp) {
109   filterset_t *fs = vp;
110   filterrule_t *r;
111   if(mtev_atomic_dec32(&fs->ref_cnt) != 0) return;
112   mtevL(noit_debug, "Freeing filterset [%d]: %s\n", fs->ref_cnt, fs->name);
113   while(fs->rules) {
114     r = fs->rules->next;
115     filterrule_free(fs->rules);
116     fs->rules = r;
117   }
118   if(fs->name) free(fs->name);
119   free(fs);
120 }
121 void
122 noit_filter_compile_add(mtev_conf_section_t setinfo) {
123   mtev_conf_section_t *rules;
124   int j, fcnt;
125   char filterset_name[256];
126   filterset_t *set;
127   if(!mtev_conf_get_stringbuf(setinfo, "@name",
128                               filterset_name, sizeof(filterset_name))) {
129     mtevL(noit_error,
130           "filterset with no name, skipping as it cannot be referenced.\n");
131     return;
132   }
133   set = calloc(1, sizeof(*set));
134   set->ref_cnt = 1;
135   set->name = strdup(filterset_name);
136
137   rules = mtev_conf_get_sections(setinfo, "rule", &fcnt);
138   /* Here we will work through the list backwards pushing the rules on
139    * the front of the list.  That way we can simply walk them in order
140    * for the application process.
141    */
142   mtevL(noit_debug, "Compiling filterset '%s'\n", set->name);
143   for(j=fcnt-1; j>=0; j--) {
144     filterrule_t *rule;
145     char buffer[256];
146     if(!mtev_conf_get_stringbuf(rules[j], "@type", buffer, sizeof(buffer)) ||
147        (strcmp(buffer, "accept") && strcmp(buffer, "allow") && strcmp(buffer, "deny"))) {
148       mtevL(noit_error, "rule must have type 'accept' or 'allow' or 'deny'\n");
149       continue;
150     }
151     mtevL(noit_debug, "Prepending %s into %s\n", buffer, set->name);
152     rule = calloc(1, sizeof(*rule));
153     rule->type = (!strcmp(buffer, "accept") || !strcmp(buffer, "allow")) ?
154                    NOIT_FILTER_ACCEPT : NOIT_FILTER_DENY;
155
156     /* Compile any hash tables, should they exist */
157 #define HT_COMPILE(rname) do { \
158     mtev_conf_section_t *htentries; \
159     int hte_cnt, hti, tablesize = 2, auto_max = 0; \
160     char *htstr; \
161     htentries = mtev_conf_get_sections(rules[j], #rname, &hte_cnt); \
162     mtev_conf_get_int(rules[j], "@" #rname "_auto_add", &auto_max); \
163     if(hte_cnt || auto_max > 0) { \
164       rule->rname##_auto_hash_max = auto_max; \
165       rule->rname##_ht = calloc(1, sizeof(*(rule->rname##_ht))); \
166       while(tablesize < hte_cnt) tablesize <<= 1; \
167       mtev_hash_init_size(rule->rname##_ht, tablesize); \
168       for(hti=0; hti<hte_cnt; hti++) { \
169         if(!mtev_conf_get_string(htentries[hti], "self::node()", &htstr)) \
170           mtevL(noit_error, "Error fetching text content from filter match.\n"); \
171         else \
172           mtev_hash_replace(rule->rname##_ht, htstr, strlen(htstr), NULL, free, NULL); \
173       } \
174     } \
175     free(htentries); \
176 } while(0);
177     HT_COMPILE(target);
178     HT_COMPILE(module);
179     HT_COMPILE(name);
180     HT_COMPILE(metric);
181    
182     /* Compile our rules */
183 #define RULE_COMPILE(rname) do { \
184   char *longre = NULL; \
185   if(mtev_conf_get_string(rules[j], "@" #rname, &longre)) { \
186     const char *error; \
187     int erroffset; \
188     rule->rname = pcre_compile(longre, 0, &error, &erroffset, NULL); \
189     if(!rule->rname) { \
190       mtevL(noit_debug, "set '%s' rule '%s: %s' compile failed: %s\n", \
191             set->name, #rname, longre, error ? error : "???"); \
192       rule->rname##_override = fallback_no_match; \
193     } \
194     else { \
195       rule->rname##_e = pcre_study(rule->rname, 0, &error); \
196     } \
197     free(longre); \
198   } \
199 } while(0)
200
201     if(rule->target_ht == NULL)
202       RULE_COMPILE(target);
203     if(rule->module_ht == NULL)
204       RULE_COMPILE(module);
205     if(rule->name_ht == NULL)
206       RULE_COMPILE(name);
207     if(rule->metric_ht == NULL)
208       RULE_COMPILE(metric);
209     rule->next = set->rules;
210     set->rules = rule;
211   }
212   free(rules);
213   LOCKFS();
214   mtev_hash_replace(filtersets, set->name, strlen(set->name), (void *)set,
215                     NULL, filterset_free);
216   UNLOCKFS();
217 }
218 int
219 noit_filter_exists(const char *name) {
220   int exists;
221   void *v;
222   LOCKFS();
223   exists = mtev_hash_retrieve(filtersets, name, strlen(name), &v);
224   UNLOCKFS();
225   return exists;
226 }
227 int
228 noit_filter_remove(mtev_conf_section_t vnode) {
229   int removed;
230   char *name = (char *)xmlGetProp(vnode, (xmlChar *)"name");
231   if(!name) return 0;
232   LOCKFS();
233   removed = mtev_hash_delete(filtersets, name, strlen(name),
234                              NULL, filterset_free);
235   UNLOCKFS();
236   return removed;
237 }
238 void
239 noit_filters_from_conf() {
240   mtev_conf_section_t *sets;
241   int i, cnt;
242
243   sets = mtev_conf_get_sections(NULL, "/noit/filtersets//filterset", &cnt);
244   for(i=0; i<cnt; i++) {
245     mtev_watchdog_child_heartbeat();
246     noit_filter_compile_add(sets[i]);
247   }
248   free(sets);
249 }
250
251 void
252 noit_refresh_filtersets(mtev_console_closure_t ncct,
253                         mtev_conf_t_userdata_t *info) {
254   noit_filters_from_conf();
255   nc_printf(ncct, "Reloaded %d filtersets.\n",
256             filtersets ? mtev_hash_size(filtersets) : 0);
257 }
258
259 static mtev_boolean
260 noit_apply_filterrule(mtev_hash_table *m,
261                       pcre *p, pcre_extra *pe, const char *subj) {
262   int rc, ovector[30];
263   if(m) {
264     void *vptr;
265     return mtev_hash_retrieve(m, subj, strlen(subj), &vptr);
266   }
267   if(!p) return mtev_true;
268   rc = pcre_exec(p, pe, subj, strlen(subj), 0, 0, ovector, 30);
269   if(rc >= 0) return mtev_true;
270   return mtev_false;
271 }
272 static int
273 noit_filter_update_conf_rule(const char *fname, int idx, const char *rname, const char *value) {
274   char xpath[1024];
275   xmlNodePtr rulenode, child;
276
277   snprintf(xpath, sizeof(xpath), "//filtersets/filterset[@name=\"%s\"]/rule[%d]", fname, idx);
278   rulenode = mtev_conf_get_section(NULL, xpath);
279   if(!rulenode) return -1;
280   child = xmlNewNode(NULL, (xmlChar *)rname);
281   xmlNodeAddContent(child, (xmlChar *)value);
282   xmlAddChild(rulenode, child);
283   CONF_DIRTY(rulenode);
284   mtev_conf_mark_changed();
285   mtev_conf_request_write();
286   return 0;
287 }
288 mtev_boolean
289 noit_apply_filterset(const char *filterset,
290                      noit_check_t *check,
291                      metric_t *metric) {
292   /* We pass in filterset here just in case someone wants to apply
293    * a filterset other than check->filterset.. You never know.
294    */
295   void *vfs;
296   if(!filterset) return mtev_true;   /* No filter */
297   if(!filtersets) return mtev_false; /* Couldn't possibly match */
298
299   LOCKFS();
300   if(mtev_hash_retrieve(filtersets, filterset, strlen(filterset), &vfs)) {
301     filterset_t *fs = (filterset_t *)vfs;
302     filterrule_t *r;
303     int idx = 1;
304     mtev_atomic_inc32(&fs->ref_cnt);
305     UNLOCKFS();
306 #define MATCHES(rname, value) noit_apply_filterrule(r->rname##_ht, r->rname ? r->rname : r->rname##_override, r->rname ? r->rname##_e : NULL, value)
307     for(r = fs->rules; r; r = r->next) {
308       int need_target, need_module, need_name, need_metric;
309       need_target = !MATCHES(target, check->target);
310       need_module = !MATCHES(module, check->module);
311       need_name = !MATCHES(name, check->name);
312       need_metric = !MATCHES(metric, metric->metric_name);
313       if(!need_target && !need_module && !need_name && !need_metric) {
314         return (r->type == NOIT_FILTER_ACCEPT) ? mtev_true : mtev_false;
315       }
316       /* If we need some of these and we have an auto setting that isn't fulfilled for each of them, we can add and succeed */
317 #define CHECK_ADD(rname) (!need_##rname || (r->rname##_auto_hash_max > 0 && r->rname##_ht && mtev_hash_size(r->rname##_ht) < r->rname##_auto_hash_max))
318       if(CHECK_ADD(target) && CHECK_ADD(module) && CHECK_ADD(name) && CHECK_ADD(metric)) {
319 #define UPDATE_FILTER_RULE(rnum, rname, value) do { \
320   mtev_hash_replace(r->rname##_ht, strdup(value), strlen(value), NULL, free, NULL); \
321   if(noit_filter_update_conf_rule(fs->name, rnum, #rname, value) < 0) { \
322     mtevL(noit_error, "Error updating configuration for new filter auto_add on %s=%s\n", #rname, value); \
323   } \
324 } while(0)
325         if(need_target) UPDATE_FILTER_RULE(idx, target, check->target);
326         if(need_module) UPDATE_FILTER_RULE(idx, module, check->module);
327         if(need_name) UPDATE_FILTER_RULE(idx, name, check->name);
328         if(need_metric) UPDATE_FILTER_RULE(idx, metric, metric->metric_name);
329         noit_filterset_log_auto_add(fs->name, check, metric, r->type == NOIT_FILTER_ACCEPT);
330         return (r->type == NOIT_FILTER_ACCEPT) ? mtev_true : mtev_false;
331       }
332       idx++;
333     }
334     filterset_free(fs);
335     return mtev_false;
336   }
337   UNLOCKFS();
338   return mtev_false;
339 }
340
341 static char *
342 conf_t_filterset_prompt(EditLine *el) {
343   mtev_console_closure_t ncct;
344   mtev_conf_t_userdata_t *info;
345   static char *tl = "noit(conf)# ";
346   static char *pfmt = "noit(conf:filterset:%.*s%s)# ";
347   int max_space, namelen;
348   el_get(el, EL_USERDATA, (void *)&ncct);
349   if(!ncct) return tl;
350   info = mtev_console_userdata_get(ncct, MTEV_CONF_T_USERDATA);
351   if(!info) return tl;
352   max_space = sizeof(info->prompt) - strlen(pfmt) + 6 - 1;
353   namelen = strlen(info->filter_name);
354   if(namelen > max_space)
355     snprintf(info->prompt, sizeof(info->prompt), pfmt,
356              max_space - 3, info->filter_name, "...");
357   else
358     snprintf(info->prompt, sizeof(info->prompt), pfmt,
359              namelen, info->filter_name, "");
360   return info->prompt;
361 }
362
363 static int
364 noit_console_filter_show(mtev_console_closure_t ncct,
365                          int argc, char **argv,
366                          mtev_console_state_t *state,
367                          void *closure) {
368   mtev_conf_t_userdata_t *info;
369   char xpath[1024];
370   xmlNodePtr fsnode;
371   mtev_conf_section_t *rules;
372   int i, rulecnt;
373
374   info = mtev_console_userdata_get(ncct, MTEV_CONF_T_USERDATA);
375   snprintf(xpath, sizeof(xpath), "/%s",
376            info->path);
377   fsnode = mtev_conf_get_section(NULL, xpath);
378   if(!fsnode) {
379     nc_printf(ncct, "internal error\n");
380     return -1;
381   }
382   rules = mtev_conf_get_sections(fsnode, "rule", &rulecnt);
383   for(i=0; i<rulecnt; i++) {
384     char val[256];
385     val[0] = '\0';
386     mtev_conf_get_stringbuf(rules[i], "@type", val, sizeof(val));
387     nc_printf(ncct, "Rule %d [%s]:\n", i+1, val);
388 #define DUMP_ATTR(a) do { \
389   char *vstr; \
390   mtev_conf_section_t ht; \
391   int cnt; \
392   ht = mtev_conf_get_sections(rules[i], #a, &cnt); \
393   if(ht && cnt) { \
394     nc_printf(ncct, "\t%s: hash match of %d items\n", #a, cnt); \
395   } \
396   else if(mtev_conf_get_string(rules[i], "@" #a, &vstr)) { \
397     nc_printf(ncct, "\t%s: /%s/\n", #a, val); \
398     free(vstr); \
399   } \
400   free(ht); \
401 } while(0)
402     DUMP_ATTR(target);
403     DUMP_ATTR(module);
404     DUMP_ATTR(name);
405     DUMP_ATTR(metric);
406   }
407   if(rules) free(rules);
408   return 0;
409 }
410 static int
411 noit_console_rule_configure(mtev_console_closure_t ncct,
412                             int argc, char **argv,
413                             mtev_console_state_t *state,
414                             void *closure) {
415   xmlNodePtr fsnode = NULL;
416   mtev_conf_t_userdata_t *info;
417   char xpath[1024];
418
419   info = mtev_console_userdata_get(ncct, MTEV_CONF_T_USERDATA);
420   snprintf(xpath, sizeof(xpath), "/%s",
421            info->path);
422   fsnode = mtev_conf_get_section(NULL, xpath);
423   if(!fsnode) {
424     nc_printf(ncct, "internal error");
425     return -1;
426   }
427   if(closure) {
428     int rulenum;
429     xmlNodePtr byebye;
430     /* removing a rule */
431     if(argc != 1) {
432       nc_printf(ncct, "requires one argument\n");
433       return -1;
434     }
435     rulenum = atoi(argv[0]);
436     snprintf(xpath, sizeof(xpath), "rule[%d]", rulenum);
437     byebye = mtev_conf_get_section(fsnode, xpath);
438     if(!byebye) {
439       nc_printf(ncct, "cannot find rule\n");
440       return -1;
441     }
442     xmlUnlinkNode(byebye);
443     xmlFreeNode(byebye);
444     nc_printf(ncct, "removed\n");
445   }
446   else {
447     xmlNodePtr (*add_func)(xmlNodePtr, xmlNodePtr);
448     xmlNodePtr add_arg, new_rule;
449     int i, needs_type = 1;
450     if(argc < 1 || argc % 2) {
451       nc_printf(ncct, "even number of arguments required\n");
452       return -1;
453     }
454     if(!strcmp(argv[0], "before") || !strcmp(argv[0], "after")) {
455       int rulenum = atoi(argv[1]);
456       snprintf(xpath, sizeof(xpath), "rule[%d]", rulenum);
457       add_arg = mtev_conf_get_section(fsnode, xpath);
458       if(!add_arg) {
459         nc_printf(ncct, "%s rule not found\n", xpath);
460         return -1;
461       }
462       if(*argv[0] == 'b') add_func = xmlAddPrevSibling;
463       else add_func = xmlAddNextSibling;
464       argc -= 2;
465       argv += 2;
466     }
467     else {
468       add_func = xmlAddChild;
469       add_arg = fsnode;
470     }
471     for(i=0;i<argc;i+=2) {
472       if(!strcmp(argv[i], "type")) needs_type = 0;
473       else if(strcmp(argv[i], "target") && strcmp(argv[i], "module") &&
474               strcmp(argv[i], "name") && strcmp(argv[i], "metric")) {
475         nc_printf(ncct, "unknown attribute '%s'\n", argv[i]);
476         return -1;
477       }
478     }
479     if(needs_type) {
480       nc_printf(ncct, "type <allow|deny> is required\n");
481       return -1;
482     }
483     new_rule = xmlNewNode(NULL, (xmlChar *)"rule");
484     for(i=0;i<argc;i+=2)
485       xmlSetProp(new_rule, (xmlChar *)argv[i], (xmlChar *)argv[i+1]);
486     add_func(add_arg, new_rule);
487     noit_filter_compile_add((mtev_conf_section_t *)fsnode);
488   }
489   return 0;
490 }
491 static int
492 noit_console_filter_configure(mtev_console_closure_t ncct,
493                               int argc, char **argv,
494                               mtev_console_state_t *state,
495                               void *closure) {
496   xmlNodePtr parent, fsnode = NULL;
497   int rv = -1;
498   mtev_conf_t_userdata_t *info;
499   char xpath[1024];
500
501   info = mtev_console_userdata_get(ncct, MTEV_CONF_T_USERDATA);
502   if(!info) {
503     nc_printf(ncct, "internal error\n");
504     goto cleanup;
505   }
506   if(strncmp(info->path, "/filtersets/", strlen("/filtersets/")) &&
507      strcmp(info->path, "/filtersets")) {
508     nc_printf(ncct, "filterset only allows inside /filtersets (not %s)\n",
509               info->path);
510     goto cleanup;
511   }
512   if(argc != 1) {
513     nc_printf(ncct, "filterset requires one argument\n");
514     goto cleanup;
515   }
516   snprintf(xpath, sizeof(xpath), "/%s", info->path);
517   parent = mtev_conf_get_section(NULL, xpath);
518   if(!parent) {
519     nc_printf(ncct, "internal error, can't final current working path\n");
520     goto cleanup;
521   }
522   snprintf(xpath, sizeof(xpath), "filterset[@name=\"%s\"]", argv[0]);
523   fsnode = mtev_conf_get_section(parent, xpath);
524   if(closure) {
525     int removed;
526     removed = noit_filter_remove(fsnode);
527     nc_printf(ncct, "%sremoved filterset '%s'\n",
528               removed ? "" : "failed to ", argv[0]);
529     if(removed) {
530       CONF_REMOVE(fsnode);
531       xmlUnlinkNode(fsnode);
532       xmlFreeNode(fsnode);
533     }
534     rv = !removed;
535     goto cleanup;
536   }
537   if(!fsnode) {
538     void *vfs;
539     nc_printf(ncct, "Cannot find filterset '%s'\n", argv[0]);
540     LOCKFS();
541     if(mtev_hash_retrieve(filtersets, argv[0], strlen(argv[0]), &vfs)) {
542       UNLOCKFS();
543       nc_printf(ncct, "filter of the same name already exists\n");
544       goto cleanup;
545     }
546     UNLOCKFS();
547     /* Fine the parent path */
548     fsnode = xmlNewNode(NULL, (xmlChar *)"filterset");
549     xmlSetProp(fsnode, (xmlChar *)"name", (xmlChar *)argv[0]);
550     xmlAddChild(parent, fsnode);
551     nc_printf(ncct, "created new filterset\n");
552   }
553
554   if(info) {
555     char *xmlpath = NULL;
556     free(info->path);
557     xmlpath = (char *)xmlGetNodePath(fsnode);
558     info->path = strdup(xmlpath + strlen("/noit"));
559     free(xmlpath);
560     strlcpy(info->filter_name, argv[0], sizeof(info->filter_name));
561     if(state) {
562       mtev_console_state_push_state(ncct, state);
563       mtev_console_state_init(ncct);
564     }
565   }
566  cleanup:
567   return rv;
568 }
569
570 static int
571 filterset_accum(noit_check_t *check, void *closure) {
572   mtev_hash_table *active = closure;
573   if(!check->filterset) return 0;
574   if(mtev_hash_delete(active, check->filterset, strlen(check->filterset), free, NULL))
575     return 1;
576   return 0;
577 }
578
579 int
580 noit_filtersets_cull_unused() {
581   mtev_hash_table active = MTEV_HASH_EMPTY;
582   char *buffer = NULL;
583   mtev_conf_section_t *declares;
584   int i, n_uses = 0, n_declares = 0, removed = 0;
585   const char *declare_xpath = "//filterset[@name and not (@cull='false')]";
586
587   declares = mtev_conf_get_sections(NULL, declare_xpath, &n_declares);
588   if(declares) {
589     /* store all unit filtersets used */
590     for(i=0;i<n_declares;i++) {
591       if(!buffer) buffer = malloc(128);
592       if(mtev_conf_get_stringbuf(declares[i], "@name", buffer, 128)) {
593         if(mtev_hash_store(&active, buffer, strlen(buffer), declares[i])) {
594           buffer = NULL;
595         }
596       }
597     }
598     if(buffer) free(buffer);
599     free(declares);
600   }
601
602   n_uses = noit_poller_do(filterset_accum, &active);
603
604   if(n_uses > 0 && mtev_hash_size(&active) > 0) {
605     mtev_hash_iter iter = MTEV_HASH_ITER_ZERO;
606     const char *filter_name;
607     int filter_name_len;
608     void *vnode;
609     while(mtev_hash_next(&active, &iter, &filter_name, &filter_name_len,
610                          &vnode)) {
611       if(noit_filter_remove(vnode)) {
612         CONF_REMOVE(vnode);
613         xmlUnlinkNode(vnode);
614         xmlFreeNode(vnode);
615         removed++;
616       }
617     }
618   }
619
620   mtev_hash_destroy(&active, free, NULL);
621   return removed;
622 }
623
624 static int
625 noit_console_filter_cull(mtev_console_closure_t ncct,
626                          int argc, char **argv,
627                          mtev_console_state_t *state,
628                          void *closure) {
629   int rv = 0;
630   mtev_conf_t_userdata_t *info;
631
632   info = mtev_console_userdata_get(ncct, MTEV_CONF_T_USERDATA);
633   if(!info) {
634     nc_printf(ncct, "internal error\n");
635     return -1;
636   }
637   if(strncmp(info->path, "/filtersets/", strlen("/filtersets/")) &&
638      strcmp(info->path, "/filtersets")) {
639     nc_printf(ncct, "filterset only allows inside /filtersets (not %s)\n",
640               info->path);
641     return -1;
642   }
643   rv = noit_filtersets_cull_unused();
644   nc_printf(ncct, "Culled %d unused filtersets\n", rv);
645   return 0;
646 }
647 static void
648 register_console_filter_commands() {
649   mtev_console_state_t *tl, *filterset_state, *nostate;
650   cmd_info_t *confcmd, *conf_t_cmd, *no_cmd;
651
652   tl = mtev_console_state_initial();
653   confcmd = mtev_console_state_get_cmd(tl, "configure");
654   assert(confcmd && confcmd->dstate);
655
656   conf_t_cmd = mtev_console_state_get_cmd(confcmd->dstate, "terminal");
657   assert(conf_t_cmd && conf_t_cmd->dstate);
658
659   nostate = mtev_console_state_alloc();
660   mtev_console_state_add_cmd(nostate,
661     NCSCMD("rule", noit_console_rule_configure, NULL, NULL, (void *)1));
662
663   filterset_state = mtev_console_state_alloc();
664   mtev_console_state_add_cmd(filterset_state,
665     NCSCMD("exit", mtev_console_config_cd, NULL, NULL, ".."));
666   mtev_console_state_add_cmd(filterset_state,
667     NCSCMD("status", noit_console_filter_show, NULL, NULL, NULL));
668   mtev_console_state_add_cmd(filterset_state,
669     NCSCMD("rule", noit_console_rule_configure, NULL, NULL, NULL));
670   mtev_console_state_add_cmd(filterset_state,
671     NCSCMD("no", mtev_console_state_delegate, mtev_console_opt_delegate,
672            nostate, NULL));
673
674   filterset_state->console_prompt_function = conf_t_filterset_prompt;
675
676   mtev_console_state_add_cmd(conf_t_cmd->dstate,
677     NCSCMD("filterset", noit_console_filter_configure,
678            NULL, filterset_state, NULL));
679
680   mtev_console_state_add_cmd(conf_t_cmd->dstate,
681     NCSCMD("cull", noit_console_filter_cull,
682            NULL, NULL, NULL));
683
684   no_cmd = mtev_console_state_get_cmd(conf_t_cmd->dstate, "no");
685   assert(no_cmd && no_cmd->dstate);
686   mtev_console_state_add_cmd(no_cmd->dstate,
687     NCSCMD("filterset", noit_console_filter_configure, NULL, NULL, (void *)1));
688 }
689
690 void
691 noit_filters_init() {
692   const char *error;
693   int erroffset;
694   pthread_mutex_init(&filterset_lock, NULL);
695   filtersets = calloc(1, sizeof(mtev_hash_table));
696   fallback_no_match = pcre_compile("^(?=a)b", 0, &error, &erroffset, NULL);
697   if(!fallback_no_match) {
698     mtevL(noit_error, "Filter initialization failed (nomatch filter)\n");
699     exit(-1);
700   }
701   mtev_capabilities_add_feature("filterset:hash", NULL);
702   register_console_filter_commands();
703   noit_filters_from_conf();
704 }
Note: See TracBrowser for help on using the browser.