void noit_filters_from_conf() { mtev_conf_section_t *sets; int i, cnt; sets = mtev_conf_get_sections(NULL, "/noit/filtersets//filterset", &cnt); for(i=0; i<cnt; i++) { mtev_watchdog_child_heartbeat(); noit_filter_compile_add(sets[i]); } free(sets); }
static int noit_console_filter_show(mtev_console_closure_t ncct, int argc, char **argv, mtev_console_state_t *state, void *closure) { mtev_conf_t_userdata_t *info; char xpath[1024]; xmlNodePtr fsnode; mtev_conf_section_t *rules; int i, rulecnt; info = mtev_console_userdata_get(ncct, MTEV_CONF_T_USERDATA); snprintf(xpath, sizeof(xpath), "/%s", info->path); fsnode = mtev_conf_get_section(NULL, xpath); if(!fsnode) { nc_printf(ncct, "internal error\n"); return -1; } rules = mtev_conf_get_sections(fsnode, "rule", &rulecnt); for(i=0; i<rulecnt; i++) { char val[256]; val[0] = '\0'; mtev_conf_get_stringbuf(rules[i], "@type", val, sizeof(val)); nc_printf(ncct, "Rule %d [%s]:\n", i+1, val); #define DUMP_ATTR(a) do { \ char *vstr; \ mtev_conf_section_t ht; \ int cnt; \ ht = mtev_conf_get_sections(rules[i], #a, &cnt); \ if(ht && cnt) { \ nc_printf(ncct, "\t%s: hash match of %d items\n", #a, cnt); \ } \ else if(mtev_conf_get_string(rules[i], "@" #a, &vstr)) { \ nc_printf(ncct, "\t%s: /%s/\n", #a, val); \ free(vstr); \ } \ free(ht); \ } while(0) DUMP_ATTR(target); DUMP_ATTR(module); DUMP_ATTR(name); DUMP_ATTR(metric); DUMP_ATTR(id); DUMP_ATTR(skipto); } if(rules) free(rules); return 0; }
void mtev_dso_init(void) { mtev_conf_section_t *sections; int i, cnt = 0; mtev_dso_add_type("loader", mtev_dso_list_loaders); mtev_dso_add_type("generic", mtev_dso_list_generics); /* Load our generic modules */ sections = mtev_conf_get_sections(MTEV_CONF_ROOT, "//modules//generic", &cnt); for(i=0; i<cnt; i++) { char g_name[256]; mtev_dso_generic_t *gen; mtev_conf_section_t *include_sections = NULL; int section_cnt; if(!mtev_conf_get_stringbuf(sections[i], "ancestor-or-self::node()/@name", g_name, sizeof(g_name))) { mtevL(mtev_stderr, "No name defined in generic stanza %d\n", i+1); continue; } if(mtev_conf_env_off(sections[i], NULL)) { mtevL(mtev_debug, "generic module %s environmentally disabled.\n", g_name); continue; } gen = (mtev_dso_generic_t *) mtev_load_generic_image(&__mtev_image_loader, g_name, sections[i]); if(!gen) { mtevL(mtev_stderr, "Failed to load generic %s\n", g_name); mtev_dso_load_failure_count++; continue; } if(gen->config) { int rv; mtev_hash_table *config; include_sections = mtev_conf_get_sections(sections[i], "include", §ion_cnt); if ((include_sections) && (section_cnt == 1)) { config = mtev_conf_get_hash(*include_sections, "config"); } else { config = mtev_conf_get_hash(sections[i], "config"); } mtev_conf_release_sections(include_sections, section_cnt); rv = gen->config(gen, config); if(rv == 0) { mtev_hash_destroy(config, free, free); free(config); } else if(rv < 0) { mtevL(mtev_stderr, "Failed to config generic %s\n", g_name); continue; } } if(gen->init && gen->init(gen)) { mtevL(mtev_stderr, "Failed to init generic %s\n", g_name); mtev_dso_load_failure_count++; } else mtevL(mtev_debug, "Generic module %s successfully loaded.\n", g_name); } mtev_conf_release_sections(sections, cnt); /* Load our module loaders */ sections = mtev_conf_get_sections(MTEV_CONF_ROOT, "//modules//loader", &cnt); for(i=0; i<cnt; i++) { char loader_name[256]; mtev_dso_loader_t *loader; mtev_conf_section_t *include_sections = NULL; int section_cnt; if(!mtev_conf_get_stringbuf(sections[i], "ancestor-or-self::node()/@name", loader_name, sizeof(loader_name))) { mtevL(mtev_stderr, "No name defined in loader stanza %d\n", i+1); continue; } if(mtev_conf_env_off(sections[i], NULL)) { mtevL(mtev_debug, "loader %s environmentally disabled.\n", loader_name); continue; } loader = (mtev_dso_loader_t *) mtev_load_loader_image(&__mtev_image_loader, loader_name, sections[i]); if(!loader) { mtevL(mtev_stderr, "Failed to load loader %s\n", loader_name); mtev_dso_load_failure_count++; continue; } if(loader->config) { int rv; mtev_hash_table *config; include_sections = mtev_conf_get_sections(sections[i], "include", §ion_cnt); if ((include_sections) && (section_cnt == 1)) { config = mtev_conf_get_hash(*include_sections, "config"); } else { config = mtev_conf_get_hash(sections[i], "config"); } mtev_conf_release_sections(include_sections, section_cnt); rv = loader->config(loader, config); if(rv == 0) { mtev_hash_destroy(config, free, free); free(config); } else if(rv < 0) { mtevL(mtev_stderr, "Failed to config loader %s\n", loader_name); mtev_dso_load_failure_count++; continue; } } if(loader->init && loader->init(loader)) mtevL(mtev_stderr, "Failed to init loader %s\n", loader_name); } mtev_conf_release_sections(sections, cnt); }
void noit_check_resolver_init() { int cnt; mtev_conf_section_t *servers, *searchdomains; eventer_t e; if(dns_init(NULL, 0) < 0) mtevL(noit_error, "dns initialization failed.\n"); dns_ctx = dns_new(NULL); if(dns_init(dns_ctx, 0) != 0) { mtevL(noit_error, "dns initialization failed.\n"); exit(-1); } /* Optional servers */ servers = mtev_conf_get_sections(NULL, "//resolver//server", &cnt); if(cnt) { int i; char server[128]; dns_add_serv(dns_ctx, NULL); /* reset */ for(i=0;i<cnt;i++) { if(mtev_conf_get_stringbuf(servers[i], "self::node()", server, sizeof(server))) { if(dns_add_serv(dns_ctx, server) < 0) { mtevL(noit_error, "Failed adding DNS server: %s\n", server); } } } free(servers); } searchdomains = mtev_conf_get_sections(NULL, "//resolver//search", &cnt); if(cnt) { int i; char search[128]; dns_add_srch(dns_ctx, NULL); /* reset */ for(i=0;i<cnt;i++) { if(mtev_conf_get_stringbuf(searchdomains[i], "self::node()", search, sizeof(search))) { if(dns_add_srch(dns_ctx, search) < 0) { mtevL(noit_error, "Failed adding DNS search path: %s\n", search); } else if(dns_search_flag) dns_search_flag = 0; /* enable search */ } } free(searchdomains); } if(mtev_conf_get_int(NULL, "//resolver/@ndots", &cnt)) dns_set_opt(dns_ctx, DNS_OPT_NDOTS, cnt); if(mtev_conf_get_int(NULL, "//resolver/@ntries", &cnt)) dns_set_opt(dns_ctx, DNS_OPT_NTRIES, cnt); if(mtev_conf_get_int(NULL, "//resolver/@timeout", &cnt)) dns_set_opt(dns_ctx, DNS_OPT_TIMEOUT, cnt); if(dns_open(dns_ctx) < 0) { mtevL(noit_error, "dns open failed.\n"); exit(-1); } eventer_name_callback("dns_cache_callback", dns_cache_callback); dns_set_tmcbck(dns_ctx, dns_cache_utm_fn, dns_ctx); e = eventer_alloc(); e->mask = EVENTER_READ | EVENTER_EXCEPTION; e->closure = dns_ctx; e->callback = dns_cache_callback; e->fd = dns_sock(dns_ctx); eventer_add(e); mtev_skiplist_init(&nc_dns_cache); mtev_skiplist_set_compare(&nc_dns_cache, name_lookup, name_lookup_k); mtev_skiplist_add_index(&nc_dns_cache, refresh_idx, refresh_idx_k); /* maybe load it from cache */ if(noit_resolver_cache_load_hook_exists()) { struct timeval now; char *key; void *data; int len; gettimeofday(&now, NULL); while(noit_resolver_cache_load_hook_invoke(&key, &data, &len) == MTEV_HOOK_CONTINUE) { dns_cache_node *n; n = calloc(1, sizeof(*n)); if(dns_cache_node_deserialize(n, data, len) >= 0) { n->target = strdup(key); /* if the TTL indicates that it will expire in less than 60 seconds * (including stuff that should have already expired), then fudge * the last_updated time to make it expire some random time within * the next 60 seconds. */ if(n->last_needed > now.tv_sec || n->last_updated > now.tv_sec) break; /* impossible */ n->last_needed = now.tv_sec; if(n->last_updated + n->ttl < now.tv_sec + 60) { int fudge = MIN(60, n->ttl) + 1; n->last_updated = now.tv_sec - n->ttl + (lrand48() % fudge); } DCLOCK(); mtev_skiplist_insert(&nc_dns_cache, n); DCUNLOCK(); n = NULL; } else { mtevL(noit_error, "Failed to deserialize resolver cache record.\n"); } if(n) dns_cache_node_free(n); if(key) free(key); if(data) free(data); } } noit_check_resolver_loop(NULL, 0, NULL, NULL); register_console_dns_cache_commands(); mtev_hash_init(&etc_hosts_cache); noit_check_etc_hosts_cache_refresh(NULL, 0, NULL, NULL); }
int mtev_main(const char *appname, const char *config_filename, int debug, int foreground, mtev_lock_op_t lock, const char *_glider, const char *drop_to_user, const char *drop_to_group, int (*passed_child_main)(void)) { mtev_conf_section_t watchdog_conf; int fd, lockfd, watchdog_timeout = 0, rv; int wait_for_lock; char conf_str[1024]; char lockfile[PATH_MAX]; char *trace_dir = NULL; char appscratch[1024]; char *glider = (char *)_glider; char *watchdog_timeout_str; int retry_val; int span_val; int ret; int cnt; mtev_conf_section_t root; wait_for_lock = (lock == MTEV_LOCK_OP_WAIT) ? 1 : 0; mtev_init_globals(); char *require_invariant_tsc = getenv("MTEV_RDTSC_REQUIRE_INVARIANT"); if (require_invariant_tsc && strcmp(require_invariant_tsc, "0") == 0) { mtev_time_toggle_require_invariant_tsc(mtev_false); } char *disable_rdtsc = getenv("MTEV_RDTSC_DISABLE"); if (disable_rdtsc && strcmp(disable_rdtsc, "1") == 0) { mtev_time_toggle_tsc(mtev_false); } char *disable_binding = getenv("MTEV_THREAD_BINDING_DISABLE"); if (disable_binding && strcmp(disable_binding, "1") == 0) { mtev_thread_disable_binding(); } /* First initialize logging, so we can log errors */ mtev_log_init(debug); mtev_log_stream_add_stream(mtev_debug, mtev_stderr); mtev_log_stream_add_stream(mtev_error, mtev_stderr); mtev_log_stream_add_stream(mtev_notice, mtev_error); /* Next load the configs */ mtev_conf_use_namespace(appname); mtev_conf_init(appname); if(mtev_conf_load(config_filename) == -1) { fprintf(stderr, "Cannot load config: '%s'\n", config_filename); exit(-1); } char* root_section_path = alloca(strlen(appname)+2); sprintf(root_section_path, "/%s", appname); root = mtev_conf_get_sections(NULL, root_section_path, &cnt); free(root); if(cnt==0) { fprintf(stderr, "The config must have <%s> as its root node\n", appname); exit(-1); } /* Reinitialize the logging system now that we have a config */ mtev_conf_log_init(appname, drop_to_user, drop_to_group); if(debug) { mtev_log_stream_set_flags(mtev_debug, mtev_log_stream_get_flags(mtev_debug) | MTEV_LOG_STREAM_ENABLED); } cli_log_switches(); snprintf(appscratch, sizeof(appscratch), "/%s/watchdog|/%s/include/watchdog", appname, appname); watchdog_conf = mtev_conf_get_section(NULL, appscratch); if(!glider) (void) mtev_conf_get_string(watchdog_conf, "@glider", &glider); if(mtev_watchdog_glider(glider)) { mtevL(mtev_stderr, "Invalid glider, exiting.\n"); exit(-1); } (void)mtev_conf_get_string(watchdog_conf, "@tracedir", &trace_dir); if(trace_dir) { if(mtev_watchdog_glider_trace_dir(trace_dir)) { mtevL(mtev_stderr, "Invalid glider tracedir, exiting.\n"); exit(-1); } } ret = mtev_conf_get_int(watchdog_conf, "@retries", &retry_val); if((ret == 0) || (retry_val == 0)) { retry_val = 5; } ret = mtev_conf_get_int(watchdog_conf, "@span", &span_val); if((ret == 0) || (span_val == 0)) { span_val = 60; } mtev_watchdog_ratelimit(retry_val, span_val); /* Lastly, run through all other system inits */ snprintf(appscratch, sizeof(appscratch), "/%s/eventer/@implementation", appname); if(!mtev_conf_get_stringbuf(NULL, appscratch, conf_str, sizeof(conf_str))) { mtevL(mtev_stderr, "Cannot find '%s' in configuration\n", appscratch); exit(-1); } if(eventer_choose(conf_str) == -1) { mtevL(mtev_stderr, "Cannot choose eventer %s\n", conf_str); exit(-1); } if(configure_eventer(appname) != 0) { mtevL(mtev_stderr, "Cannot configure eventer\n"); exit(-1); } mtev_watchdog_prefork_init(); if(foreground != 1 && chdir("/") != 0) { mtevL(mtev_stderr, "Failed chdir(\"/\"): %s\n", strerror(errno)); exit(-1); } /* Acquire the lock so that we can throw an error if it doesn't work. * If we've started -D, we'll have the lock. * If not we will daemon and must reacquire the lock. */ lockfd = -1; lockfile[0] = '\0'; snprintf(appscratch, sizeof(appscratch), "/%s/@lockfile", appname); if(lock != MTEV_LOCK_OP_NONE && mtev_conf_get_stringbuf(NULL, appscratch, lockfile, sizeof(lockfile))) { do { if((lockfd = mtev_lockfile_acquire(lockfile)) < 0) { if(!wait_for_lock) { mtevL(mtev_stderr, "Failed to acquire lock: %s\n", lockfile); exit(-1); } if(wait_for_lock == 1) { mtevL(mtev_stderr, "%d failed to acquire lock(%s), waiting...\n", (int)getpid(), lockfile); wait_for_lock++; } usleep(1000); } else { if(wait_for_lock > 1) mtevL(mtev_stderr, "Lock acquired proceeding.\n"); wait_for_lock = 0; } } while(wait_for_lock); } if(foreground == 1) { mtev_time_start_tsc(); mtevL(mtev_notice, "%s booting [unmanaged]\n", appname); int rv = passed_child_main(); mtev_lockfile_release(lockfd); return rv; } watchdog_timeout_str = getenv("WATCHDOG_TIMEOUT"); if(watchdog_timeout_str) { watchdog_timeout = atoi(watchdog_timeout_str); mtevL(mtev_error, "Setting watchdog timeout to %d\n", watchdog_timeout); } /* This isn't inherited across forks... */ if(lockfd >= 0) mtev_lockfile_release(lockfd); lockfd = -1; if(foreground == 0) { fd = open("/dev/null", O_RDONLY); if(fd < 0 || dup2(fd, STDIN_FILENO) < 0) { fprintf(stderr, "Failed to setup stdin: %s\n", strerror(errno)); exit(-1); } close(fd); fd = open("/dev/null", O_WRONLY); if(fd < 0 || dup2(fd, STDOUT_FILENO) < 0 || dup2(fd, STDERR_FILENO) < 0) { fprintf(stderr, "Failed to setup std{out,err}: %s\n", strerror(errno)); exit(-1); } close(fd); if(fork()) exit(0); setsid(); if(fork()) exit(0); } /* Reacquire the lock */ if(*lockfile) { if (lock) { if((lockfd = mtev_lockfile_acquire(lockfile)) < 0) { mtevL(mtev_stderr, "Failed to acquire lock: %s\n", lockfile); exit(-1); } } } signal(SIGHUP, SIG_IGN); mtevL(mtev_notice, "%s booting\n", appname); rv = mtev_watchdog_start_child(appname, passed_child_main, watchdog_timeout); mtev_lockfile_release(lockfd); return rv; }
int noit_filtersets_cull_unused() { mtev_hash_table active = MTEV_HASH_EMPTY; char *buffer = NULL; mtev_conf_section_t *declares; int i, n_uses = 0, n_declares = 0, removed = 0; const char *declare_xpath = "//filterset[@name and not (@cull='false')]"; declares = mtev_conf_get_sections(NULL, declare_xpath, &n_declares); if(declares) { /* store all unit filtersets used */ for(i=0;i<n_declares;i++) { if(!buffer) buffer = malloc(128); if(mtev_conf_get_stringbuf(declares[i], "@name", buffer, 128)) { if(mtev_hash_store(&active, buffer, strlen(buffer), declares[i])) { buffer = NULL; } else { void *vnode = NULL; /* We've just hit a duplicate.... check to see if there's an existing * entry and if there is, load the latest one and delete the old * one. */ mtev_hash_retrieve(&active, buffer, strlen(buffer), &vnode); if (vnode) { noit_filter_compile_add(declares[i]); CONF_REMOVE(vnode); xmlUnlinkNode(vnode); xmlFreeNode(vnode); removed++; if(mtev_hash_replace(&active, buffer, strlen(buffer), declares[i], free, NULL)) { buffer = NULL; } } } } } if(buffer) free(buffer); free(declares); } n_uses = noit_poller_do(filterset_accum, &active); if(n_uses > 0 && mtev_hash_size(&active) > 0) { mtev_hash_iter iter = MTEV_HASH_ITER_ZERO; const char *filter_name; int filter_name_len; void *vnode; while(mtev_hash_next(&active, &iter, &filter_name, &filter_name_len, &vnode)) { if(noit_filter_remove(vnode)) { CONF_REMOVE(vnode); xmlUnlinkNode(vnode); xmlFreeNode(vnode); removed++; } } } mtev_hash_destroy(&active, free, NULL); return removed; }
void noit_filter_compile_add(mtev_conf_section_t setinfo) { mtev_conf_section_t *rules; int j, fcnt; char filterset_name[256]; filterset_t *set; if(!mtev_conf_get_stringbuf(setinfo, "@name", filterset_name, sizeof(filterset_name))) { mtevL(noit_error, "filterset with no name, skipping as it cannot be referenced.\n"); return; } set = calloc(1, sizeof(*set)); set->ref_cnt = 1; set->name = strdup(filterset_name); rules = mtev_conf_get_sections(setinfo, "rule", &fcnt); /* Here we will work through the list backwards pushing the rules on * the front of the list. That way we can simply walk them in order * for the application process. */ mtevL(noit_debug, "Compiling filterset '%s'\n", set->name); for(j=fcnt-1; j>=0; j--) { filterrule_t *rule; char buffer[256]; if(!mtev_conf_get_stringbuf(rules[j], "@type", buffer, sizeof(buffer)) || (strcmp(buffer, "accept") && strcmp(buffer, "allow") && strcmp(buffer, "deny") && strncmp(buffer, "skipto:", strlen("skipto:")))) { mtevL(noit_error, "rule must have type 'accept' or 'allow' or 'deny' or 'skipto:'\n"); continue; } mtevL(noit_debug, "Prepending %s into %s\n", buffer, set->name); rule = calloc(1, sizeof(*rule)); if(!strncasecmp(buffer, "skipto:", strlen("skipto:"))) { rule->type = NOIT_FILTER_SKIPTO; rule->skipto = strdup(buffer+strlen("skipto:")); } else { rule->type = (!strcmp(buffer, "accept") || !strcmp(buffer, "allow")) ? NOIT_FILTER_ACCEPT : NOIT_FILTER_DENY; } if(mtev_conf_get_stringbuf(rules[j], "@id", buffer, sizeof(buffer))) { rule->ruleid = strdup(buffer); } /* Compile any hash tables, should they exist */ #define HT_COMPILE(rname) do { \ mtev_conf_section_t *htentries; \ int hte_cnt, hti, tablesize = 2, auto_max = 0; \ char *htstr; \ htentries = mtev_conf_get_sections(rules[j], #rname, &hte_cnt); \ mtev_conf_get_int(rules[j], "@" #rname "_auto_add", &auto_max); \ if(hte_cnt || auto_max > 0) { \ rule->rname##_auto_hash_max = auto_max; \ rule->rname##_ht = calloc(1, sizeof(*(rule->rname##_ht))); \ while(tablesize < hte_cnt) tablesize <<= 1; \ mtev_hash_init_size(rule->rname##_ht, tablesize); \ for(hti=0; hti<hte_cnt; hti++) { \ if(!mtev_conf_get_string(htentries[hti], "self::node()", &htstr)) \ mtevL(noit_error, "Error fetching text content from filter match.\n"); \ else \ mtev_hash_replace(rule->rname##_ht, htstr, strlen(htstr), NULL, free, NULL); \ } \ } \ free(htentries); \ } while(0); HT_COMPILE(target); HT_COMPILE(module); HT_COMPILE(name); HT_COMPILE(metric); /* Compile our rules */ #define RULE_COMPILE(rname) do { \ char *longre = NULL; \ if(mtev_conf_get_string(rules[j], "@" #rname, &longre)) { \ const char *error; \ int erroffset; \ rule->rname = pcre_compile(longre, 0, &error, &erroffset, NULL); \ if(!rule->rname) { \ mtevL(noit_debug, "set '%s' rule '%s: %s' compile failed: %s\n", \ set->name, #rname, longre, error ? error : "???"); \ rule->rname##_override = fallback_no_match; \ } \ else { \ rule->rname##_e = pcre_study(rule->rname, 0, &error); \ } \ free(longre); \ } \ } while(0) if(rule->target_ht == NULL) RULE_COMPILE(target); if(rule->module_ht == NULL) RULE_COMPILE(module); if(rule->name_ht == NULL) RULE_COMPILE(name); if(rule->metric_ht == NULL) RULE_COMPILE(metric); rule->next = set->rules; set->rules = rule; } filterrule_t *cursor; for(cursor = set->rules; cursor->next; cursor = cursor->next) { if(cursor->skipto) { filterrule_t *target; for(target = cursor->next; target; target = target->next) { if(target->ruleid && !strcmp(cursor->skipto, target->ruleid)) { cursor->skipto_rule = target; break; } } if(!cursor->skipto_rule) mtevL(noit_error, "filterset %s skipto:%s not found\n", set->name, cursor->skipto); } } free(rules); LOCKFS(); mtev_hash_replace(filtersets, set->name, strlen(set->name), (void *)set, NULL, filterset_free); UNLOCKFS(); }