Fix up config parser and allow comments

This commit is contained in:
Christopher Wellons
2019-02-03 17:35:03 -05:00
parent 7dc64226aa
commit 7693ce54e3
2 changed files with 76 additions and 42 deletions

View File

@@ -50,6 +50,7 @@ A SIGHUP signal requests a reload of the configuration file (`-f`).
The configuration file has similar syntax to OpenSSH. The configuration file has similar syntax to OpenSSH.
``` ```
# This is a comment
Port 22 Port 22
Delay 30000 Delay 30000
MaxLineLength 8 MaxLineLength 8

View File

@@ -1,4 +1,4 @@
#define _POSIX_C_SOURCE 200112L #define _POSIX_C_SOURCE 200809L
#include <time.h> #include <time.h>
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
@@ -338,11 +338,27 @@ config_set_max_line_length(struct config *c, const char *s, int hardfail)
} }
} }
static void enum config_key {
config_fail(const char *file, long lineno, int hardfail) KEY_INVALID,
KEY_PORT,
KEY_DELAY,
KEY_MAX_LINE_LENGTH,
KEY_MAX_CLIENTS,
};
static enum config_key
config_key_parse(const char *tok)
{ {
fprintf(stderr, "%s:%ld: Expected integer\n", file, lineno); static const char *const table[] = {
if (hardfail) exit(EXIT_FAILURE); [KEY_PORT] = "Port",
[KEY_DELAY] = "Delay",
[KEY_MAX_LINE_LENGTH] = "MaxLineLength",
[KEY_MAX_CLIENTS] = "MaxClients",
};
for (size_t i = 1; i < sizeof(table) / sizeof(*table); i++)
if (!strcmp(tok, table[i]))
return i;
return KEY_INVALID;
} }
static void static void
@@ -351,47 +367,64 @@ config_load(struct config *c, const char *file, int hardfail)
long lineno = 0; long lineno = 0;
FILE *f = fopen(file, "r"); FILE *f = fopen(file, "r");
if (f) { if (f) {
const char *delim = " \n"; size_t len = 0;
char line[256]; char *line = 0;
while (fgets(line, sizeof(line), f)) { while (getline(&line, &len, f) != -1) {
lineno++; lineno++;
/* Remove comments */
char *comment = strchr(line, '#');
if (comment)
*comment = 0;
/* Parse tokes on line */
char *save = 0; char *save = 0;
char *tok = strtok_r(line, delim, &save); char *tokens[3];
if (!tok) { int ntokens = 0;
continue; for (; ntokens < 3; ntokens++) {
} else if (!strcmp(tok, "Port")) { char *tok = strtok_r(ntokens ? 0 : line, " \r\n", &save);
tok = strtok_r(0, delim, &save); if (!tok)
if (tok) { break;
config_set_port(c, tok, hardfail); tokens[ntokens] = tok;
} else { }
config_fail(file, lineno, hardfail);
} switch (ntokens) {
} else if (!strcmp(tok, "Delay")) { case 0: /* Empty line */
tok = strtok_r(0, delim, &save); continue;
if (tok) { case 1:
config_set_delay(c, tok, hardfail); fprintf(stderr, "%s:%ld: Missing value\n", file, lineno);
} else { if (hardfail) exit(EXIT_FAILURE);
config_fail(file, lineno, hardfail); continue;
} case 2: /* Expected */
} else if (!strcmp(tok, "MaxLineLength")) { break;
tok = strtok_r(0, delim, &save); case 3:
if (tok) { fprintf(stderr, "%s:%ld: Too many values\n", file, lineno);
config_set_max_line_length(c, tok, hardfail); if (hardfail) exit(EXIT_FAILURE);
} else { continue;
config_fail(file, lineno, hardfail); }
}
} else if (!strcmp(tok, "MaxClients")) { enum config_key key = config_key_parse(tokens[0]);
tok = strtok_r(0, delim, &save); switch (key) {
if (tok) { case KEY_INVALID:
config_set_max_line_length(c, tok, hardfail); fprintf(stderr, "%s:%ld: Unknown option '%s'\n",
} else { file, lineno, tokens[0]);
config_fail(file, lineno, hardfail); break;
} case KEY_PORT:
} else { config_set_port(c, tokens[1], hardfail);
fprintf(stderr, "%s:%ld: Unknown option '%s'\n", break;
file, lineno, tok); case KEY_DELAY:
config_set_delay(c, tokens[1], hardfail);
break;
case KEY_MAX_LINE_LENGTH:
config_set_max_line_length(c, tokens[1], hardfail);
break;
case KEY_MAX_CLIENTS:
config_set_max_line_length(c, tokens[1], hardfail);
break;
} }
} }
free(line);
fclose(f); fclose(f);
} }
} }