#include "common.h" #include "config.h" #include "log.h" f2b_config_param_t * f2b_config_parse_kv_pair(const char *src) { f2b_config_param_t *param = NULL; char line[CONFIG_LINE_MAX] = ""; char *p, *key, *value; size_t len; strncpy(line, src, sizeof(line)); line[CONFIG_LINE_MAX] = '\0'; /* strip spaces before key */ key = line; while (isblank(*key)) key++; if ((value = strchr(key, '=')) == NULL) return NULL; /* strip spaces after key */ p = value - 1; while (p > line && isblank(*p)) p--; p++, *p = '\0'; value++; /* move to next char after '=' */ while (isblank(*value)) value++; /* strip trailing comment */ if ((p = strstr(value, " #")) != NULL) *p = '\0'; if ((p = strstr(value, "\t#")) != NULL) *p = '\0'; if ((p = strstr(value, " ;")) != NULL) *p = '\0'; if ((p = strstr(value, "\t;")) != NULL) *p = '\0'; /* strip trailing spaces */ p = value + strlen(value); if (p > value) p--; /* step back at char before '\0' */ while (p > value && isspace(*p)) p--; p++, *p = '\0'; len = strlen(key); if (len < 1 || len > CONFIG_KEY_MAX) return NULL; len = strlen(value); if (len < 1 || len > CONFIG_VAL_MAX) return NULL; if ((param = calloc(1, sizeof(f2b_config_param_t))) != NULL) { strncpy(param->name, key, sizeof(param->name)); strncpy(param->value, value, sizeof(param->value)); param->name[CONFIG_KEY_MAX] = '\0'; param->name[CONFIG_VAL_MAX] = '\0'; return param; } return NULL; } f2b_config_section_t * f2b_config_parse_section(const char *src) { f2b_config_section_t *section = NULL; char line[CONFIG_LINE_MAX] = ""; char *name, *end; strncpy(line, src, sizeof(line)); line[CONFIG_LINE_MAX] = '\0'; if ((end = strchr(line, ']')) == NULL) return NULL; *end = '\0'; if ((section = calloc(1, sizeof(f2b_config_section_t))) == NULL) return NULL; name = "[defaults]"; if (strncmp(line, name, strlen(name)) == 0) { section->type = t_defaults; return section; } name = "[backend:"; if (strncmp(line, name, strlen(name)) == 0) { section->type = t_backend; strncpy(section->name, line + strlen(name), sizeof(section->name)); return section; } name = "[jail:"; if (strncmp(line, name, strlen(name)) == 0) { section->type = t_jail; strncpy(section->name, line + strlen(name), sizeof(section->name)); return section; } free(section); return NULL; } f2b_config_section_t * f2b_config_find_section(f2b_config_section_t *section, f2b_section_type type, const char *name) { for (; section != NULL; section = section->next) { if (section->type == type && strcmp(section->name, name) == 0) return section; } return NULL; } f2b_config_param_t * f2b_config_find_param(f2b_config_param_t *param, const char *name) { for (; param != NULL; param = param->next) { if (strcmp(name, param->name) == 0) return param; } return NULL; } f2b_config_section_t * f2b_config_append_param(f2b_config_section_t *section, f2b_config_param_t *param) { if (section->param) { section->last->next = param; section->last = section->last->next; } else { section->param = param; section->last = param; } return section; } f2b_config_section_t * f2b_config_load(const char *path) { f2b_config_section_t *config = NULL; /* always points to current section */ f2b_config_section_t *section = NULL; /* temp pointer */ f2b_config_param_t *param = NULL; /* temp pointer */ FILE *f = NULL; /* config file fd */ char *p; /* temp pointer */ char line[CONFIG_LINE_MAX] = ""; /* last read line */ bool skip_section = false; /* if set - skip parameters unless next section */ size_t linenum = 0; /* current line number in config */ if ((f = fopen(path, "r")) == NULL) { f2b_log_msg(log_error, "can't open config file '%s': %s", path, strerror(errno)); return NULL; } if ((config = calloc(1, sizeof(f2b_config_section_t))) == NULL) return NULL; config->type = t_main; while (1) { p = fgets(line, sizeof(line), f); if (!p && (feof(f) || ferror(f))) break; while (isblank(*p)) p++; linenum++; switch(*p) { case '\0': case '\r': case '\n': /* empty line */ break; case ';': case '#': /* comment line */ break; case '[': /* section header */ section = f2b_config_parse_section(p); if (section) { skip_section = false; section->next = config; config = section; } else { skip_section = true; f2b_log_msg(log_error, "unknown section at line %d: %s", linenum, p); } break; default: if (skip_section) { f2b_log_msg(log_warn, "skipping line in unknown section: %s", p); continue; } /* key/value pair */ param = f2b_config_parse_kv_pair(p); if (param) { f2b_config_append_param(config, param); } else { f2b_log_msg(log_error, "can't parse key/value at line %d: %s", linenum, p); } break; } /* switch */ } /* while */ fclose(f); return config; } void f2b_config_free(f2b_config_section_t *config) { f2b_config_section_t *next_section = NULL; f2b_config_param_t *next_param = NULL; for (; config != NULL; config = next_section) { next_section = config->next; for (; config->param != NULL; config->param = next_param) { next_param = config->param->next; FREE(config->param); } FREE(config); } }