diff options
author | David Härdeman <david@hardeman.nu> | 2020-06-05 16:27:31 +0200 |
---|---|---|
committer | David Härdeman <david@hardeman.nu> | 2020-06-05 16:27:31 +0200 |
commit | cf87432e410cbe2ee61e90b8f4c2e8d2a75f09ca (patch) | |
tree | 73a38b16215515ce7d3cd87b9f8ccfb55e22e885 | |
parent | db66484c4300f5f0e857eff01d15fd3593002a79 (diff) |
Split config into generic and dir watching parts
-rw-r--r-- | .gitignore | 2 | ||||
-rw-r--r-- | cfgdir.c (renamed from inotify.c) | 413 | ||||
-rw-r--r-- | cfgdir.h | 10 | ||||
-rw-r--r-- | config.c | 456 | ||||
-rw-r--r-- | config.h | 25 | ||||
-rw-r--r-- | inotify.h | 12 | ||||
-rw-r--r-- | main.c | 9 | ||||
-rw-r--r-- | meson.build | 2 |
8 files changed, 116 insertions, 813 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f7cb71c --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build +attic @@ -14,408 +14,62 @@ #include "main.h" #include "uring.h" +#include "cfgdir.h" #include "config.h" #include "server.h" -static void -eat_whitespace_and_comments(char **pos) -{ - while (true) { - while (isspace(**pos)) - (*pos)++; - - if (**pos == '#') { - while (**pos != '\r' && **pos != '\n' && **pos != '\0') - (*pos)++; - continue; - } - - return; - } -} - -static char * -get_line(char **pos) -{ - char *begin = *pos; - char *end; - - while (isspace(*begin)) - begin++; - - if (*begin == '\0') - return NULL; - - end = begin; - while (*end != '\n' && *end != '\0') - end++; - - if (*end == '\0') - *pos = end; - else - *pos = end + 1; - - while (isspace(*end)) { - *end = '\0'; - end--; - } - - return begin; -} - -static bool -strtosockaddrs(const char *str, struct list_head *list) -{ - char *tmp; - uint16_t port; - int r; - struct sockaddr_in46 *addr; - - if (!str || *str == '\0' || !list) - return false; - list_init(list); - - if (*str == '[') { - /* IPv6, [a:b:c...h]:p or [*]:p */ - str++; - tmp = strchr(str, ']'); - if (!tmp) - goto out; - *tmp = '\0'; - - addr = zmalloc(sizeof(*addr)); - if (!addr) - goto out; - list_add(&addr->list, list); - - if (!strcmp(str, "*")) - addr->in6.sin6_addr = in6addr_any; - else if (inet_pton(AF_INET6, str, &addr->in6.sin6_addr) <= 0) - goto out; - - tmp++; - if (*tmp != ':') - goto out; - - tmp++; - if (strtou16_strict(tmp, &port) < 0) - goto out; - - addr->in6.sin6_family = AF_INET6; - addr->in6.sin6_port = htons(port); - addr->addrlen = sizeof(addr->in6); - - } else if (*str == '*') { - /* IPv4, *:p */ - str++; - if (*str != ':') - goto out; - - str++; - if (strtou16_strict(str, &port) < 0) - goto out; - - addr = zmalloc(sizeof(*addr)); - if (!addr) - goto out; - list_add(&addr->list, list); - - addr->in4.sin_family = AF_INET; - addr->in4.sin_addr.s_addr = INADDR_ANY; - addr->in4.sin_port = htons(port); - addr->addrlen = sizeof(addr->in4); - - } else if ((tmp = strchr(str, ':'))) { - /* IPv4, a.b.c.d:p or IPv4/6 hostname:p */ - fprintf(stderr, "Got an IPv4:port or hostname:port\n"); - *tmp = '\0'; - tmp++; - if (strtou16_strict(tmp, &port) < 0) - goto out; - - addr = zmalloc(sizeof(*addr)); - if (!addr) - goto out; - - if (inet_pton(AF_INET, str, &addr->in4.sin_addr) > 0) { - fprintf(stderr, "...Got an IPv4:port (0x%p, list 0x%p)\n", addr, &addr->list); - addr->in4.sin_family = AF_INET; - addr->in4.sin_port = htons(port); - addr->addrlen = sizeof(addr->in4); - list_add(&addr->list, list); - goto success; - } else { - free(addr); - } - - struct addrinfo hints = { - .ai_family = AF_UNSPEC, - .ai_socktype = SOCK_STREAM, - .ai_protocol = 0, - .ai_flags = 0, - }; - struct addrinfo *results, *ai; - - /* FIXME: This is completely synchronous but getaddrinfo_a is not very ergonomic */ - r = getaddrinfo(str, tmp, &hints, &results); - if (r != 0) { - fprintf(stderr, "gettaddrinfo(%s): %s\n", str, gai_strerror(r)); - goto out; - } - - fprintf(stderr, "...Got an hostname:port\n"); - for (ai = results; ai; ai = ai->ai_next) { - fprintf(stderr, "Got a result from getaddrinfo\n"); - - addr = zmalloc(sizeof(*addr)); - if (!addr) { - freeaddrinfo(results); - goto out; - } - - switch (ai->ai_family) { - case AF_INET: { - struct sockaddr_in *naddr = (struct sockaddr_in *)ai->ai_addr; - - addr->in4.sin_family = AF_INET; - addr->in4.sin_addr = naddr->sin_addr; - addr->in4.sin_port = naddr->sin_port; - addr->addrlen = sizeof(addr->in4); - list_add(&addr->list, list); - break; - } - case AF_INET6: { - struct sockaddr_in6 *naddr = (struct sockaddr_in6 *)ai->ai_addr; - - addr->in6.sin6_family = AF_INET6; - addr->in6.sin6_addr = naddr->sin6_addr; - addr->in6.sin6_port = naddr->sin6_port; - addr->addrlen = sizeof(addr->in6); - list_add(&addr->list, list); - break; - } - default: - fprintf(stderr, " Fam: Unknown (%i)\n", ai->ai_family); - free(addr); - continue; - } - } - - freeaddrinfo(results); - - } else if (strtou16_strict(tmp, &port) == 0) { - /* Port */ - - addr = zmalloc(sizeof(*addr)); - if (!addr) - goto out; - addr->in6.sin6_family = AF_INET6; - addr->in6.sin6_addr = in6addr_any; - addr->in6.sin6_port = htons(port); - addr->addrlen = sizeof(addr->in6); - list_add(&addr->list, list); - - addr = zmalloc(sizeof(*addr)); - if (!addr) - goto out; - addr->in4.sin_family = AF_INET; - addr->in4.sin_addr.s_addr = INADDR_ANY; - addr->in4.sin_port = htons(port); - addr->addrlen = sizeof(addr->in4); - list_add(&addr->list, list); - } - -success: - if (list_empty(list)) { - fprintf(stderr, "Success but empty list!?\n"); - return false; - } else { - int i = 0; - struct list_head *pos; - - list_for_each(pos, list) - i++; - fprintf(stderr, "Success, %i entries\n", i); - } - - return true; - -out: - if (!list_empty(list)) { - struct sockaddr_in46 *tmpaddr; - - list_for_each_entry_safe(addr, tmpaddr, list, list) { - list_del(&addr->list); - free(addr); - } - } - return false; -} - enum scfg_keys { + SCFG_KEY_INVALID = 0, SCFG_KEY_TYPE, SCFG_KEY_NAME, SCFG_KEY_PORT, SCFG_KEY_LOCAL, SCFG_KEY_REMOTE, - SCFG_KEY_INVALID -}; - -enum value_type { - VAL_TYPE_STRING, - VAL_TYPE_UINT16, - VAL_TYPE_ADDR, - VAL_TYPE_INVALID }; -struct scfg_key_map { - const char *key_name; - enum scfg_keys key_value; - enum value_type value_type; -} scfg_key_map[] = { +struct cfg_key_value_map scfg_key_map[] = { { .key_name = "type", .key_value = SCFG_KEY_TYPE, - .value_type = VAL_TYPE_STRING, + .value_type = CFG_VAL_TYPE_STRING, }, { .key_name = "name", .key_value = SCFG_KEY_NAME, - .value_type = VAL_TYPE_STRING, + .value_type = CFG_VAL_TYPE_STRING, }, { .key_name = "port", .key_value = SCFG_KEY_PORT, - .value_type = VAL_TYPE_UINT16, + .value_type = CFG_VAL_TYPE_UINT16, }, { .key_name = "local", .key_value = SCFG_KEY_LOCAL, - .value_type = VAL_TYPE_ADDR, + .value_type = CFG_VAL_TYPE_ADDRS, }, { .key_name = "remote", .key_value = SCFG_KEY_REMOTE, - .value_type = VAL_TYPE_ADDR, + .value_type = CFG_VAL_TYPE_ADDRS, + }, { + .key_name = NULL, + .key_value = SCFG_KEY_INVALID, + .value_type = CFG_VAL_TYPE_INVALID, } }; -union cfg_value { - const char *str; - uint16_t uint16; - struct list_head addr_list; -}; - - -static void -line_get_key_value(char *line, enum scfg_keys *rkey, union cfg_value *rvalue) -{ - char *tmp, *key; - int i; - - *rkey = SCFG_KEY_INVALID; - if (!line) - return; - - tmp = line; - while (isspace(*tmp)) - tmp++; - - if (*tmp == '\0') - return; - - key = tmp; - while (*tmp != '\0' && !isspace(*tmp)) - tmp++; - - if (*tmp == '\0') - return; - - *tmp = '\0'; - tmp++; - - while (isspace(*tmp)) - tmp++; - - if (*tmp != '=') - return; - - tmp++; - while (isspace(*tmp)) - tmp++; - - if (*tmp == '\0') - return; - - for (i = 0; i < ARRAY_SIZE(scfg_key_map); i++) { - if (strcmp(scfg_key_map[i].key_name, key)) - continue; - - switch (scfg_key_map[i].value_type) { - - case VAL_TYPE_STRING: - rvalue->str = tmp; - break; - - case VAL_TYPE_UINT16: { - uint16_t v; - - if (strtou16_strict(tmp, &v) < 0) - return; - rvalue->uint16 = v; - break; - } - - case VAL_TYPE_ADDR: { - if (!strtosockaddrs(tmp, &rvalue->addr_list)) - return; - if (list_empty(&rvalue->addr_list)) { - fprintf(stderr, "VAL_TYPE_ADDR with zero list!?\n"); - return; - } else { - int i = 0; - struct list_head *pos; - - list_for_each(pos, &rvalue->addr_list) - i++; - fprintf(stderr, "VAL_TYPE_ADDR with list %i entries\n", i); - } - break; - } - - case VAL_TYPE_INVALID: - /* fall through */ - default: - return; - } - *rkey = scfg_key_map[i].key_value; - break; - } -} - static void scfg_parse(struct cfg *cfg, struct server *scfg) { char *pos = &scfg->buf[0]; - char *line; - - eat_whitespace_and_comments(&pos); - line = get_line(&pos); - if (!line) { - printf("Cfg: premature EOF\n"); + if (!config_parse_header(cfg, "server", &pos)) return; - } - - if (strcmp(line, "[server]")) { - printf("Invalid line: %s\n", line); - return; - } while (true) { - enum scfg_keys key; + int key; union cfg_value value; - eat_whitespace_and_comments(&pos); - line = get_line(&pos); - printf("Examining line: %s\n", line); - line_get_key_value(line, &key, &value); + if (!config_parse_line(cfg, &pos, scfg_key_map, &key, &value)) + break; + if (key == SCFG_KEY_INVALID) break; printf("Got a key-value pair: %i = something\n", key); @@ -646,13 +300,13 @@ inotify_cb(struct cfg *cfg, struct uring_task *task, int res) } void -inotify_refdump(struct inotify_ev *iev) +cfgdir_refdump(struct inotify_ev *iev) { uring_task_refdump(&iev->task); } void -scfg_stop_monitor_dir(struct cfg *cfg) +cfgdir_delete(struct cfg *cfg) { if (!cfg->iev) { fprintf(stderr, "%s called with no iev!\n", __func__); @@ -665,11 +319,14 @@ scfg_stop_monitor_dir(struct cfg *cfg) } void -scfg_monitor_dir(struct cfg *cfg) +cfgdir_init(struct cfg *cfg) { int ifd; int iwd; struct inotify_ev *iev; + DIR *cfgdir; + struct dirent *dent; + struct server *scfg; iev = malloc(sizeof(*iev)); if (!iev) @@ -692,33 +349,15 @@ scfg_monitor_dir(struct cfg *cfg) uring_task_set_fd(&iev->task, ifd); cfg->iev = iev; uring_read(cfg, &iev->task, iev->buf, sizeof(iev->buf), 0, inotify_cb); -} - -void -scfg_read_all(struct cfg *cfg) -{ - - DIR *cfgdir; - struct dirent *dent; - struct server *scfg; cfgdir = opendir("."); - if (!cfgdir) { - perror("opendir"); - free(cfg); - return; - } + if (!cfgdir) + perrordie("opendir"); while ((dent = readdir(cfgdir)) != NULL) { - char *suffix; - - if (dent->d_name[0] == '.') - continue; if (dent->d_type != DT_REG && dent->d_type != DT_UNKNOWN) continue; - if ((suffix = strrchr(dent->d_name, '.')) == NULL) - continue; - if (strcmp(suffix, ".server")) + if (!scfg_valid_filename(dent->d_name)) continue; scfg = server_new(cfg, dent->d_name); diff --git a/cfgdir.h b/cfgdir.h new file mode 100644 index 0000000..ff55fb9 --- /dev/null +++ b/cfgdir.h @@ -0,0 +1,10 @@ +#ifndef foocfgdirhfoo +#define foocfgdirhfoo + +void cfgdir_delete(struct cfg *cfg); + +void cfgdir_refdump(struct inotify_ev *iev); + +void cfgdir_init(struct cfg *cfg); + +#endif @@ -2,8 +2,6 @@ #include <ctype.h> #include <string.h> #include <stdbool.h> -#include <sys/inotify.h> -#include <dirent.h> #include <errno.h> #include <sys/types.h> #include <sys/socket.h> @@ -252,80 +250,37 @@ out: return false; } -enum scfg_keys { - SCFG_KEY_TYPE, - SCFG_KEY_NAME, - SCFG_KEY_PORT, - SCFG_KEY_LOCAL, - SCFG_KEY_REMOTE, - SCFG_KEY_INVALID -}; - -enum value_type { - VAL_TYPE_STRING, - VAL_TYPE_UINT16, - VAL_TYPE_ADDR, - VAL_TYPE_INVALID -}; - -struct scfg_key_map { - const char *key_name; - enum scfg_keys key_value; - enum value_type value_type; -} scfg_key_map[] = { - { - .key_name = "type", - .key_value = SCFG_KEY_TYPE, - .value_type = VAL_TYPE_STRING, - }, { - .key_name = "name", - .key_value = SCFG_KEY_NAME, - .value_type = VAL_TYPE_STRING, - }, { - .key_name = "port", - .key_value = SCFG_KEY_PORT, - .value_type = VAL_TYPE_UINT16, - }, { - .key_name = "local", - .key_value = SCFG_KEY_LOCAL, - .value_type = VAL_TYPE_ADDR, - }, { - .key_name = "remote", - .key_value = SCFG_KEY_REMOTE, - .value_type = VAL_TYPE_ADDR, - } -}; - -union cfg_value { - const char *str; - uint16_t uint16; - struct list_head addr_list; -}; - - -static void -line_get_key_value(char *line, enum scfg_keys *rkey, union cfg_value *rvalue) +/* Returns true if theres data left to parse in buf */ +bool +config_parse_line(struct cfg *cfg, char **buf, struct cfg_key_value_map *kvmap, + int *rkey, union cfg_value *rvalue) { - char *tmp, *key; + char *line, *tmp, *key; int i; - *rkey = SCFG_KEY_INVALID; + if (!cfg || !buf || !*buf || !kvmap || !rkey || !rvalue) + die("%s: called with invalid parameters\n", __func__); + + eat_whitespace_and_comments(buf); + line = get_line(buf); if (!line) - return; + return false; + + printf("%s: examining line: %s\n", __func__, line); tmp = line; while (isspace(*tmp)) tmp++; if (*tmp == '\0') - return; + goto out; key = tmp; while (*tmp != '\0' && !isspace(*tmp)) tmp++; if (*tmp == '\0') - return; + goto out; *tmp = '\0'; tmp++; @@ -334,397 +289,90 @@ line_get_key_value(char *line, enum scfg_keys *rkey, union cfg_value *rvalue) tmp++; if (*tmp != '=') - return; + goto out; tmp++; while (isspace(*tmp)) tmp++; if (*tmp == '\0') - return; + goto out; - for (i = 0; i < ARRAY_SIZE(scfg_key_map); i++) { - if (strcmp(scfg_key_map[i].key_name, key)) + for (i = 0; kvmap[i].key_name; i++) { + if (strcmp(kvmap[i].key_name, key)) continue; - switch (scfg_key_map[i].value_type) { + switch (kvmap[i].value_type) { - case VAL_TYPE_STRING: + case CFG_VAL_TYPE_STRING: rvalue->str = tmp; break; - case VAL_TYPE_UINT16: { + case CFG_VAL_TYPE_UINT16: { uint16_t v; if (strtou16_strict(tmp, &v) < 0) - return; + goto out; rvalue->uint16 = v; break; } - case VAL_TYPE_ADDR: { + case CFG_VAL_TYPE_ADDRS: { if (!strtosockaddrs(tmp, &rvalue->addr_list)) - return; + goto out; if (list_empty(&rvalue->addr_list)) { - fprintf(stderr, "VAL_TYPE_ADDR with zero list!?\n"); - return; + fprintf(stderr, "CFG_VAL_TYPE_ADDRS with zero list!?\n"); + goto out; } else { int i = 0; struct list_head *pos; list_for_each(pos, &rvalue->addr_list) i++; - fprintf(stderr, "VAL_TYPE_ADDR with list %i entries\n", i); + fprintf(stderr, "CFG_VAL_TYPE_ADDRS with list %i entries\n", i); } break; } - case VAL_TYPE_INVALID: + case CFG_VAL_TYPE_INVALID: /* fall through */ default: - return; - } - *rkey = scfg_key_map[i].key_value; - break; - } -} - -static void -scfg_parse(struct cfg *cfg, struct server *scfg) -{ - char *pos = &scfg->buf[0]; - char *line; - - eat_whitespace_and_comments(&pos); - - line = get_line(&pos); - if (!line) { - printf("Cfg: premature EOF\n"); - return; - } - - if (strcmp(line, "[server]")) { - printf("Invalid line: %s\n", line); - return; - } - - while (true) { - enum scfg_keys key; - union cfg_value value; - - eat_whitespace_and_comments(&pos); - line = get_line(&pos); - printf("Examining line: %s\n", line); - line_get_key_value(line, &key, &value); - if (key == SCFG_KEY_INVALID) - break; - printf("Got a key-value pair: %i = something\n", key); - - switch (key) { - - case SCFG_KEY_TYPE: - if (!strcmp(value.str, "proxy")) { - if (!server_set_type(cfg, scfg, SERVER_TYPE_PROXY)) - return; - } else if (!strcmp(value.str, "announce")) { - if (!server_set_type(cfg, scfg, SERVER_TYPE_ANNOUNCE)) - return; - } - break; - - case SCFG_KEY_NAME: - if (!server_set_pretty_name(cfg, scfg, value.str)) - return; - break; - - case SCFG_KEY_PORT: - if (!server_set_port(cfg, scfg, value.uint16)) - return; - break; - - case SCFG_KEY_LOCAL: { - struct sockaddr_in46 *addr, *tmp; - - list_for_each_entry_safe(addr, tmp, &value.addr_list, list) { - list_del(&addr->list); - server_add_local(cfg, scfg, addr); - } - break; - } - - case SCFG_KEY_REMOTE: { - struct sockaddr_in46 *addr, *tmp; - - list_for_each_entry_safe(addr, tmp, &value.addr_list, list) { - list_del(&addr->list); - server_add_remote(cfg, scfg, addr); - } - break; - } - - case SCFG_KEY_INVALID: - default: - break; - } - } - - //printf("Cfg:\n%s\n\n", pos); -} - -static void -scfg_read_cb(struct cfg *cfg, struct uring_task *task, int res) -{ - struct server *scfg = container_of(task, struct server, task); - - printf("Asked to parse server cfg %s (bytes %i)\n", scfg->name, res); - - if (res < 0) { - perrordie("read"); - } else if (res > 0) { - scfg->len += res; - if (scfg->len + 1 >= sizeof(scfg->buf)) { - fprintf(stderr, "Server config too large\n"); - server_delete(cfg, scfg); - return; + goto out; } - uring_read(cfg, &scfg->task, scfg->buf + scfg->len, sizeof(scfg->buf) - scfg->len, scfg->len, scfg_read_cb); - return; - } else { - /* EOF */ - scfg->buf[scfg->len] = '\0'; - uring_task_close_fd(cfg, &scfg->task); - scfg_parse(cfg, scfg); - server_commit(cfg, scfg); + *rkey = kvmap[i].key_value; + return true; } -} - -static void -scfg_open_cb(struct cfg *cfg, struct uring_task *task, int res) -{ - struct server *scfg = container_of(task, struct server, task); - - if (res < 0) { - fprintf(stderr, "Open failed\n"); - server_delete(cfg, scfg); - return; - } - - printf("Asked to read server cfg %s (fd %i)\n", scfg->name, res); - uring_task_set_fd(&scfg->task, res); - scfg->len = 0; - uring_read(cfg, &scfg->task, scfg->buf, sizeof(scfg->buf), 0, scfg_read_cb); -} - -static bool -scfg_valid_filename(const char *name) -{ - const char *suffix; - - if (!name) - return false; - if (name[0] == '\0') - return false; - if (name[0] == '.') - return false; - if ((suffix = strrchr(name, '.')) == NULL) - return false; - if (strcmp(suffix, ".server")) - return false; +out: + fprintf(stderr, "Invalid line\n"); + *rkey = 0; return true; } -struct inotify_ev { - struct uring_task task; - char buf[4096] __attribute__((aligned(__alignof__(struct inotify_event)))); -}; - -static void -inotify_free(struct uring_task *task) +bool +config_parse_header(struct cfg *cfg, const char *title, char **buf) { - struct inotify_ev *iev = container_of(task, struct inotify_ev, task); - struct cfg *cfg = container_of(task->parent, struct cfg, task); - - fprintf(stderr, "%s called\n", __func__); - if (!iev || !cfg) - die("%s: iev or cfg is NULL!?\n", __func__); - - free(iev); - cfg->iev = NULL; - uring_task_put(cfg, &cfg->task); -} - -static void -inotify_event_dump(const struct inotify_event *event) -{ - printf("Event:\n"); - printf(" * WD : %i\n", event->wd); - printf(" * Cookie : %" PRIu32 "\n", event->cookie); - printf(" * Length : %" PRIu32 "\n", event->len); - printf(" * Name : %s\n", event->name); - printf(" * Mask : %" PRIu32 "\n", event->mask); - if (event->mask & IN_ACCESS) - printf("\tIN_ACCESS\n"); - else if(event->mask & IN_MODIFY) - printf("\tIN_MODIFY\n"); - else if(event->mask & IN_ATTRIB) - printf("\tIN_ATTRIB\n"); - else if(event->mask & IN_CLOSE_WRITE) - printf("\tIN_CLOSE_WRITE\n"); - else if(event->mask & IN_CLOSE_NOWRITE) - printf("\tIN_CLOSE_NOWRITE\n"); - else if(event->mask & IN_OPEN) - printf("\tIN_OPEN\n"); - else if(event->mask & IN_MOVED_FROM) - printf("\tIN_MOVED_FROM\n"); - else if(event->mask & IN_MOVED_TO) - printf("\tIN_MOVED_TO\n"); - else if(event->mask & IN_CREATE) - printf("\tIN_CREATE\n"); - else if(event->mask & IN_DELETE) - printf("\tIN_DELETE\n"); - else if(event->mask & IN_DELETE_SELF) - printf("\tIN_DELETE_SELF\n"); - else if(event->mask & IN_MOVE_SELF) - printf("\tIN_MOVE_SELF\n"); - else if(event->mask & IN_UNMOUNT) - printf("\tIN_UNMOUNT\n"); - else if(event->mask & IN_Q_OVERFLOW) - printf("\tIN_Q_OVERFLOW\n"); - else if(event->mask & IN_IGNORED) - printf("\tIN_IGNORED\n"); - printf("\n"); -} - -static void -inotify_cb(struct cfg *cfg, struct uring_task *task, int res) -{ - struct inotify_ev *iev = container_of(task, struct inotify_ev, task); - const struct inotify_event *event; - char *ptr; - struct server *scfg; - - fprintf(stderr, "%s: ret is %i (ref %u)\n", __func__, res, task->refcount); - - if (task->dead) { - fprintf(stderr, "%s: task is dead\n", __func__); - uring_task_put(cfg, task); - return; - } - - if (res <= 0) - perrordie("inotify_read"); + char *line; - for (ptr = iev->buf; ptr < iev->buf + res; ptr += sizeof(struct inotify_event) + event->len) { - event = (const struct inotify_event *)ptr; + if (!cfg || !title || !buf || !*buf) + return false; - if (debuglvl > 0) - inotify_event_dump(event); + eat_whitespace_and_comments(buf); - if (event->mask & (IN_IGNORED | IN_MOVE_SELF | IN_DELETE_SELF | IN_UNMOUNT)) - die("Configuration directory gone, exiting\n"); + line = get_line(buf); + if (!line) { + printf("Cfg: premature EOF\n"); + return false; + } else { + char titlehdr[strlen(title) + 3]; - if (event->mask & IN_Q_OVERFLOW) { - error("inotify queue overflow!\n"); - continue; + sprintf(titlehdr, "[%s]", title); + if (strcmp(line, titlehdr)) { + printf("Invalid header: %s\n", line); + return false; } - - if (!scfg_valid_filename(event->name)) - continue; - - if (event->mask & (IN_MOVED_FROM | IN_DELETE)) - server_delete_by_name(cfg, event->name); - else if (event->mask & (IN_MOVED_TO | IN_CREATE | IN_CLOSE_WRITE)) { - scfg = server_new(cfg, event->name); - uring_openat(cfg, &scfg->task, event->name, scfg_open_cb); - } else - error("inotify: weird, unknown event: 0x%08x\n", event->mask); - } - - uring_read(cfg, &iev->task, iev->buf, sizeof(iev->buf), 0, inotify_cb); -} - -void -inotify_refdump(struct inotify_ev *iev) -{ - uring_task_refdump(&iev->task); -} - -void -scfg_stop_monitor_dir(struct cfg *cfg) -{ - if (!cfg->iev) { - fprintf(stderr, "%s called with no iev!\n", __func__); - return; } - fprintf(stderr, "%s called, closing fd %i\n", __func__, cfg->iev->task.fd); - uring_cancel(cfg, &cfg->iev->task); - cfg->iev = NULL; -} - -void -scfg_monitor_dir(struct cfg *cfg) -{ - int ifd; - int iwd; - struct inotify_ev *iev; - - iev = malloc(sizeof(*iev)); - if (!iev) - perrordie("malloc"); - - ifd = inotify_init1(IN_CLOEXEC); - if (ifd < 0) - perrordie("inotify_init1"); - - /* ln = IN_CREATE, cp/vi/mv = IN_CREATE, IN_OPEN, IN_CLOSE_WRITE */ - iwd = inotify_add_watch(ifd, ".", - IN_CLOSE_WRITE | IN_DELETE | IN_CREATE | - IN_DELETE_SELF | IN_MOVE_SELF | IN_MOVED_TO | - IN_MOVED_FROM | IN_DONT_FOLLOW | - IN_EXCL_UNLINK | IN_ONLYDIR ); - if (iwd < 0) - perrordie("inotify_add_watch"); - - uring_task_init(&iev->task, "iev", &cfg->task, inotify_free); - uring_task_set_fd(&iev->task, ifd); - cfg->iev = iev; - uring_read(cfg, &iev->task, iev->buf, sizeof(iev->buf), 0, inotify_cb); -} - -void -scfg_read_all(struct cfg *cfg) -{ - - DIR *cfgdir; - struct dirent *dent; - struct server *scfg; - - cfgdir = opendir("."); - if (!cfgdir) { - perror("opendir"); - free(cfg); - return; - } - - while ((dent = readdir(cfgdir)) != NULL) { - char *suffix; - - if (dent->d_name[0] == '.') - continue; - if (dent->d_type != DT_REG && dent->d_type != DT_UNKNOWN) - continue; - if ((suffix = strrchr(dent->d_name, '.')) == NULL) - continue; - if (strcmp(suffix, ".server")) - continue; - - scfg = server_new(cfg, dent->d_name); - uring_openat(cfg, &scfg->task, dent->d_name, scfg_open_cb); - } - - closedir(cfgdir); + return true; } - @@ -1,12 +1,29 @@ #ifndef fooconfighfoo #define fooconfighfoo -void scfg_monitor_dir(struct cfg *cfg); +enum cfg_value_type { + CFG_VAL_TYPE_INVALID, + CFG_VAL_TYPE_STRING, + CFG_VAL_TYPE_UINT16, + CFG_VAL_TYPE_ADDRS, +}; -void inotify_refdump(struct inotify_ev *iev); +struct cfg_key_value_map { + const char *key_name; + int key_value; + enum cfg_value_type value_type; +}; -void scfg_stop_monitor_dir(struct cfg *cfg); +union cfg_value { + const char *str; + uint16_t uint16; + struct list_head addr_list; /* FIXME: addrs */ +}; -void scfg_read_all(struct cfg *cfg); +bool config_parse_line(struct cfg *cfg, char **buf, + struct cfg_key_value_map *kvmap, + int *key, union cfg_value *value); + +bool config_parse_header(struct cfg *cfg, const char *title, char **buf); #endif diff --git a/inotify.h b/inotify.h deleted file mode 100644 index c70c6ef..0000000 --- a/inotify.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef fooconfighfoo -#define fooconfighfoo - -void scfg_monitor_dir(struct cfg *cfg); - -void inotify_refdump(struct inotify_ev *iev); - -void scfg_stop_monitor_dir(struct cfg *cfg); - -void scfg_read_all(struct cfg *cfg); - -#endif @@ -17,6 +17,7 @@ #include "uring.h" #include "config.h" #include "server.h" +#include "cfgdir.h" int debuglvl = 0; @@ -156,7 +157,7 @@ dump_tree(struct cfg *cfg) uring_task_refdump(&cfg->sev->task); uring_refdump(cfg->uev); if (cfg->iev) - inotify_refdump(cfg->iev); + cfgdir_refdump(cfg->iev); list_for_each_entry(server, &cfg->servers, list) server_refdump(server); fprintf(stderr, "============\n"); @@ -183,7 +184,7 @@ signalfd_read(struct cfg *cfg, struct uring_task *task, int res) } else { fprintf(stderr, "Got a signal to dump tree\n"); dump_tree(cfg); - scfg_stop_monitor_dir(cfg); + cfgdir_delete(cfg); list_for_each_entry_safe(server, stmp, &cfg->servers, list) server_delete(cfg, server); uring_read(cfg, &sev->task, &sev->buf, sizeof(sev->buf), 0, signalfd_read); @@ -274,9 +275,7 @@ main(int argc, char **argv) signalfd_init(cfg); - scfg_monitor_dir(cfg); - - scfg_read_all(cfg); + cfgdir_init(cfg); uring_event_loop(cfg); diff --git a/meson.build b/meson.build index afc5f0d..efa0cdb 100644 --- a/meson.build +++ b/meson.build @@ -4,6 +4,6 @@ uring = dependency('liburing') executable('ctest', 'ctest.c') executable('stest', 'stest.c') executable('mcproxy', - ['main.c', 'uring.c', 'server.c', 'config.c', 'utils.c'], + ['main.c', 'uring.c', 'server.c', 'cfgdir.c', 'config.c', 'utils.c'], dependencies: uring) |