static xmlNodePtr make_conf_path(char *path) { xmlNodePtr start, tmp; char fullpath[1024], *tok, *brk; if(!path || strlen(path) < 1) return NULL; snprintf(fullpath, sizeof(fullpath), "%s", path+1); fullpath[strlen(fullpath)-1] = '\0'; start = mtev_conf_get_section(NULL, "/noit/filtersets"); if(!start) return NULL; for (tok = strtok_r(fullpath, "/", &brk); tok; tok = strtok_r(NULL, "/", &brk)) { if(!xmlValidateNameValue((xmlChar *)tok)) return NULL; if(!strcmp(tok, "filterset")) return NULL; for (tmp = start->children; tmp; tmp = tmp->next) { if(!strcmp((char *)tmp->name, tok)) break; } if(!tmp) { tmp = xmlNewNode(NULL, (xmlChar *)tok); xmlAddChild(start, tmp); CONF_DIRTY(tmp); } start = tmp; } return start; }
void noit_jlog_listener_init() { xmlNodePtr node; eventer_name_callback("log_transit/1.0", noit_jlog_handler); mtev_control_dispatch_delegate(mtev_control_dispatch, NOIT_JLOG_DATA_FEED, noit_jlog_handler); mtev_control_dispatch_delegate(mtev_control_dispatch, NOIT_JLOG_DATA_TEMP_FEED, noit_jlog_handler); node = mtev_conf_get_section(NULL, "//logs"); if (node) { mtev_conf_get_int(node, "//jlog/max_msg_batch_lines", &MAX_ROWS_AT_ONCE); mtev_conf_get_int(node, "//jlog/default_mseconds_between_batches", &DEFAULT_MSECONDS_BETWEEN_BATCHES); mtev_conf_get_int(node, "//jlog/default_transient_mseconds_between_batches", &DEFAULT_TRANSIENT_MSECONDS_BETWEEN_BATCHES); } mtevAssert(mtev_http_rest_register_auth( "GET", "/", "^feed$", rest_show_feed, mtev_http_rest_client_cert_auth ) == 0); mtevAssert(mtev_http_rest_register_auth( "DELETE", "/feed/", "^(.+)$", rest_delete_feed, mtev_http_rest_client_cert_auth ) == 0); mtevAssert(mtev_http_rest_register_auth( "PUT", "/", "^feed$", rest_add_feed, mtev_http_rest_client_cert_auth ) == 0); }
static int child_main() { int log_flags; mtev_conf_section_t section; char *err = NULL; cli_stdout = mtev_log_stream_new_on_fd("stdout", 1, NULL); log_flags = mtev_log_stream_get_flags(mtev_stderr); log_flags &= ~(MTEV_LOG_STREAM_FACILITY|MTEV_LOG_STREAM_TIMESTAMPS); mtev_log_stream_set_flags(mtev_stderr, log_flags); /* reload our config, to make sure we have the most current */ if(mtev_conf_load(NULL) == -1) { mtevL(mtev_error, "Cannot load config: '%s'\n", config_file); if(needs_unlink) unlink(config_file); exit(2); } mtev_conf_security_init(APPNAME, droptouser, droptogroup, NULL); if(mtev_conf_write_file(&err) != 0) { if(err) { mtevL(mtev_stderr, "Error: '%s'\n", err); free(err); } mtevL(mtev_stderr, "Permissions issue, are you running as the right user?\n"); exit(2); } if(needs_unlink) unlink(config_file); /* update the lua module */ section = mtev_conf_get_section(NULL, "/cli/modules/generic[@name=\"lua_general\"]/config"); if(!section || !mtev_conf_set_string(section, "lua_module", lua_file)) { mtevL(mtev_stderr, "Cannot set target lua module, invalid config.\n"); exit(2); } eventer_init(); mtev_dso_init(); mtev_dso_post_init(); if(mtev_dso_load_failures() > 0) { mtevL(mtev_stderr, "Failed to initialize.\n"); exit(2); } if(interactive) { mtev_console_init(APPNAME); mtev_console_conf_init(APPNAME); eventer_set_fd_nonblocking(STDIN_FILENO); if(mtev_console_std_init(STDIN_FILENO, STDOUT_FILENO)) { mtevL(mtev_stderr, "Failed to initialize IO\n"); exit(2); } } /* Lastly, spin up the event loop */ eventer_loop(); return 0; }
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; }
static mtev_hook_return_t noit_delete_section_impl(void *closure, const char *root, const char *path, const char *name, const char **err) { mtev_hook_return_t rv = MTEV_HOOK_CONTINUE; char xpath[1024]; mtev_conf_section_t exists = NULL; snprintf(xpath, sizeof(xpath), "/%s%s/%s//check", root, path, name); exists = mtev_conf_get_section(NULL, xpath); if(exists) { if(err) *err = "cannot delete section, has checks"; rv = MTEV_HOOK_ABORT; } return rv; }
static int noit_filter_update_conf_rule(const char *fname, int idx, const char *rname, const char *value) { char xpath[1024]; xmlNodePtr rulenode, child; snprintf(xpath, sizeof(xpath), "//filtersets/filterset[@name=\"%s\"]/rule[%d]", fname, idx); rulenode = mtev_conf_get_section(NULL, xpath); if(!rulenode) return -1; child = xmlNewNode(NULL, (xmlChar *)rname); xmlNodeAddContent(child, (xmlChar *)value); xmlAddChild(rulenode, child); CONF_DIRTY(rulenode); mtev_conf_mark_changed(); mtev_conf_request_write(); return 0; }
static int rest_show_filter(mtev_http_rest_closure_t *restc, int npats, char **pats) { mtev_http_session_ctx *ctx = restc->http_ctx; xmlDocPtr doc = NULL; xmlNodePtr node, root; char xpath[1024]; int error_code = 500; if(npats != 2) goto error; snprintf(xpath, sizeof(xpath), "//filtersets%sfilterset[@name=\"%s\"]", pats[0], pats[1]); node = mtev_conf_get_section(NULL, xpath); if(!node) goto not_found; doc = xmlNewDoc((xmlChar *)"1.0"); root = xmlCopyNode(node, 1); xmlDocSetRootElement(doc, root); mtev_http_response_ok(ctx, "text/xml"); mtev_http_response_xml(ctx, doc); mtev_http_response_end(ctx); goto cleanup; not_found: mtev_http_response_not_found(ctx, "text/html"); mtev_http_response_end(ctx); goto cleanup; error: mtev_http_response_standard(ctx, error_code, "ERROR", "text/html"); mtev_http_response_end(ctx); goto cleanup; cleanup: if(doc) xmlFreeDoc(doc); return 0; }
static int rest_delete_filter(mtev_http_rest_closure_t *restc, int npats, char **pats) { mtev_http_session_ctx *ctx = restc->http_ctx; xmlNodePtr node; char xpath[1024]; int error_code = 500; if(npats != 2) goto error; snprintf(xpath, sizeof(xpath), "//filtersets%sfilterset[@name=\"%s\"]", pats[0], pats[1]); node = mtev_conf_get_section(NULL, xpath); if(!node) goto not_found; if(noit_filter_remove(node) == 0) goto not_found; CONF_REMOVE(node); xmlUnlinkNode(node); xmlFreeNode(node); if(mtev_conf_write_file(NULL) != 0) mtevL(noit_error, "local config write failed\n"); mtev_conf_mark_changed(); mtev_http_response_ok(ctx, "text/html"); mtev_http_response_end(ctx); goto cleanup; not_found: mtev_http_response_not_found(ctx, "text/html"); mtev_http_response_end(ctx); goto cleanup; error: mtev_http_response_standard(ctx, error_code, "ERROR", "text/html"); mtev_http_response_end(ctx); goto cleanup; cleanup: return 0; }
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; }
noit_check_t * noit_fire_check(xmlNodePtr attr, xmlNodePtr config, const char **error) { char *target = NULL, *name = NULL, *module = NULL, *filterset = NULL; char *resolve_rtype = NULL; int timeout = 0, flags = NP_TRANSIENT, i, mod_cnt; noit_module_t *m = NULL; noit_check_t *c = NULL; xmlNodePtr a, co; mtev_hash_table *conf_hash = NULL; mtev_hash_table **moptions = NULL; for(a = attr->children; a; a = a->next) { if(!strcmp((char *)a->name, "target")) target = (char *)xmlNodeGetContent(a); else if(!strcmp((char *)a->name, "name")) name = (char *)xmlNodeGetContent(a); else if(!strcmp((char *)a->name, "module")) module = (char *)xmlNodeGetContent(a); else if(!strcmp((char *)a->name, "filterset")) filterset = (char *)xmlNodeGetContent(a); else if(!strcmp((char *)a->name, "timeout")) { char *timeout_str = (char *)xmlNodeGetContent(a); timeout = atoi(timeout_str); free(timeout_str); } else if(!strcmp((char *)a->name, "resolve_rtype")) resolve_rtype = (char *)xmlNodeGetContent(a); } if(!noit_check_validate_target(target)) { *error = "malformed target"; goto error; } if(!noit_check_validate_name(name)) { *error = "malformed name"; goto error; } if(module) m = noit_module_lookup(module); if(!m) { *error = "cannot find requested module"; goto error; } conf_hash = calloc(1, sizeof(*conf_hash)); if(config) { for(co = config->children; co; co = co->next) { char *name, *val; xmlChar *tmp_val; name = strdup((char *)co->name); tmp_val = xmlNodeGetContent(co); val = strdup(tmp_val ? (char *)tmp_val : ""); mtev_hash_replace(conf_hash, name, strlen(name), val, free, free); xmlFree(tmp_val); } } mod_cnt = noit_check_registered_module_cnt(); if(mod_cnt > 0) { moptions = alloca(mod_cnt * sizeof(*moptions)); memset(moptions, 0, mod_cnt * sizeof(*moptions)); for(i=0; i<mod_cnt; i++) { const char *name; mtev_conf_section_t checks; name = noit_check_registered_module(i); checks = mtev_conf_get_section(NULL, "/noit/checks"); if(name) moptions[i] = mtev_conf_get_namespaced_hash(checks, "config", name); } } if(!m->initiate_check) { *error = "that module cannot run checks"; goto error; } flags |= noit_calc_rtype_flag(resolve_rtype); c = mtev_memory_safe_calloc(1, sizeof(*c)); c->module = strdup(module); c->flags = NP_TRANSIENT; noit_check_update(c, target, name, filterset, conf_hash, moptions, 0, timeout, NULL, 0, flags); uuid_generate(c->checkid); c->flags |= NP_DISABLED; /* this is hack to know we haven't run it yet */ if(NOIT_CHECK_SHOULD_RESOLVE(c)) noit_check_resolve(c); error: if(conf_hash) { mtev_hash_destroy(conf_hash, free, free); free(conf_hash); } if(moptions) { for(i=0; i<mod_cnt; i++) { if(moptions[i]) { mtev_hash_destroy(moptions[i], free, free); free(moptions[i]); } } } if(target) xmlFree(target); if(name) xmlFree(name); if(module) xmlFree(module); if(filterset) xmlFree(filterset); if(resolve_rtype) xmlFree(resolve_rtype); return c; }
static int rest_set_filter(mtev_http_rest_closure_t *restc, int npats, char **pats) { mtev_http_session_ctx *ctx = restc->http_ctx; xmlDocPtr doc = NULL, indoc = NULL; xmlNodePtr node, parent, root, newfilter; char xpath[1024]; int error_code = 500, complete = 0, mask = 0; const char *error = "internal error"; if(npats != 2) goto error; indoc = rest_get_xml_upload(restc, &mask, &complete); if(!complete) return mask; if(indoc == NULL) FAIL("xml parse error"); snprintf(xpath, sizeof(xpath), "//filtersets%sfilterset[@name=\"%s\"]", pats[0], pats[1]); node = mtev_conf_get_section(NULL, xpath); if(!node && noit_filter_exists(pats[1])) { /* It's someone else's */ error_code = 403; goto error; } if((newfilter = validate_filter_post(indoc)) == NULL) goto error; xmlSetProp(newfilter, (xmlChar *)"name", (xmlChar *)pats[1]); parent = make_conf_path(pats[0]); if(!parent) FAIL("invalid path"); if(node) { xmlUnlinkNode(node); xmlFreeNode(node); } xmlUnlinkNode(newfilter); xmlAddChild(parent, newfilter); CONF_DIRTY(newfilter); mtev_conf_mark_changed(); if(mtev_conf_write_file(NULL) != 0) mtevL(noit_error, "local config write failed\n"); noit_filter_compile_add(newfilter); if(restc->call_closure_free) restc->call_closure_free(restc->call_closure); restc->call_closure_free = NULL; restc->call_closure = NULL; restc->fastpath = rest_show_filter; return restc->fastpath(restc, restc->nparams, restc->params); error: mtev_http_response_standard(ctx, error_code, "ERROR", "text/html"); doc = xmlNewDoc((xmlChar *)"1.0"); root = xmlNewDocNode(doc, NULL, (xmlChar *)"error", NULL); xmlDocSetRootElement(doc, root); xmlNodeAddContent(root, (xmlChar *)error); mtev_http_response_xml(ctx, doc); mtev_http_response_end(ctx); goto cleanup; cleanup: if(doc) xmlFreeDoc(doc); return 0; }
static int noit_console_filter_configure(mtev_console_closure_t ncct, int argc, char **argv, mtev_console_state_t *state, void *closure) { xmlNodePtr parent, fsnode = NULL; int rv = -1; mtev_conf_t_userdata_t *info; char xpath[1024]; info = mtev_console_userdata_get(ncct, MTEV_CONF_T_USERDATA); if(!info) { nc_printf(ncct, "internal error\n"); goto cleanup; } if(strncmp(info->path, "/filtersets/", strlen("/filtersets/")) && strcmp(info->path, "/filtersets")) { nc_printf(ncct, "filterset only allows inside /filtersets (not %s)\n", info->path); goto cleanup; } if(argc != 1) { nc_printf(ncct, "filterset requires one argument\n"); goto cleanup; } snprintf(xpath, sizeof(xpath), "/%s", info->path); parent = mtev_conf_get_section(NULL, xpath); if(!parent) { nc_printf(ncct, "internal error, can't final current working path\n"); goto cleanup; } snprintf(xpath, sizeof(xpath), "filterset[@name=\"%s\"]", argv[0]); fsnode = mtev_conf_get_section(parent, xpath); if(closure) { int removed; removed = noit_filter_remove(fsnode); nc_printf(ncct, "%sremoved filterset '%s'\n", removed ? "" : "failed to ", argv[0]); if(removed) { CONF_REMOVE(fsnode); xmlUnlinkNode(fsnode); xmlFreeNode(fsnode); } rv = !removed; goto cleanup; } if(!fsnode) { void *vfs; nc_printf(ncct, "Cannot find filterset '%s'\n", argv[0]); LOCKFS(); if(mtev_hash_retrieve(filtersets, argv[0], strlen(argv[0]), &vfs)) { UNLOCKFS(); nc_printf(ncct, "filter of the same name already exists\n"); goto cleanup; } UNLOCKFS(); /* Fine the parent path */ fsnode = xmlNewNode(NULL, (xmlChar *)"filterset"); xmlSetProp(fsnode, (xmlChar *)"name", (xmlChar *)argv[0]); xmlAddChild(parent, fsnode); nc_printf(ncct, "created new filterset\n"); } if(info) { char *xmlpath = NULL; free(info->path); xmlpath = (char *)xmlGetNodePath(fsnode); info->path = strdup(xmlpath + strlen("/noit")); free(xmlpath); strlcpy(info->filter_name, argv[0], sizeof(info->filter_name)); if(state) { mtev_console_state_push_state(ncct, state); mtev_console_state_init(ncct); } } cleanup: return rv; }
static int noit_console_rule_configure(mtev_console_closure_t ncct, int argc, char **argv, mtev_console_state_t *state, void *closure) { xmlNodePtr fsnode = NULL; mtev_conf_t_userdata_t *info; char xpath[1024]; 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"); return -1; } if(closure) { int rulenum; xmlNodePtr byebye; /* removing a rule */ if(argc != 1) { nc_printf(ncct, "requires one argument\n"); return -1; } rulenum = atoi(argv[0]); snprintf(xpath, sizeof(xpath), "rule[%d]", rulenum); byebye = mtev_conf_get_section(fsnode, xpath); if(!byebye) { nc_printf(ncct, "cannot find rule\n"); return -1; } xmlUnlinkNode(byebye); xmlFreeNode(byebye); nc_printf(ncct, "removed\n"); } else { xmlNodePtr (*add_func)(xmlNodePtr, xmlNodePtr); xmlNodePtr add_arg, new_rule; int i, needs_type = 1; if(argc < 1 || argc % 2) { nc_printf(ncct, "even number of arguments required\n"); return -1; } if(!strcmp(argv[0], "before") || !strcmp(argv[0], "after")) { int rulenum = atoi(argv[1]); snprintf(xpath, sizeof(xpath), "rule[%d]", rulenum); add_arg = mtev_conf_get_section(fsnode, xpath); if(!add_arg) { nc_printf(ncct, "%s rule not found\n", xpath); return -1; } if(*argv[0] == 'b') add_func = xmlAddPrevSibling; else add_func = xmlAddNextSibling; argc -= 2; argv += 2; } else { add_func = xmlAddChild; add_arg = fsnode; } for(i=0;i<argc;i+=2) { if(!strcmp(argv[i], "type")) needs_type = 0; else if(strcmp(argv[i], "target") && strcmp(argv[i], "module") && strcmp(argv[i], "name") && strcmp(argv[i], "metric") && strcmp(argv[i], "id")) { nc_printf(ncct, "unknown attribute '%s'\n", argv[i]); return -1; } } if(needs_type) { nc_printf(ncct, "type <allow|deny> is required\n"); return -1; } new_rule = xmlNewNode(NULL, (xmlChar *)"rule"); for(i=0;i<argc;i+=2) xmlSetProp(new_rule, (xmlChar *)argv[i], (xmlChar *)argv[i+1]); add_func(add_arg, new_rule); noit_filter_compile_add((mtev_conf_section_t *)fsnode); } return 0; }