#include "hypercube.h" static akbuf_ctxh cfg_ctx; FILE *cfg_f = NULL; hypercube_config cfg; enum { CFG_NONE, CFG_BOOL, CFG_INT, CFG_STR, CFG_TABLE, CFG_INADDR, CFG_REGEX_TABLE, CFG_FUNC }; int cfg_func_include(unsigned char *, unsigned int, unsigned char **, unsigned int); int cfg_func_echo(unsigned char *, unsigned int, unsigned char **, unsigned int); struct hypercube_config_token { unsigned char *key; unsigned int type; void *val; } hypercube_config_tokens[] = { { "listen_port", CFG_INT, &cfg.listen_port }, { "listen_addr", CFG_INADDR, &cfg.listen_addr }, { "default_root", CFG_STR, &cfg.default_root }, { "log", CFG_BOOL, &cfg.log }, { "log_level", CFG_STR, &cfg.log_level }, { "log_file", CFG_STR, &cfg.log_file }, { "background", CFG_BOOL, &cfg.background }, { "run_as_uid", CFG_INT, &cfg.run_as_uid }, { "run_as_gid", CFG_INT, &cfg.run_as_gid }, { "chroot_dir", CFG_STR, &cfg.chroot_dir }, { "vhost", CFG_TABLE, &cfg.vhosts }, { "mime", CFG_TABLE, &cfg.mime_types }, { "rewrite", CFG_REGEX_TABLE, &cfg.rewrite_rules }, { "include", CFG_FUNC, cfg_func_include }, { "echo", CFG_FUNC, cfg_func_echo }, { "allow", CFG_REGEX_TABLE, &cfg.allow_clients }, { "deny", CFG_REGEX_TABLE, &cfg.deny_clients }, /* tracker */ { "tracker_interval", CFG_INT, &cfg.tracker.interval }, { "tracker_init_interval", CFG_INT, &cfg.tracker.init_interval }, { "tracker_timeout", CFG_INT, &cfg.tracker.timeout }, { "tracker_stopped_timeout", CFG_INT, &cfg.tracker.stopped_timeout }, { "tracker_respnum", CFG_INT, &cfg.tracker.respnum }, { "tracker_period", CFG_INT, &cfg.tracker.period }, { "tracker_sql_stats", CFG_BOOL, &cfg.tracker.sql_stats }, { "tracker_sql_host", CFG_STR, &cfg.tracker.sql_host }, { "tracker_sql_db", CFG_STR, &cfg.tracker.sql_db }, { "tracker_sql_user", CFG_STR, &cfg.tracker.sql_user }, { "tracker_sql_pass", CFG_STR, &cfg.tracker.sql_pass }, { "tracker_statslog", CFG_STR, &cfg.tracker.statslog }, { "tracker_sync", CFG_BOOL, &cfg.tracker.sync }, { "tracker_sync_interval", CFG_INT, &cfg.tracker.sync_interval }, { "tracker_sync_size", CFG_INT, &cfg.tracker.sync_size }, { "tracker_sync_addr", CFG_INADDR, &cfg.tracker.sync_addr }, { "tracker_sync_port", CFG_INT, &cfg.tracker.sync_port }, { "tracker_infohash_file", CFG_STR, &cfg.tracker.infohash_file }, { "tracker_infohash_interval",CFG_INT, &cfg.tracker.infohash_interval }, { NULL, CFG_NONE, NULL }, }; #define CFG_ERR_HDR() fprintf(stderr, "Error in configuration '%s' on line %u:\n ", filename, curline); int cfg_load(unsigned char *filename, unsigned int level) { FILE *f; unsigned char readbuf[BUF_SIZE], *p; #define MAX_CFG_TOKENS 16 unsigned char *tokenv[MAX_CFG_TOKENS]; unsigned int tokenc, i; unsigned int curline; unsigned int bool_val; curline = 0; if (level == 0) { if (cfg_f == NULL || fseek(cfg_f, 0, SEEK_SET) != 0) { if ((f = fopen(filename, "r")) == NULL) { fprintf(stderr, "Unable to open config file '%s': %s\n", filename, strerror(errno)); return -1; } cfg_f = f; } else { f = cfg_f; } } else { if ((f = fopen(filename, "r")) == NULL) { fprintf(stderr, "Unable to open config file '%s': %s\n", filename, strerror(errno)); return -1; } } while (fgets(readbuf, sizeof(readbuf) - 1, f) != NULL) { curline ++; if ((p = strpbrk(readbuf, "\n\r")) != NULL) *p = 0; tokenc = 0; p = readbuf; while (*p == ' ' || *p == '\t') p ++; if (*p == '#') continue; bool_val = 1; DEBUGF("cfg line %s:%u [%s]", filename, curline, p); if (*p == 0) continue; p = strtok(p, " \t"); while (tokenc < MAX_CFG_TOKENS && p != NULL && *p != '#') { /* handle !foo / no foo */ if (tokenc == 0) { if (*p == '!') { bool_val = 0; p ++; } else if (strcasecmp(p, "no") == 0) { bool_val = 0; p = NULL; } } if (p != NULL && *p != 0) tokenv[tokenc ++] = strdup(p); p = strtok(NULL, " \t"); } if (tokenc == 0) continue; for (i = 0; hypercube_config_tokens[i].key != NULL; i ++) if (strcasecmp(hypercube_config_tokens[i].key, tokenv[0]) == 0) break; if (hypercube_config_tokens[i].key == NULL) { CFG_ERR_HDR(); fprintf(stderr, "Unknown key '%s'\n", tokenv[0]); return -1; } if (hypercube_config_tokens[i].type == CFG_BOOL) { if (tokenc != 1) { CFG_ERR_HDR(); fprintf(stderr, "Invalid number of arguments (expected [!]%s)\n", tokenv[0]); return -1; } DEBUGF("bool value '%s' = %u", hypercube_config_tokens[i].key, bool_val); *(int *)hypercube_config_tokens[i].val = bool_val; } else if (bool_val != 0) switch (hypercube_config_tokens[i].type) { case CFG_NONE: break; case CFG_INT: { if (tokenc != 2) { CFG_ERR_HDR(); fprintf(stderr, "Invalid number of arguments (expected %s )\n", tokenv[0]); return -1; } *(int *)hypercube_config_tokens[i].val = atoi(tokenv[1]); break; } case CFG_STR: { unsigned char **dest; if (tokenc != 2) { CFG_ERR_HDR(); fprintf(stderr, "Invalid number of arguments (expected %s )\n", tokenv[0]); return -1; } dest = hypercube_config_tokens[i].val; *dest = strdup(tokenv[1]); break; } case CFG_TABLE: { akbuf_table *tbl; unsigned char **dest; if (tokenc != 3) { CFG_ERR_HDR(); fprintf(stderr, "Invalid number of arguments (expected %s )\n", tokenv[0]); return -1; } dest = hypercube_config_tokens[i].val; tbl = (akbuf_table *)*dest; akbuf_table_entry_add_str(cfg_ctx, tbl, tokenv[1], tokenv[2]); break; } case CFG_REGEX_TABLE: { akbuf_table *tbl; unsigned char **dest; akbuf *compbuf, *valbuf; int ret; if (tokenc != 2 && tokenc != 3) { CFG_ERR_HDR(); fprintf(stderr, "Invalid number of arguments (expected %s [arg])\n", tokenv[0]); return -1; } compbuf = akbuf_init(cfg_ctx, sizeof(regex_t)); if ((ret = regcomp((regex_t *)akbuf_data(compbuf), tokenv[1], REG_EXTENDED)) != 0) { unsigned char errbuf[BUF_SIZE]; regerror(ret, (regex_t *)akbuf_data(compbuf), errbuf, sizeof(errbuf)); fprintf(stderr, "Parsing of regex '%s' failed: %s\n", tokenv[1], errbuf); return -1; } akbuf_set_idx(compbuf, sizeof(regex_t)); valbuf = akbuf_init(cfg_ctx, 0); akbuf_strcpy(valbuf, tokenv[2]); dest = hypercube_config_tokens[i].val; tbl = (akbuf_table *)*dest; akbuf_table_entry_add_buf(cfg_ctx, tbl, compbuf, valbuf); akbuf_free(cfg_ctx, valbuf); break; } case CFG_INADDR: { struct in_addr *addr; if (tokenc != 2) { CFG_ERR_HDR(); fprintf(stderr, "Invalid number of arguments (expected %s )\n", tokenv[0]); return -1; } addr = hypercube_config_tokens[i].val; if ((addr->s_addr = inet_addr(tokenv[1])) == -1) { CFG_ERR_HDR(); fprintf(stderr, "Invalid IP address '%s'\n", tokenv[1]); return -1; } break; } case CFG_FUNC: { int (*func)(); func = hypercube_config_tokens[i].val; if (func != NULL) if (func(filename, curline, tokenv, tokenc) != 0) return -1; break; } } } return 0; } int cfg_func_include(unsigned char *filename, unsigned int curline, unsigned char **tokenv, unsigned int tokenc) { if (tokenc != 2) { CFG_ERR_HDR(); fprintf(stderr, "Invalid number of arguments (expected %s )\n", tokenv[0]); return -1; } return cfg_load(tokenv[1], 1); } int cfg_func_echo(unsigned char *filename, unsigned int curline, unsigned char **tokenv, unsigned int tokenc) { unsigned char *msg; if (tokenc < 2) msg = ""; else msg = tokenv[1]; printf("%s:%u: %s\n", filename, curline, msg); return 0; } void cfg_init(void) { cfg_ctx = akbuf_new_ctx(); cfg.listen_port = 8000; cfg.listen_addr.s_addr = INADDR_ANY; cfg.default_root = "dox/"; cfg.log = 1; cfg.log_level = "request"; cfg.log_file = NULL; cfg.background = 0; cfg.run_as_uid = cfg.run_as_gid = -1; cfg.chroot_dir = NULL; cfg.tracker.statslog = NULL; cfg.vhosts = akbuf_table_init(cfg_ctx, AKBUF_TABLE_NOCASE); cfg.mime_types = akbuf_table_init(cfg_ctx, AKBUF_TABLE_NOCASE); cfg.rewrite_rules = akbuf_table_init(cfg_ctx, AKBUF_TABLE_BIN); cfg.allow_clients = akbuf_table_init(cfg_ctx, AKBUF_TABLE_BIN); cfg.deny_clients = akbuf_table_init(cfg_ctx, AKBUF_TABLE_BIN); /* tracker */ cfg.tracker.interval = 360; cfg.tracker.timeout = 360 * 2; cfg.tracker.stopped_timeout = 300 * 2; cfg.tracker.respnum = 50; cfg.tracker.period = 15; cfg.tracker.sql_stats = 0; cfg.tracker.sql_host = NULL; cfg.tracker.sql_db = NULL; cfg.tracker.sql_user = NULL; cfg.tracker.sql_pass = NULL; cfg.tracker.sync = 0; cfg.tracker.sync_interval = 15; cfg.tracker.sync_size = 1400; cfg.tracker.sync_addr.s_addr = INADDR_BROADCAST; cfg.tracker.sync_port = 4242; cfg.tracker.infohash_file = NULL; cfg.tracker.infohash_interval = 30; if (cfg_load(CFG_FILE, 0) != 0) exit(1); } void cfg_reload(void) { akbuf_free_ctx(cfg_ctx); cfg_init(); }