summaryrefslogtreecommitdiffstats
path: root/src/config.c
diff options
context:
space:
mode:
authorDrew DeVault <sir@cmpwn.com>2020-09-23 11:19:29 -0400
committerDrew DeVault <sir@cmpwn.com>2020-09-23 11:24:23 -0400
commit58500c8e530cc9b0807afbe8b068fe7b00db0131 (patch)
tree25d8d12de0e3a9ec1bc65a5256ab3bebe06771e2 /src/config.c
parentccae8ffd2807b8b984b657b6321802fa00b52427 (diff)
downloadgmnisrv-58500c8e530cc9b0807afbe8b068fe7b00db0131.tar.gz
gmnisrv-58500c8e530cc9b0807afbe8b068fe7b00db0131.tar.xz
gmnisrv-58500c8e530cc9b0807afbe8b068fe7b00db0131.zip
Initial config parser
Diffstat (limited to 'src/config.c')
-rw-r--r--src/config.c141
1 files changed, 141 insertions, 0 deletions
diff --git a/src/config.c b/src/config.c
new file mode 100644
index 0000000..847af6e
--- /dev/null
+++ b/src/config.c
@@ -0,0 +1,141 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "config.h"
+#include "ini.h"
+
+struct gmnisrv_host *
+gmnisrv_config_get_host(struct gmnisrv_config *conf, const char *hostname)
+{
+ struct gmnisrv_host *host = conf->hosts;
+ while (host) {
+ if (strcmp(host->hostname, hostname) == 0) {
+ return host;
+ }
+ host = host->next;
+ }
+ return NULL;
+}
+
+static int
+parse_listen(struct gmnisrv_config *conf, const char *value)
+{
+ // TODO
+ (void)conf;
+ (void)value;
+ return 1;
+}
+
+static int
+conf_ini_handler(void *user, const char *section,
+ const char *name, const char *value)
+{
+ struct gmnisrv_config *conf = (struct gmnisrv_config *)user;
+ struct {
+ char *section;
+ char *name;
+ char **value;
+ } strvars[] = {
+ { ":tls", "store", &conf->tls.store },
+ { ":tls", "organization", &conf->tls.organization },
+ { ":tls", "email", &conf->tls.email },
+ };
+ struct {
+ char *section;
+ char *name;
+ int (*fn)(struct gmnisrv_config *conf, const char *value);
+ } fnvars[] = {
+ { "", "listen", &parse_listen, }
+ };
+
+ for (size_t i = 0; i < sizeof(strvars) / sizeof(strvars[0]); ++i) {
+ if (strcmp(strvars[i].section, section) != 0) {
+ continue;
+ }
+ if (strcmp(strvars[i].name, name) != 0) {
+ continue;
+ }
+ *strvars[i].value = strdup(value);
+ return 1;
+ }
+
+ for (size_t i = 0; i < sizeof(fnvars) / sizeof(fnvars[0]); ++i) {
+ if (strcmp(fnvars[i].section, section) != 0) {
+ continue;
+ }
+ if (strcmp(fnvars[i].name, name) != 0) {
+ continue;
+ }
+ return fnvars[i].fn(conf, value);
+ }
+
+ if (section[0] == '\0' || section[0] == ':') {
+ fprintf(stderr, "Unknown config option [%s]%s\n", section, name);
+ return 0;
+ }
+
+ struct gmnisrv_host *host = gmnisrv_config_get_host(conf, section);
+ if (!host) {
+ host = calloc(1, sizeof(struct gmnisrv_host));
+ host->hostname = strdup(section);
+ host->next = conf->hosts;
+ conf->hosts = host;
+ }
+
+ struct {
+ char *name;
+ char **value;
+ } host_strvars[] = {
+ { "root", &host->root },
+ };
+
+ for (size_t i = 0; i < sizeof(host_strvars) / sizeof(host_strvars[0]); ++i) {
+ if (strcmp(host_strvars[i].name, name) != 0) {
+ continue;
+ }
+ *host_strvars[i].value = strdup(value);
+ return 1;
+ }
+
+ fprintf(stderr, "Unknown config option [%s]%s\n", section, name);
+ return 0;
+}
+
+static int
+validate_config(struct gmnisrv_config *conf)
+{
+ if (!conf->binds) {
+ fprintf(stderr, "Error: config missing listen directive\n");
+ return 1;
+ }
+ if (!conf->hosts) {
+ fprintf(stderr, "Error: config defines no hosts\n");
+ return 1;
+ }
+ if (!conf->tls.store) {
+ fprintf(stderr, "Error: config defines no certificate store\n");
+ return 1;
+ }
+ return 0;
+}
+
+int
+load_config(struct gmnisrv_config *conf, const char *path)
+{
+ FILE *f = fopen(path, "r");
+ if (!f) {
+ fprintf(stderr, "Error opening %s: %s\n",
+ path, strerror(errno));
+ return 1;
+ }
+
+ int n = ini_parse_file(f, conf_ini_handler, conf);
+ fclose(f);
+ if (n != 0) {
+ fprintf(stderr, "at %s:%d\n", path, n);
+ return 1;
+ }
+
+ return validate_config(conf);
+}