/*- * Copyright (c) 2004 Andrey Simonenko * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "config.h" #ifndef lint static const char rcsid[] ATTR_UNUSED = "@(#)$Id: ipastat_conf.c,v 1.1.4.6 2007/05/11 16:29:59 simon Exp $"; #endif /* !lint */ #include #include #include #include #include #include #include #include #include #include #include #include #include "ipa_mod.h" #include "dlapi.h" #include "confcommon.h" #include "memfunc.h" #include "parser.h" #include "pathnames.h" #include "ipastat_conf.h" #include "ipastat_log.h" #include "ipastat_rules.h" #include "ipastat_st.h" #include "ipastat_main.h" char *ipastat_conf_file = IPASTAT_CONF_FILE; /* -f */ int mimic_real_config = 0; /* 1, if -tt. */ static u_int section; /* Current section ID. */ static int global_section_set; /* 1, if has global{}. */ static regex_t reg_list; static struct rule *currule; /* Current rule. */ static struct rulepat *currulepat; /* Current rulepat. */ static u_int rulepatno = 0; static int posix_re_pattern; /* posix_re_pattern parameter. */ #ifdef WITH_LIMITS static struct limit *curlimit; /* Current limit. */ static u_int limitno; /* Order number of the current limit. */ static struct limits_list *limits_list; #endif #ifdef WITH_THRESHOLDS static struct threshold *curthreshold; /* Current threshold. */ static u_int thresholdno; /* Order number of the current threshold. */ static struct thresholds_list *thresholds_list; #endif /* Macro for validating if empty STAILQ_HEAD is in consistent state. */ #define STAILQ_EMPTY_HEAD_VALID(x) \ ((x)->stqh_first == NULL && (x)->stqh_last == &(x)->stqh_first) /* * Exported support functions for modules. */ static const ipa_suppfunc suppfunc = { print_string, /* print_string */ print_bytes, /* print_bytes */ print_time, /* print_time */ print_value, /* print_value */ print_boolean, /* print_boolean */ print_space, /* print_space */ set_indent, /* set_indent */ print_param_name, /* print_param_name */ print_args, /* print_param_args */ print_param_end, /* print_param_end */ print_sect_name, /* print_sect_name */ print_args, /* print_sect_args */ print_sect_begin, /* print_sect_begin */ print_sect_end, /* print_sect_end */ open_close_log, /* open_log */ open_close_log, /* close_log */ mod_logmsg, /* logmsg */ mod_logconferr, /* logconferr */ parser_local_sym_add, /* local_sym_add */ parser_local_sym_del, /* local_sym_del */ parser_global_sym_add, /* global_sym_add */ parser_global_sym_del /* global_sym_del */ }; void conferrx(const char *, ...) ATTR_FORMAT(printf, 1, 2); static void confvlogmsgx_prefix(int, const char *, const char *, va_list) ATTR_FORMAT(printf, 3, 0); /* * Log message prepending it with prefix. * If use_log == 1 then log is used, else printf(3) is used. * Don't use mem_* functions. */ static void confvlogmsgx_prefix(int priority, const char *prefix, const char *format, va_list ap) { int rv; char *ptr; char buf[LOG_BUF_SIZE]; /* Try to use buffer in stack. */ if ( (rv = vsnprintf(buf, sizeof buf, format, ap)) < 0) { logmsg(IPA_LOG_ERR, "confvlogmsgx_prefix: vsnprintf failed"); goto log_unformated; } if (rv >= sizeof buf) { if ( (ptr = malloc(++rv)) == NULL) { logmsgx(IPA_LOG_ERR, "confvlogmsgx_prefix: malloc failed"); goto log_unformated; } if (vsnprintf(ptr, rv, format, ap) < 0) { logmsg(IPA_LOG_ERR, "confvlogmsgx_prefix: vsnprintf failed again"); free(ptr); goto log_unformated; } logmsgx(priority, "%s: %s", prefix, ptr); free(ptr); } else logmsgx(priority, "%s: %s", prefix, buf); return; log_unformated: logmsgx(priority, "%s: unformated message: %s", prefix, format); } /* * The wrapper for parser_vlogmsgx. */ static void parser_vlogmsgx_wrapper(const char *format, va_list ap) { confvlogmsgx_prefix(IPA_LOG_ERR, "parsing error", format, ap); } /* * The wrapper for mvlogmsgx during configuration. */ static void mvlogmsgx_conf_wrapper(const char *format, va_list ap) { confvlogmsgx_prefix(IPA_LOG_ERR, "config error", format, ap); } /* * A wrapper for logging about errors. */ void conferrx(const char *format, ...) { va_list ap; va_start(ap, format); confvlogmsgx_prefix(IPA_LOG_ERR, "config error", format, ap); va_end(ap); } /* * The same as above one, but with priority argument and va_list. */ static void vconferrx_priority(int priority, const char *format, va_list ap) { confvlogmsgx_prefix(priority, "config error", format, ap); } /* * Register a configuration event in st_mod module. */ static int st_mod_conf_event(const struct st_mod *st_mod, u_int event, u_int no, const void *arg) { if (st_mod->ipa_st_mod->conf_event(event, no, arg) < 0) { logconferrx("module %s: conf_event(IPA_CONF_EVENT_%s) failed", st_mod->mod_file, conf_event_msg[event]); return -1; } return 0; } /* * Register a configuration event in each module. */ static int mod_conf_event(u_int event, u_int no, const void *arg) { const struct st_mod *st_mod; SLIST_FOREACH(st_mod, &st_mod_list, link) if (st_mod_conf_event(st_mod, event, no, arg) < 0) { conferrx("mod_conf_event: st_mod_conf_event failed"); return -1; } return 0; } /* * Inherit settings from rulepat from modules for rule. */ int mod_conf_inherit(const struct rulepat *rulepat, const struct rule *rule) { const struct st_mod *st_mod; SLIST_FOREACH(st_mod, &st_mod_list, link) { if (st_mod->ipa_st_mod->conf_inherit != NULL) if (st_mod->ipa_st_mod->conf_inherit(rulepat->rulepatno, rule->ruleno, rule->rule_name) < 0) { xlogmsgx(IPA_LOG_ERR, "module %s: conf_inherit(%s, %s) failed", st_mod->mod_file, parser_buf_to_string(rulepat->pat), rule->rule_name); return -1; } } return 0; } /* * Parse the "global" section. */ /* ARGSUSED */ static int parse_global(void *arg ATTR_UNUSED) { if (global_section_set) { logconferrx("this section is duplicated"); return -1; } global_section_set = 1; return mod_conf_event(IPA_CONF_EVENT_GLOBAL_BEGIN, 0, (void *)NULL); } /* * Parse the "rule" section. */ static int parse_rule(void *arg) { const char *rule_name = *(char **)arg; struct rule *rule; if (rule_by_name(rule_name) != NULL) { logconferrx("this section is duplicated"); return -1; } if ( (rule = alloc_rule()) == NULL) { logconferrx("alloc_rule failed"); return -1; } if ( (rule->rule_name = mem_strdup(rule_name, m_anon)) == NULL) { xlogmsgx(IPA_LOG_ERR, "alloc_rule: mem_strdup failed"); return -1; } rule->free_mask = RULE_FREE_NAME; add_rule_to_hash(rule); #ifdef WITH_LIMITS limits_list = &rule->limits; STAILQ_INIT(limits_list); limitno = 0; #endif #ifdef WITH_THRESHOLDS thresholds_list = &rule->thresholds; STAILQ_INIT(thresholds_list); thresholdno = 0; #endif if (parser_local_sym_add("rule", rule->rule_name, 0) < 0) return -1; if (mod_conf_event(IPA_CONF_EVENT_RULE_BEGIN, rule->ruleno, rule->rule_name) < 0) return -1; currule = rule; return 0; } /* * Parse the "dynamic_rules" parameter. */ static int parse_dynamic_rules(void *arg) { dynamic_rules = *(int *)arg; return 0; } /* * Parse the "rulepat" section. */ static int parse_rulepat(void *arg) { char *pat = *(char **)arg; struct rulepat *rulepat; STAILQ_FOREACH(rulepat, &rulepats_list, link) if (strcmp(rulepat->pat, pat) == 0) { logconferrx("this section is duplicated"); return -1; } if ( (rulepat = mzone_alloc(rulepat_mzone)) == NULL) { logconferrx("mzone_alloc failed"); return -1; } STAILQ_INSERT_TAIL(&rulepats_list, rulepat, link); if ( (re_errcode = regcomp(&rulepat->reg, pat, REG_EXTENDED|REG_NOSUB)) != 0) { re_form_errbuf(); logconferrx("regcomp(\"%s\"): %s", pat, re_errbuf); return -1; } rulepat->pat = pat; rulepat->rulepatno = rulepatno++; rulepat->check_next_rulepat = -1; rulepat->st_list = NULL; #ifdef WITH_LIMITS limits_list = &rulepat->limits; STAILQ_INIT(limits_list); limitno = 0; #endif #ifdef WITH_THRESHOLDS thresholds_list = &rulepat->thresholds; STAILQ_INIT(thresholds_list); thresholdno = 0; #endif if (mod_conf_event(IPA_CONF_EVENT_RULEPAT_BEGIN, rulepat->rulepatno, rulepat->pat) < 0) return -1; currulepat = rulepat; return 0; } /* * Parse the "check_next_rulepat" parameter. */ static int parse_check_next_rulepat(void *arg) { currulepat->check_next_rulepat = *(int *)arg; return 0; } #ifdef WITH_LIMITS /* * Parse the "limit" section. */ static int parse_limit(void *arg) { const char *limit_name = *(char **)arg; struct limit *limit; STAILQ_FOREACH(limit, limits_list, link) if (strcmp(limit->limit_name, limit_name) == 0) { logconferrx("this section is duplicated"); return -1; } if ( (limit = alloc_limit()) == NULL) { logconferrx("alloc_limit failed"); return -1; } STAILQ_INSERT_TAIL(limits_list, limit, link); if ( (limit->limit_name = mem_strdup(limit_name, m_anon)) == NULL) { logconferrx("mem_strdup failed"); return -1; } limit->limitno = limitno++; limit->free_mask = LIMIT_FREE_NAME; if (mod_conf_event(IPA_CONF_EVENT_LIMIT_BEGIN, limit->limitno, limit->limit_name) < 0) return -1; curlimit = limit; return 0; } /* * Parse "dynamic_limits" parameter. */ static int parse_dynamic_limits(void *arg) { dynamic_limits = *(int *)arg; return 0; } #endif /* WITH_LIMITS */ #ifdef WITH_THRESHOLDS /* * Parse "threshold" section. */ static int parse_threshold(void *arg) { const char *threshold_name = *(char **)arg; struct threshold *threshold; STAILQ_FOREACH(threshold, thresholds_list, link) if (strcmp(threshold->threshold_name, threshold_name) == 0) { logconferrx("this section is duplicated"); return -1; } if ( (threshold = alloc_threshold()) == NULL) { logconferrx("alloc_threshold failed"); return -1; } STAILQ_INSERT_TAIL(thresholds_list, threshold, link); if ( (threshold->threshold_name = mem_strdup(threshold_name, m_anon)) == NULL) { logconferrx("mem_strdup failed"); return -1; } threshold->thresholdno = thresholdno++; threshold->free_mask = THRESHOLD_FREE_NAME; if (mod_conf_event(IPA_CONF_EVENT_THRESHOLD_BEGIN, threshold->thresholdno, threshold->threshold_name) < 0) return -1; curthreshold = threshold; return 0; } /* * Parse "dynamic_thresholds" parameter. */ static int parse_dynamic_thresholds(void *arg) { dynamic_thresholds = *(int *)arg; return 0; } #endif /* WITH_THRESHOLDS */ /* * Check security of configuration file: absolute path, regular file. */ static int check_conf_file(const char *fname) { struct stat statbuf; if (lstat(fname, &statbuf) < 0) { conferrx("lstat(%s): %s", fname, strerror(errno)); return -1; } if (!S_ISREG(statbuf.st_mode)) { conferrx("configuration file \"%s\" should be a regular file", fname); return -1; } return 0; } /* * Get module's name from the file name "[/path/]foobar[-x.y.z][.so]". * Return "foobar" part from the given path name. */ static char * get_mod_name(char *file_name) { char *ptr, *ptr2, *name; if ( (ptr = strrchr(file_name, '/')) != NULL) ++ptr; /* foobar[-x.y.z].[so] */ else ptr = file_name; if ( (name = mem_strdup(ptr, m_anon)) == NULL) { logconferrx("get_mod_name: mem_strdup failed"); return NULL; } if ( (ptr2 = strchr(name, '.')) != NULL) *ptr2 = '\0'; /* foobar[-x] */ if ( (ptr = strrchr(name, '-')) != NULL) { for (ptr2 = ptr; *ptr2 != '\0'; ++ptr2) if (isdigit(*ptr2) == 0) break; if (*ptr2 == '\0') *ptr = '\0'; /* foobar */ } return name; } /* * Parse the "st_mod" parameter. */ static int parse_st_mod(void *arg) { char *mod_name, *sym; struct st_mod *st_mod, *st_mod2; struct ipa_st_mod *ipa_st_mod; if ( (st_mod = mem_malloc(sizeof *st_mod, m_anon)) == NULL) { logconferrx("mem_malloc failed"); return -1; } st_mod->mod_file = *(char **)arg; if ( (st_mod->mod_handle = dl_open(st_mod->mod_file)) == NULL) { logconferrx("dl_open(%s): %s", st_mod->mod_file, dl_error()); return -1; } if ( (mod_name = get_mod_name(st_mod->mod_file)) == NULL) return -1; if (mem_asprintf(m_anon, &sym, "%s_st_mod", mod_name) < 0) { logconferrx("mem_asprintf failed"); return -1; } if ( (st_mod->ipa_st_mod = (struct ipa_st_mod *)dl_lookup_sym(st_mod->mod_handle, sym)) == NULL) { logconferrx("given module is not an IPA statistics module or unknown symbol naming scheme is used"); return -1; } mem_free(sym, m_anon); mem_free(mod_name, m_anon); ipa_st_mod = st_mod->ipa_st_mod; /* Check ipa_st_mod API version. */ if (ipa_st_mod->api_ver != IPA_ST_MOD_API_VERSION) { logconferrx("module %s uses ipa_st_mod API version %u, my ipa_st_mod API version is %u", st_mod->mod_file, ipa_st_mod->api_ver, IPA_DB_MOD_API_VERSION); return -1; } /* Check if module is thread-safe or vice versa. */ #ifdef WITH_PTHREAD if (!(ipa_st_mod->mod_flags & IPA_MOD_FLAG_PTHREAD_SAFE)) { logconferrx("module %s must be thread-safe", st_mod->mod_file); return -1; } #else if (ipa_st_mod->mod_flags & IPA_MOD_FLAG_PTHREAD_SAFE) { logconferrx("module %s must not be thread-safe", st_mod->mod_file); return -1; } #endif /* WITH_PTHREAD */ if (strcmp(ipa_st_mod->st_name, "null") == 0) { logconferrx("module's statistics name is \"null\", this is a name of the builtin statistics"); return -1; } if ( (st_mod2 = st_mod_by_name(ipa_st_mod->st_name)) != NULL) { conferrx("duplicated statistics name \"%s\" in %s and %s modules", ipa_st_mod->st_name, st_mod->mod_file, st_mod2->mod_file); return -1; } if ( (st_mod2 = st_mod_by_prefix(ipa_st_mod->conf_prefix)) != NULL) { conferrx("duplicated configuration prefix \"%s\" in %s and %s modules", ipa_st_mod->conf_prefix, st_mod->mod_file, st_mod2->mod_file); return -1; } ipa_st_mod->suppfunc = &suppfunc; ipa_st_mod->memfunc = &memfunc; if (init_conf_tbls(st_mod->mod_file, 1, ipa_st_mod->conf_sect_tbl, &st_mod->conf_sect_hash, ipa_st_mod->conf_param_tbl, &st_mod->conf_param_hash) < 0) return -1; if (ipa_st_mod->conf_init() < 0) { conferrx("module %s: conf_init failed", st_mod->mod_file); return -1; } SLIST_INSERT_HEAD(&st_mod_list, st_mod, link); return 0; } /* * Parse the "st_list" parameter. */ static int parse_st_list(void *arg) { char *ptr; const char *st_name; struct st_elem *st; struct st_set *set; struct st_list *list; const struct st_mod *st_mod; const struct st_list **listp; switch (section) { #ifdef WITH_RULES case IPA_CONF_SECT_RULE: listp = &currule->st_list; break; #endif case IPA_CONF_SECT_RULEPAT: listp = &currulepat->st_list; break; #ifdef WITH_LIMITS case IPA_CONF_SECT_LIMIT: listp = &curlimit->st_list; break; #endif #ifdef WITH_THRESHOLDS case IPA_CONF_SECT_THRESHOLD: listp = &curthreshold->st_list; break; #endif default: /* IPA_CONF_SECT_GLOBAL */ listp = &global_st_list; } if (*listp != NULL) { logconferrx("cannot redefine this parameter"); return -1; } set = NULL; list = NULL; for (ptr = *(char **)arg; ptr != NULL;) { /* Get the name of the next statistics system. */ st_name = ptr; if ( (ptr = strchr(ptr, ' ')) != NULL) *ptr++ = '\0'; /* Handle "null" statistics system. */ if (strcmp(st_name, "null") == 0) { if (list != NULL || ptr != NULL) { logconferrx("builtin statistics system \"null\" cannot be used together with another statistics systems"); return -1; } *listp = &st_list_null; return 0; } if ( (st_mod = st_mod_by_name(st_name)) == NULL) { logconferrx("cannot find module with \"%s\" statistics system name", st_name); return -1; } if (set != NULL) { /* We already have set for current st_list parameter. */ STAILQ_FOREACH(st, list, link) if (strcmp(st_name, st->ipa_st_mod->st_name) == 0) { logconferrx("duplicated statistics system name \"%s\"", st_name); return -1; } } else { /* Create new set for st_list parameter. */ if ( (set = mem_malloc(sizeof *set, m_anon)) == NULL) { logconferrx("mem_malloc failed"); return -1; } list = &set->list; STAILQ_INIT(list); } /* Add new st element to st_list. */ if ( (st = mem_malloc(sizeof *st, m_anon)) == NULL) { logconferrx("mem_malloc failed"); return -1; } st->ipa_st_mod = st_mod->ipa_st_mod; st->mod_file = st_mod->mod_file; STAILQ_INSERT_TAIL(list, st, link); } /* New st_list --> add it to st_sets. */ *listp = list; SLIST_INSERT_HEAD(&st_sets, set, link); return 0; } /* * Parse "posix_re_pattern" parameter. */ static int parse_posix_re_pattern(void *arg) { posix_re_pattern = *(int *)arg; return 0; } /* * Parse "debug_st_null" parameter. */ static int parse_debug_st_null(void *arg) { uint32_t level = *(uint32_t *)arg; if (level > 1) { logconferrx("too big debug level, max level is 1"); return -1; } debug_st_null = (int)level; return 0; } /* * Check file path: non empty string and should start with '/'. */ static int check_file_path(const char *fname, const char *what) { if (*fname == '\0') { logconferrx("argument should be a non-empty string"); return -1; } if (*fname != '/') { logconferrx("%s should be given with absolute path", what); return -1; } return 0; } /* * Parse the "include" parameter. */ static int parse_include(void *arg) { char *fname = *(char **)arg; struct parser_pbuf *pbuf; /* Save offset of current configuration file and close it. */ if ( (parser_curpbuf->foff = ftell(parser_curpbuf->fp)) < 0) { logconferr("ftell(%s)", parser_curpbuf->fname); return -1; } if (fclose(parser_curpbuf->fp) != 0) { logconferr("fclose(%s)", parser_curpbuf->fname); return -1; } /* Validate an argument. */ if (check_file_path(fname, "file") < 0) return -1; /* Check security of configuration file. */ if (check_conf_file(fname) < 0) return -1; /* Open included configuration file and put it to stack. */ if ( (pbuf = parser_new_pbuf(0)) == NULL) return -1; if ( (pbuf->fp = fopen(fname, "r")) == NULL) { logconferr("fopen(%s, \"r\")", fname); return -1; } pbuf->fname = fname; return parser_push_pbuf(pbuf); } /* * Parse the "include_files" parameter. */ static int parse_include_files(void *arg) { char *dir = *(char **)arg, *pat, *fname; int include_something; DIR *dirp; regex_t re; struct stat statbuf; struct dirent *dp; struct parser_pbuf *pbuf, *old_curpbuf; /* Validate an argument. */ if (check_file_path(dir, "directory") < 0) return -1; pat = strrchr(dir, '/'); *pat++ = '\0'; if (posix_re_pattern > 0) if ( (re_errcode = regcomp(&re, pat, REG_EXTENDED|REG_NOSUB)) != 0) { regerror(re_errcode, (regex_t *)NULL, re_errbuf, sizeof re_errbuf); logconferrx("cannot compile regular expression: regcomp(\"%s\"): %s", pat, re_errbuf); return -1; } /* Check security of the given directory. */ if (lstat(dir, &statbuf) < 0) { logconferr("lstat(%s)", dir); return -1; } if (!S_ISDIR(statbuf.st_mode)) { logconferrx("given pathname is not a directory"); return -1; } if ( (dirp = opendir(dir)) == NULL) { logconferr("opendir(%s)", dir); return -1; } include_something = 0; old_curpbuf = parser_curpbuf; for (;;) { errno = 0; if ( (dp = readdir(dirp)) == NULL) { if (errno != 0) { logconferr("readdir(%s)", dir); return -1; } break; } if (*dp->d_name == '.') /* Optimize and don't use strcmp(3) here for "." and "..". */ switch (*(dp->d_name + 1)) { case '\0': continue; case '.': if (*(dp->d_name + 2) == '\0') continue; } if (posix_re_pattern != 1) { if (fnmatch(pat, dp->d_name, FNM_PERIOD) == FNM_NOMATCH) continue; } else { if (regexec(&re, dp->d_name, 0, (regmatch_t *)NULL, 0) != 0) continue; } if (mem_asprintf(m_parser, &fname, "%s/%s", dir, dp->d_name) < 0) { logconferrx("mem_asprintf failed"); return -1; } if (lstat(fname, &statbuf) < 0) { logconferr("lstat(%s)", fname); return -1; } if (!S_ISREG(statbuf.st_mode)) { mem_free(fname, m_parser); continue; } if ( (pbuf = parser_new_pbuf(0)) == NULL) return -1; pbuf->fname = fname; pbuf->foff = 0; if (parser_push_pbuf(pbuf) < 0) return -1; include_something = 1; } if (posix_re_pattern > 0) regfree(&re); if (closedir(dirp) < 0) { logconferr("closedir(%s)", dir); return -1; } mem_free(dir, m_parser); if (include_something) { if ( (old_curpbuf->foff = ftell(old_curpbuf->fp)) < 0) { logconferr("ftell(%s)", old_curpbuf->fname); return -1; } if (fclose(old_curpbuf->fp) != 0) { logconferr("fclose(%s)", old_curpbuf->fname); return -1; } if ( (parser_curpbuf->fp = fopen(parser_curpbuf->fname, "r")) == NULL) { logconferr("fopen(%s, \"r\")", parser_curpbuf->fname); return -1; } } return 0; } static const u_int sect_root[] = { IPA_CONF_SECT_ROOT, 0 }; static const u_int sect_for_st_list[] = { IPA_CONF_SECT_GLOBAL, IPA_CONF_SECT_RULE, IPA_CONF_SECT_LIMIT, IPA_CONF_SECT_THRESHOLD, IPA_CONF_SECT_RULEPAT, 0 }; static const u_int sect_rulepat[] = { IPA_CONF_SECT_RULEPAT, 0 }; #ifdef WITH_ANY_LIMITS static const u_int sect_for_any_limit[] = { IPA_CONF_SECT_RULE, IPA_CONF_SECT_RULEPAT, 0 }; #endif /* * Sections in ipastat.conf(5). */ static ipa_conf_sect conf_sect_tbl[] = { { "global", IPA_CONF_SECT_GLOBAL, 0, NULL, NULL, IPA_CONF_TYPE_MISC, sect_root, parse_global }, { "rule", IPA_CONF_SECT_RULE, 1, NULL, NULL, IPA_CONF_TYPE_MISC, sect_root, parse_rule }, { "rulepat", IPA_CONF_SECT_RULEPAT, 1, NULL, NULL, IPA_CONF_TYPE_STRING, sect_root, parse_rulepat }, #ifdef WITH_LIMITS { "limit", IPA_CONF_SECT_LIMIT, 1, NULL, NULL, IPA_CONF_TYPE_MISC, sect_for_any_limit, parse_limit }, #endif #ifdef WITH_THRESHOLDS { "threshold", IPA_CONF_SECT_THRESHOLD,1, NULL, NULL, IPA_CONF_TYPE_MISC, sect_for_any_limit, parse_threshold }, #endif { NULL, 0, 0, NULL, NULL, IPA_CONF_TYPE_MISC, 0, NULL } }; #define PAT_LIST "^[^ \"]+( [^ \"]+)*$" /* * Parameters in ipastat.conf(5). */ static ipa_conf_param conf_param_tbl[] = { { "st_mod", 1, NULL, NULL, IPA_CONF_TYPE_STRING, sect_root, parse_st_mod }, { "include", 1, NULL, NULL, IPA_CONF_TYPE_STRING, NULL, parse_include }, { "include_files", 1, NULL, NULL, IPA_CONF_TYPE_STRING, NULL, parse_include_files }, { "posix_re_pattern", 1, NULL, NULL, IPA_CONF_TYPE_BOOLEAN, sect_root, parse_posix_re_pattern }, { "st_list", -1, PAT_LIST, ®_list, IPA_CONF_TYPE_MISC, sect_for_st_list, parse_st_list }, { "check_next_rulepat", 1, NULL, NULL, IPA_CONF_TYPE_BOOLEAN, sect_rulepat, parse_check_next_rulepat }, { "debug_st_null", 1, NULL, NULL, IPA_CONF_TYPE_UINT32, sect_root, parse_debug_st_null }, { "dynamic_rules", 1, NULL, NULL, IPA_CONF_TYPE_BOOLEAN, sect_root, parse_dynamic_rules }, #ifdef WITH_LIMITS { "dynamic_limits", 1, NULL, NULL, IPA_CONF_TYPE_BOOLEAN, sect_root, parse_dynamic_limits }, #endif #ifdef WITH_THRESHOLDS { "dynamic_thresholds", 1, NULL, NULL, IPA_CONF_TYPE_BOOLEAN, sect_root, parse_dynamic_thresholds }, #endif { NULL, 0, NULL, NULL, 0, 0, NULL } }; int configure(PARSING_MODE mode) { int real_config; char *ptr; const u_int *id_ptr; const char *prefix; /* Configuration prefix. */ struct rule *rule; struct rulepat *rulepat; /* Stack of nested configuration sections. */ struct section_stack { SLIST_ENTRY(section_stack) link; u_int section; /* Section ID. */ } *section_stack_ptr; SLIST_HEAD(, section_stack) section_stack_list = SLIST_HEAD_INITIALIZER(section_stack_list); const struct st_mod *st_mod; struct parser_pbuf *pbuf; struct conf_sect_hash *conf_sect_hash; struct conf_param_hash *conf_param_hash; const struct conf_sect_hash *conf_sect_hash_ptr; const struct conf_param_hash *conf_param_hash_ptr; const ipa_conf_sect *conf_sect_tbl_ptr, *conf_sect; const ipa_conf_param *conf_param_tbl_ptr, *conf_param; int in_own_sect; /* 1, if in own ipastat.conf(5) section. */ const struct get_arg_tbl *get_arg_ptr; real_config = mode != TEST_PARSING; xvlogmsgx = vconferrx_priority; /* Set wrappers for log functions. */ mvlogmsgx = mvlogmsgx_conf_wrapper; parser_vlogmsgx = parser_vlogmsgx_wrapper; if ((m_result = mem_type_new_local(MTYPE_NAME(result), "Memory for query results", 0)) == NULL || (m_parser = mem_type_new_local(MTYPE_NAME(parser), "Memory of parser", MEMTYPE_FLAGS)) == NULL) { logmsgx(IPA_LOG_ERR, "configure: mem_type_new_local failed"); goto parsing_failed; } global_st_list = NULL; debug_st_null = -1; SLIST_INIT(&st_mod_list); if ( (conf_sect_hentry_mzone = mzone_init(MZONE_NAME(conf_sect_hentry), "Config sections hash entries", 0, sizeof(struct conf_sect_hentry), CONF_SECT_HENTRY_NSIZE, CONF_SECT_HENTRY_NALLOC)) == NULL) goto parsing_failed; if ( (conf_param_hentry_mzone = mzone_init(MZONE_NAME(conf_param_hentry), "Config parameters hash entries", 0, sizeof(struct conf_param_hentry), CONF_PARAM_HENTRY_NSIZE, CONF_PARAM_HENTRY_NALLOC)) == NULL) goto parsing_failed; init_rules_hash(); if ( (rule_mzone = mzone_init(MZONE_NAME(rule), "Rules", 0, sizeof(struct rule), RULE_NSIZE, RULE_NALLOC)) == NULL) goto parsing_failed; if ( (rulepat_mzone = mzone_init(MZONE_NAME(rulepat), "Rules patterns", 0, sizeof(struct rulepat), RULEPAT_NSIZE, RULEPAT_NALLOC)) == NULL) goto parsing_failed; #ifdef WITH_LIMITS if ( (limit_mzone = mzone_init(MZONE_NAME(limit), "Limits", 0, sizeof(struct limit), LIMIT_NSIZE, LIMIT_NALLOC)) == NULL) goto parsing_failed; #endif #ifdef WITH_THRESHOLDS if ( (threshold_mzone = mzone_init(MZONE_NAME(threshold), "Thresholds", 0, sizeof(struct threshold), THRESHOLD_NSIZE, THRESHOLD_NALLOC)) == NULL) goto parsing_failed; #endif posix_re_pattern = -1; if (check_conf_file(ipastat_conf_file) < 0) goto parsing_failed; section = IPA_CONF_SECT_ROOT; memfunc.m_parser = m_parser; /* Init parser. */ if (parser_init() < 0) { logmsgx(IPA_LOG_ERR, "configure: parser_init failed"); return -1; } /* Init first pbuf. */ if ( (pbuf = parser_new_pbuf(0)) == NULL) return -1; pbuf->fname = ipastat_conf_file; if ( (pbuf->fp = fopen(ipastat_conf_file, "r")) == NULL) { conferrx("fopen(%s, \"r\"): %s", ipastat_conf_file, strerror(errno)); goto parsing_failed; } if (parser_push_pbuf(pbuf) < 0) goto parsing_failed; /* Needed for log messages. */ curparam = cursect = curmodfile = NULL; if (build_conf_regexp() < 0) { conferrx("cannot build additional regular expressions needed for parsing"); goto parsing_failed; } if (init_conf_tbls((char *)NULL, 1, conf_sect_tbl, &conf_sect_hash, conf_param_tbl, &conf_param_hash) < 0) goto parsing_failed; /* Set ipa.conf(5) configuration tables. */ conf_sect_tbl_ptr = conf_sect_tbl; conf_param_tbl_ptr = conf_param_tbl; conf_sect_hash_ptr = conf_sect_hash; conf_param_hash_ptr = conf_param_hash; in_own_sect = 1; for (;;) { switch (parser_read_string()) { case 1: /* Successfully read one logical line. */ break; case 0: /* EOF of current configuration file. */ if (fclose(parser_curpbuf->fp) != 0) { conferrx("fclose(%s): %s", parser_curpbuf->fname, strerror(errno)); goto parsing_failed; } if (parser_curpbuf->fname != ipastat_conf_file) mem_free(parser_curpbuf->fname, m_parser); parser_pop_pbuf(); if (parser_curpbuf != NULL) { /* Init previous file for parsing. */ if ( (parser_curpbuf->fp = fopen(parser_curpbuf->fname, "r")) == NULL) { conferrx("fopen(%s, \"r\"): %s", parser_curpbuf->fname, strerror(errno)); goto parsing_failed; } if (fseek(parser_curpbuf->fp, parser_curpbuf->foff, SEEK_SET) < 0) { conferrx("fseek(%s, %ld, SEEK_SET): %s", parser_curpbuf->fname, parser_curpbuf->foff, strerror(errno)); goto parsing_failed; } continue; } goto end_of_parsing; default: /* -1 */ goto parsing_failed; } switch (parser_token_id) { case TOKEN_ID_SECTION_BEGIN: /* Put previous section on top of sections stack. */ if ( (section_stack_ptr = mem_malloc(sizeof *section_stack_ptr, m_anon)) == NULL) { conferrx("configure: mem_malloc failed"); goto parsing_failed; } section_stack_ptr->section = section; SLIST_INSERT_HEAD(§ion_stack_list, section_stack_ptr, link); /* Get name of current section. */ cursect = parser_token; /* "section" or "prefix:section". */ if (in_own_sect) { /* Previous section is not a custom section. */ if ( (ptr = strchr(cursect, ':')) != NULL) { *ptr = '\0'; prefix = cursect; cursect = ptr + 1; /* Fix section name. */ if ( (st_mod = st_mod_by_prefix(prefix)) != NULL) { conf_sect_hash_ptr = st_mod->conf_sect_hash; conf_param_hash_ptr = st_mod->conf_param_hash; conf_sect_tbl_ptr = st_mod->ipa_st_mod->conf_sect_tbl; conf_param_tbl_ptr = st_mod->ipa_st_mod->conf_param_tbl; curmodfile = st_mod->mod_file; } else { logconferrx("cannot find module with \"%s\" configuration prefix", prefix); goto parsing_failed; } in_own_sect = 0; } } /* Find ID of section. */ if ( (conf_sect = find_conf_sect(conf_sect_tbl_ptr, conf_sect_hash_ptr, cursect)) == NULL) { logconferrx("unknown section"); goto parsing_failed; } /* Check if current section is used in correct place. */ if ( (id_ptr = conf_sect->sect_where) != NULL) for (;; ++id_ptr) { if (*id_ptr == section) break; if (*id_ptr == 0) goto section_not_expected; } /* Check number of section's arguments. */ if (conf_sect->arg_nargs >= 0) { if (parser_nargs != conf_sect->arg_nargs) { logconferrx("wrong number of arguments (has %d, should have %d)", parser_nargs, conf_sect->arg_nargs); goto parsing_failed; } } else { if (parser_nargs < -conf_sect->arg_nargs) { logconferrx("this section should have at least %d argument%s", -conf_sect->arg_nargs, conf_sect->arg_nargs == -1 ? "" : "s"); goto parsing_failed; } } /* Validate arguments if needed. */ if (conf_sect->arg_regexp != NULL) if (regexec(conf_sect->arg_regexp, parser_args, 0, (regmatch_t *)NULL, 0) != 0) { logconferrx("wrong format of an argument"); goto parsing_failed; } section = conf_sect->sect_id; /* Register config event in module. */ if (!in_own_sect) if (st_mod_conf_event(st_mod, IPA_CONF_EVENT_CUSTOM_SECT_BEGIN, section, (void *)NULL) < 0) goto parsing_failed; /* Parse it. */ if (conf_sect->arg_type <= IPA_CONF_TYPE_MISC) { get_arg_ptr = &get_arg_tbl[conf_sect->arg_type]; if (get_arg_ptr->reg != NULL) if (regexec(get_arg_ptr->reg, parser_args, 0, (regmatch_t *)NULL, 0) != 0) { logconferrx("wrong format of an argument"); goto parsing_failed; } if (get_arg_ptr->get_arg(get_arg_ptr->argp) < 0) goto parsing_failed; if (conf_sect->arg_parse != NULL) if (conf_sect->arg_parse(get_arg_ptr->argp) < 0) goto parsing_failed; } else { logconferrx("internal error: unknown type %u of function's argument", conf_sect->arg_type); goto parsing_failed; } break; case TOKEN_ID_PARAMETER: curparam = parser_token; /* "param" or "prefix:param". */ if (in_own_sect) { /* Current section is not a custom section. */ if ( (ptr = strchr(curparam, ':')) != NULL) { *ptr = '\0'; prefix = curparam; curparam = ptr + 1; /* Fix parameter name. */ if ( (st_mod = st_mod_by_prefix(prefix)) != NULL) { conf_param_hash_ptr = st_mod->conf_param_hash; conf_param_tbl_ptr = st_mod->ipa_st_mod->conf_param_tbl; curmodfile = st_mod->mod_file; } else { logconferrx("cannot find module with \"%s\" configuration prefix", prefix); goto parsing_failed; } } } /* Find ID of parameter. */ if ( (conf_param = find_conf_param(conf_param_tbl_ptr, conf_param_hash_ptr, curparam)) == NULL) { logconferrx("unknown parameter"); goto parsing_failed; } /* Check if parameter is used in correct place. */ if ( (id_ptr = conf_param->param_where) != NULL) for (;; ++id_ptr) { if (*id_ptr == section) break; if (*id_ptr == 0) { logconferrx("this parameter is not expected here"); goto parsing_failed; } } /* Check number of parameters's arguments. */ if (conf_param->arg_nargs >= 0) { if (parser_nargs != conf_param->arg_nargs) { logconferrx("wrong number of arguments (has %d, should have %d)", parser_nargs, conf_param->arg_nargs); goto parsing_failed; } } else { if (parser_nargs < -conf_param->arg_nargs) { logconferrx("this parameter should have at least %d argument%s", -conf_param->arg_nargs, conf_param->arg_nargs == -1 ? "": "s"); goto parsing_failed; } } /* Validate arguments if needed. */ if (conf_param->arg_regexp != NULL) if (regexec(conf_param->arg_regexp, parser_args, 0, (regmatch_t *)NULL, 0) != 0) { logconferrx("wrong format of an argument"); goto parsing_failed; } /* Parse it. */ if (conf_param->arg_type <= IPA_CONF_TYPE_MISC) { get_arg_ptr = &get_arg_tbl[conf_param->arg_type]; if (get_arg_ptr->reg != NULL) if (regexec(get_arg_ptr->reg, parser_args, 0, (regmatch_t *)NULL, 0) != 0) { logconferrx("wrong format of an argument"); goto parsing_failed; } if (get_arg_ptr->get_arg(get_arg_ptr->argp) < 0) goto parsing_failed; if (conf_param->arg_parse != NULL) if (conf_param->arg_parse(get_arg_ptr->argp) < 0) goto parsing_failed; curparam = NULL; } else { logconferrx("internal error: unknown type %u of an argument", conf_param->arg_type); goto parsing_failed; } if (curmodfile != NULL && in_own_sect) { curmodfile = NULL; /* Was set above for logxxx() functions. */ /* Restore ipa.conf(5) parameters tables. */ conf_param_hash_ptr = conf_param_hash; conf_param_tbl_ptr = conf_param_tbl; } break; default: /* TOKEN_ID_SECTION_END */ if (section > IPA_CONF_SECT_CUSTOM_OFFSET) { if (st_mod_conf_event(st_mod, IPA_CONF_EVENT_CUSTOM_SECT_END, section, (void *)NULL) < 0) goto parsing_failed; } else { switch (section) { case IPA_CONF_SECT_RULE: if (mod_conf_event(IPA_CONF_EVENT_RULE_END, currule->ruleno, (void *)NULL) < 0) goto parsing_failed; break; case IPA_CONF_SECT_RULEPAT: if (mod_conf_event(IPA_CONF_EVENT_RULEPAT_END, currulepat->rulepatno, (void *)NULL) < 0) goto parsing_failed; break; #ifdef WITH_LIMITS case IPA_CONF_SECT_LIMIT: (void)parser_local_sym_del("limit"); if (mod_conf_event(IPA_CONF_EVENT_LIMIT_END, curlimit->limitno, (void *)NULL) < 0) goto parsing_failed; break; #endif /* WITH_LIMITS */ #ifdef WITH_THRESHOLDS case IPA_CONF_SECT_THRESHOLD: (void)parser_local_sym_del("threshold"); if (mod_conf_event(IPA_CONF_EVENT_THRESHOLD_END, curthreshold->thresholdno, (void *)NULL) < 0) goto parsing_failed; break; #endif /* WITH_THRESHOLDS */ case IPA_CONF_SECT_GLOBAL: if (mod_conf_event(IPA_CONF_EVENT_GLOBAL_END, 0, (void *)NULL) < 0) goto parsing_failed; break; } } section_stack_ptr = SLIST_FIRST(§ion_stack_list); SLIST_REMOVE_HEAD(§ion_stack_list, link); section = section_stack_ptr->section; mem_free(section_stack_ptr, m_anon); if (!in_own_sect && section < IPA_CONF_SECT_CUSTOM_OFFSET) { /* We were in custom section and previous section is not a custom section. */ curmodfile = NULL; /* Restore ipastat.conf(5) configuration tables. */ conf_sect_tbl_ptr = conf_sect_tbl; conf_param_tbl_ptr = conf_param_tbl; conf_sect_hash_ptr = conf_sect_hash; conf_param_hash_ptr = conf_param_hash; in_own_sect = 1; } } } end_of_parsing: deinit_conf_tbls(0, conf_sect_tbl, conf_sect_hash, conf_param_tbl, conf_param_hash); mzone_deinit(conf_sect_hentry_mzone); mzone_deinit(conf_param_hentry_mzone); if (mzone_is_empty(rulepat_mzone)) { mzone_deinit(rulepat_mzone); rulepat_mzone = NULL; } if (parser_deinit() < 0) goto parsing_failed; SLIST_FOREACH(st_mod, &st_mod_list, link) { if (mimic_real_config) if (st_mod->ipa_st_mod->conf_mimic_real() < 0) { conferrx("module %s: conf_mimic_real failed", st_mod->mod_file); goto parsing_failed; } deinit_conf_tbls(1, st_mod->ipa_st_mod->conf_sect_tbl, st_mod->conf_sect_hash, st_mod->ipa_st_mod->conf_param_tbl, st_mod->conf_param_hash); if (st_mod->ipa_st_mod->conf_deinit() < 0) { conferrx("module %s: conf_deinit failed", st_mod->mod_file); goto parsing_failed; } } if (real_config || mimic_real_config) { /* Set global parameters. */ global_section_set = 1; if (global_st_list == NULL) global_st_list = &st_list_null; if (debug_st_null < 0) debug_st_null = 0; if (dynamic_rules < 0) dynamic_rules = 0; #ifdef WITH_LIMITS if (dynamic_limits < 0) dynamic_limits = 0; #endif #ifdef WITH_THRESHOLDS if (dynamic_thresholds < 0) dynamic_thresholds = 0; #endif /* Inherit some settings for rulepat{} from global{}. */ STAILQ_FOREACH(rulepat, &rulepats_list, link) if (rulepat->check_next_rulepat <= 0) { rulepat->check_next_rulepat = 0; if (rulepat->st_list == NULL) rulepat->st_list = global_st_list; } } if (mimic_real_config) { STAILQ_FOREACH(rule, &rules_list, list) { STAILQ_FOREACH(rulepat, &rulepats_list, link) { if (regexec(&rulepat->reg, rule->rule_name, 0, (regmatch_t *)NULL, 0) == 0) { /* Inherit some settings for rule{} from rulepat{}. */ if (rule->st_list == NULL) rule->st_list = rulepat->st_list; #ifdef WITH_LIMITS if (STAILQ_EMPTY(&rule->limits) && !STAILQ_EMPTY(&rulepat->limits)) if (copy_limits(rule, &rulepat->limits) < 0) { conferrx("rule %s: cannot copy all limits from rulepat %s", rule->rule_name, parser_buf_to_string(rulepat->pat)); goto parsing_failed; } #endif #ifdef WITH_THRESHOLDS if (STAILQ_EMPTY(&rule->thresholds) && !STAILQ_EMPTY(&rulepat->thresholds)) if (copy_thresholds(rule, &rulepat->thresholds) < 0) { conferrx("rule %s: cannot copy all thresholds from rulepat %s", rule->rule_name, parser_buf_to_string(rulepat->pat)); goto parsing_failed; } #endif if (mod_conf_inherit(rulepat, rule) < 0) { conferrx("configure: mod_conf_inherit failed"); goto parsing_failed; } if (rulepat->check_next_rulepat == 0) break; } } if (rulepat == NULL) { /* Inherit some settings for rule{} from global{}. */ if (rule->st_list == NULL) rule->st_list = global_st_list; } } } mvlogmsgx = mvlogmsgx_wrapper; xvlogmsgx = vlogmsgx; return 0; section_not_expected: logconferrx("this section is not expected here"); parsing_failed: logmsgx(IPA_LOG_ERR, "configuration file(s) parsing failed!"); return -1; } /* * Unload all modules and free memory used by structures which * describe loaded modules. Note that any pointer should not references * any data in unloaded modules' memory. So, the best place when * to call this function: after memfunc_deinit() and before checking * amount of not freed memory. */ static int unload_all_mods(void) { struct st_mod *st_mod, *st_mod_next; for (st_mod = SLIST_FIRST(&st_mod_list); st_mod != NULL; st_mod = st_mod_next) { st_mod_next = SLIST_NEXT(st_mod, link); if (dl_close(st_mod->mod_handle) < 0) { logmsgx(IPA_LOG_ERR, "module %s: dl_close failed: %s", st_mod->mod_file, dl_error()); return -1; } mem_free(st_mod->mod_file, m_parser); mem_free(st_mod, m_anon); } return 0; } /* * Free all resources allocated during work. */ int free_all(void) { u_int n; free_rules(); if (!STAILQ_EMPTY(&rules_list)) { logmsgx(IPA_LOG_ERR, "internal error: free_all: rules_list is not empty"); return -1; } if (!STAILQ_EMPTY_HEAD_VALID(&rules_list)) { logmsgx(IPA_LOG_ERR, "internal error: free_all: empty rules_list list is in inconsistent state"); return -1; } if ( (n = mzone_nused(rule_mzone)) != 0) { logmsgx(IPA_LOG_ERR, "internal error: free_all: rule_mzone is not empty: %u", n); return -1; } mzone_deinit(rule_mzone); #ifdef WITH_LIMITS if ( (n = mzone_nused(limit_mzone)) != 0) { logmsgx(IPA_LOG_ERR, "internal error: free_all: limit_mzone is not empty: %u", n); return -1; } mzone_deinit(limit_mzone); #endif #ifdef WITH_THRESHOLDS if ( (n = mzone_nused(threshold_mzone)) != 0) { logmsgx(IPA_LOG_ERR, "internal error: free_all: threshold_mzone is not empty: %u", n); return -1; } mzone_deinit(threshold_mzone); #endif free_rulepats(); free_st_lists(); memfunc_deinit_1(0); if (unload_all_mods() < 0) { logmsgx(IPA_LOG_ERR, "free_all: cannot correctly unload all modules"); return -1; } memfunc_deinit_2(0); return 0; } static void mod_conf_show(u_int sect_id, u_int no) { const struct st_mod *st_mod; need_nl = 0; SLIST_FOREACH(st_mod, &st_mod_list, link) st_mod->ipa_st_mod->conf_show(sect_id, no); if (sect_id == IPA_CONF_SECT_ROOT) print_nl(); } static void show_st_list(const struct st_list *list) { const struct st_elem *st; if (list != NULL) { printf("%*sst_list =", conf_indent, ""); if (list != &st_list_null) STAILQ_FOREACH(st, list, link) printf(" %s", st->ipa_st_mod->st_name); else printf(" null"); print_eol(); } } #ifdef WITH_LIMITS static void show_limits(const struct limits_list *list) { const struct limit *limit; STAILQ_FOREACH(limit, list, link) { conf_indent = 2 * CONF_INDENT; printf("%*slimit %s {\n", CONF_INDENT, "", limit->limit_name); show_st_list(limit->st_list); mod_conf_show(IPA_CONF_SECT_LIMIT, limit->limitno); printf("%*s}\n", CONF_INDENT, ""); } } #endif #ifdef WITH_THRESHOLDS static void show_thresholds(const struct thresholds_list *list) { const struct threshold *threshold; STAILQ_FOREACH(threshold, list, link) { conf_indent = 2 * CONF_INDENT; printf("%*sthreshold %s {\n", CONF_INDENT, "", threshold->threshold_name); show_st_list(threshold->st_list); mod_conf_show(IPA_CONF_SECT_THRESHOLD, threshold->thresholdno); printf("%*s}\n", CONF_INDENT, ""); } } #endif void show_config(void) { const struct rule *rule; const struct rulepat *rulepat; const struct st_mod *st_mod; printf("\ /*\n\ * This output is not identical to the original content of the\n\ * configuration file(s), this is just how ipastat(8) and IPA modules\n\ * see their configurations. Any \"include\" or \"include_files\"\n\ * parameters are not printed and all macro variables are expanded.\n\ */\n\n"); if (mimic_real_config) printf("/* Mimic real configuration regime. */\n\n"); conf_indent = mod_indent = 0; SLIST_FOREACH(st_mod, &st_mod_list, link) { printf("st_mod "); print_string(st_mod->mod_file); print_eol(); need_nl = 1; } print_nl(); if (posix_re_pattern >= 0) { printf("posix_re_pattern = "); print_boolean(posix_re_pattern); print_eol(); need_nl = 1; } print_nl(); if (debug_st_null >= 0) { printf("debug_st_null = %d", debug_st_null); print_eol(); need_nl = 1; print_nl(); } if (dynamic_rules >= 0) { printf("dynamic_rules = "); print_boolean(dynamic_rules); print_eol(); need_nl = 1; } #ifdef WITH_LIMITS if (dynamic_limits >= 0) { printf("dynamic_limits = "); print_boolean(dynamic_limits); print_eol(); need_nl = 1; } #endif #ifdef WITH_THRESHOLDS if (dynamic_thresholds >= 0) { printf("dynamic_thresholds = "); print_boolean(dynamic_thresholds); print_eol(); need_nl = 1; } #endif print_nl(); mod_conf_show(IPA_CONF_SECT_ROOT, 0); if (global_section_set) { conf_indent = CONF_INDENT; printf("global {\n"); show_st_list(global_st_list); mod_conf_show(IPA_CONF_SECT_GLOBAL, 0); printf("}\n\n"); } STAILQ_FOREACH(rulepat, &rulepats_list, link) { conf_indent = CONF_INDENT; printf("rulepat "); print_string(rulepat->pat); printf(" {\n"); if (rulepat->check_next_rulepat >= 0) { printf("%*scheck_next_rulepat = ", CONF_INDENT, ""); print_boolean(rulepat->check_next_rulepat); print_eol(); } show_st_list(rulepat->st_list); mod_conf_show(IPA_CONF_SECT_RULE, rulepat->rulepatno); #ifdef WITH_LIMITS show_limits(&rulepat->limits); #endif #ifdef WITH_THRESHOLDS show_thresholds(&rulepat->thresholds); #endif printf("}\n\n"); } STAILQ_FOREACH(rule, &rules_list, list) { conf_indent = CONF_INDENT; printf("rule %s {\n", rule->rule_name); show_st_list(rule->st_list); mod_conf_show(IPA_CONF_SECT_RULE, rule->ruleno); #ifdef WITH_LIMITS show_limits(&rule->limits); #endif #ifdef WITH_THRESHOLDS show_thresholds(&rule->thresholds); #endif printf("}\n\n"); } }