+#if ENABLE_FEATURE_SYSLOGD_CFG
+static const CODE* find_by_name(char *name, const CODE* c_set)
+{
+ for (; c_set->c_name; c_set++) {
+ if (strcmp(name, c_set->c_name) == 0)
+ return c_set;
+ }
+ return NULL;
+}
+#endif
+static const CODE* find_by_val(int val, const CODE* c_set)
+{
+ for (; c_set->c_name; c_set++) {
+ if (c_set->c_val == val)
+ return c_set;
+ }
+ return NULL;
+}
+
+#if ENABLE_FEATURE_SYSLOGD_CFG
+static void parse_syslogdcfg(const char *file)
+{
+ char *t;
+ logRule_t **pp_rule;
+ /* tok[0] set of selectors */
+ /* tok[1] file name */
+ /* tok[2] has to be NULL */
+ char *tok[3];
+ parser_t *parser;
+
+ parser = config_open2(file ? file : "/etc/syslog.conf",
+ file ? xfopen_for_read : fopen_for_read);
+ if (!parser)
+ /* didn't find default /etc/syslog.conf */
+ /* proceed as if we built busybox without config support */
+ return;
+
+ /* use ptr to ptr to avoid checking whether head was initialized */
+ pp_rule = &G.log_rules;
+ /* iterate through lines of config, skipping comments */
+ while (config_read(parser, tok, 3, 2, "# \t", PARSE_NORMAL | PARSE_MIN_DIE)) {
+ char *cur_selector;
+ logRule_t *cur_rule;
+
+ /* unexpected trailing token? */
+ if (tok[2])
+ goto cfgerr;
+
+ cur_rule = *pp_rule = xzalloc(sizeof(*cur_rule));
+
+ cur_selector = tok[0];
+ /* iterate through selectors: "kern.info;kern.!err;..." */
+ do {
+ const CODE *code;
+ char *next_selector;
+ uint8_t negated_prio; /* "kern.!err" */
+ uint8_t single_prio; /* "kern.=err" */
+ uint32_t facmap; /* bitmap of enabled facilities */
+ uint8_t primap; /* bitmap of enabled priorities */
+ unsigned i;
+
+ next_selector = strchr(cur_selector, ';');
+ if (next_selector)
+ *next_selector++ = '\0';
+
+ t = strchr(cur_selector, '.');
+ if (!t)
+ goto cfgerr;
+ *t++ = '\0'; /* separate facility from priority */
+
+ negated_prio = 0;
+ single_prio = 0;
+ if (*t == '!') {
+ negated_prio = 1;
+ ++t;
+ }
+ if (*t == '=') {
+ single_prio = 1;
+ ++t;
+ }
+
+ /* parse priority */
+ if (*t == '*')
+ primap = 0xff; /* all 8 log levels enabled */
+ else {
+ uint8_t priority;
+ code = find_by_name(t, prioritynames);
+ if (!code)
+ goto cfgerr;
+ primap = 0;
+ priority = code->c_val;
+ if (priority == INTERNAL_NOPRI) {
+ /* ensure we take "enabled_facility_priomap[fac] &= 0" branch below */
+ negated_prio = 1;
+ } else {
+ priority = 1 << priority;
+ do {
+ primap |= priority;
+ if (single_prio)
+ break;
+ priority >>= 1;
+ } while (priority);
+ if (negated_prio)
+ primap = ~primap;
+ }
+ }
+
+ /* parse facility */
+ if (*cur_selector == '*')
+ facmap = (1<<LOG_NFACILITIES) - 1;
+ else {
+ char *next_facility;
+ facmap = 0;
+ t = cur_selector;
+ /* iterate through facilities: "kern,daemon.<priospec>" */
+ do {
+ next_facility = strchr(t, ',');
+ if (next_facility)
+ *next_facility++ = '\0';
+ code = find_by_name(t, facilitynames);
+ if (!code)
+ goto cfgerr;
+ /* "mark" is not a real facility, skip it */
+ if (code->c_val != INTERNAL_MARK)
+ facmap |= 1<<(LOG_FAC(code->c_val));
+ t = next_facility;
+ } while (t);
+ }
+
+ /* merge result with previous selectors */
+ for (i = 0; i < LOG_NFACILITIES; ++i) {
+ if (!(facmap & (1<<i)))
+ continue;
+ if (negated_prio)
+ cur_rule->enabled_facility_priomap[i] &= primap;
+ else
+ cur_rule->enabled_facility_priomap[i] |= primap;
+ }
+
+ cur_selector = next_selector;
+ } while (cur_selector);
+
+ /* check whether current file name was mentioned in previous rules or
+ * as global logfile (G.logFile).
+ */
+ if (strcmp(G.logFile.path, tok[1]) == 0) {
+ cur_rule->file = &G.logFile;
+ goto found;
+ }
+ /* temporarily use cur_rule as iterator, but *pp_rule still points
+ * to currently processing rule entry.
+ * NOTE: *pp_rule points to the current (and last in the list) rule.
+ */
+ for (cur_rule = G.log_rules; cur_rule != *pp_rule; cur_rule = cur_rule->next) {
+ if (strcmp(cur_rule->file->path, tok[1]) == 0) {
+ /* found - reuse the same file structure */
+ (*pp_rule)->file = cur_rule->file;
+ cur_rule = *pp_rule;
+ goto found;
+ }
+ }
+ cur_rule->file = xzalloc(sizeof(*cur_rule->file));
+ cur_rule->file->fd = -1;
+ cur_rule->file->path = xstrdup(tok[1]);
+ found:
+ pp_rule = &cur_rule->next;
+ }
+ config_close(parser);
+ return;
+
+ cfgerr:
+ bb_error_msg_and_die("error in '%s' at line %d",
+ file ? file : "/etc/syslog.conf",
+ parser->lineno);
+}
+#endif