#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <unistd.h>
#include <apr_general.h>
+#include <apr_strings.h>
#include "hostinfod.h"
-typedef int (*process_line_fn) (const char *key, const char *value);
-static void process_conf_file (const char *path, int exit_if_not_exist, process_line_fn process_line);
+typedef int (*process_line_fn) (const char *path, int lineno,
+ const char *key, const char *value);
+typedef int (*process_section_fn) (const char *path, int lineno,
+ const char *section);
+static void process_conf_file (const char *path, int exit_if_not_exist,
+ process_line_fn process_line,
+ process_section_fn process_section);
+static int get_bool (const char *str);
+
+/* Read the main configuration file. */
+static int main_process_line (const char *path, int lineno, const char *key, const char *value);
-/* Read the main configuration file. This file is NOT reread if it
- * changes, but the auxiliary guests.conf file IS reread (and so is
- * the socket directory of course).
- */
void
read_main_conf_file (void)
{
- process_conf_file (conf_file, 0, NULL);
+ process_conf_file (conf_file, 0, main_process_line, NULL);
}
+static int
+main_process_line (const char *path, int lineno,
+ const char *key, const char *value)
+{
+ int bool;
+
+ if (strcasecmp (key, "guests") == 0) {
+ if (!value) {
+ error ("%s:%d: directive is empty: %s", path, lineno, key);
+ return -1;
+ }
+ guests_file = apr_pstrdup (pool, value);
+ } else if (strcasecmp (key, "sockets") == 0) {
+ if (!value) {
+ error ("%s:%d: directive is empty: %s", path, lineno, key);
+ return -1;
+ }
+ socket_dir = apr_pstrdup (pool, value);
+ } else if (strcasecmp (key, "verbose") == 0) {
+ bool = get_bool (value);
+ if (bool == -1) {
+ error ("%s:%d: %s: not a valid boolean - use 1 or 0", path, lineno, key);
+ return -1;
+ }
+ if (!verbose_set_on_cmdline)
+ verbose = bool;
+ } else if (strcasecmp (key, "foreground") == 0) {
+ bool = get_bool (value);
+ if (bool == -1) {
+ error ("%s:%d: %s: not a valid boolean - use 1 or 0", path, lineno, key);
+ return -1;
+ }
+ if (!foreground_set_on_cmdline)
+ foreground = bool;
+ } else {
+ error ("%s:%d: unknown directive in configuration file: %s",
+ path, lineno, key);
+ return -1;
+ }
+ return 0;
+}
+
+/* Configuration file parser. */
static void
process_conf_file (const char *path, int exit_if_not_exist,
- process_line_fn process_line)
+ process_line_fn process_line,
+ process_section_fn process_section)
{
static const char *whitespace = " \t\n\v";
FILE *fp;
char *line = NULL;
+ int lineno = 0;
size_t len = 0;
size_t real_len, key_len;
ssize_t r;
const char *key, *value;
+ debug ("begin processing configuration file %s", path);
+
fp = fopen (path, "r");
if (!fp) {
if (exit_if_not_exist) {
- perror (path);
+ perrorf ("%s", path);
exit (1);
- }
+ } else
+ pwarningf ("%s", path);
return;
}
while ((r = getline (&line, &len, fp)) != -1) {
+ lineno++;
+
+ /*debug ("%s:%d: '%s' (len = %d)", path, lineno, line, len);*/
+
/* Remove trailing \n */
- real_len = len;
+ real_len = strlen (line);
if (real_len > 0 && line[real_len-1] == '\n')
line[--real_len] = '\0';
if (line[0] == '#' || strspn (line, whitespace) == real_len)
continue;
- /* Split into key value. */
- key_len = strcspn (line, whitespace);
- line[key_len] = '\0';
- key = line;
- value = key_len < real_len ? &line[key_len+1] : NULL;
- if (value) {
- value += strspn (line, whitespace);
- if (value[0] == '\0')
- value = NULL;
+ if (line[0] == '[') { /* Section. */
+ if (line[real_len-1] == ']')
+ line[--real_len] = '\0';
+ else {
+ error ("%s:%d: in section header, ']' not found (is there trailing whitespace or a comment?), near: %s",
+ path, lineno, line);
+ exit (1);
+ }
+
+ debug ("configuration file: section [%s]", line);
+
+ if (!process_section) {
+ error ("%s:%d: unexpected section header ([%s]) in file",
+ path, lineno, line);
+ exit (1);
+ }
+
+ if (process_section (path, lineno, line) == -1)
+ exit (1);
}
+ else { /* Key value */
+ key_len = strcspn (line, whitespace);
+ line[key_len] = '\0';
+ key = line;
+ value = key_len < real_len ? &line[key_len+1] : NULL;
+ if (value) {
+ value += strspn (line, whitespace);
+ if (value[0] == '\0')
+ value = NULL;
+ }
- if (process_line && process_line (key, value) == -1)
- exit (1);
+ debug ("configuration file: key '%s', value '%s'", key, value);
+
+ if (process_line && process_line (path, lineno, key, value) == -1)
+ exit (1);
+ }
}
free (line);
if (ferror (fp)) {
- fprintf (stderr, "error reading configuration file: %s\n", path);
+ error ("%s: error reading configuration file", path);
exit (1);
}
if (fclose (fp) == EOF) {
- perror (path);
+ perrorf ("%s", path);
exit (1);
}
+
+ debug ("finished processing configuration file successfully");
+}
+
+static int
+get_bool (const char *str)
+{
+ if (!str)
+ return -1;
+
+ if (strcasecmp (str, "on") == 0)
+ return 1;
+ if (strcasecmp (str, "off") == 0)
+ return 0;
+
+ switch (str[0]) {
+ case '1': case 'y': case 'Y': case 't': case 'T': case 'e': case 'E':
+ return 1;
+ case '0': case 'n': case 'N': case 'f': case 'F': case 'd': case 'D':
+ return 0;
+ }
+
+ return -1;
}