Add configuration infrastructure

Rather than expecting parameters on the command line, this change
implemnets a little configration infrastructure, to allow the core
code to load configuration from a file in ${sysconfdir}.

Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
diff --git a/config.c b/config.c
new file mode 100644
index 0000000..6665677
--- /dev/null
+++ b/config.c
@@ -0,0 +1,143 @@
+
+#include <err.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+static const char *config_default_filename = SYSCONFDIR "/openbmc-console.conf";
+
+struct config_item {
+	char			*name;
+	char			*value;
+	struct config_item	*next;
+};
+
+struct config {
+	struct config_item	*items;
+};
+
+const char *config_get_value(struct config *config, const char *name)
+{
+	struct config_item *item;
+
+	for (item = config->items; item; item = item->next)
+		if (!strcasecmp(item->name, name))
+			return item->value;
+
+	return NULL;
+}
+
+static void config_parse(struct config *config, char *buf)
+{
+	struct config_item *item;
+	char *name, *value;
+	char *p, *line;
+	int rc;
+
+	for (p = NULL, line = strtok_r(buf, "\n", &p); line;
+			line = strtok_r(NULL, "\n", &p)) {
+
+		/* trim leading space */
+		for (;*line == ' ' || *line == '\t'; line++)
+			;
+
+		/* skip comments */
+		if (*line == '#')
+			continue;
+
+		name = value = NULL;
+
+		rc = sscanf(line, "%m[^ =] = %ms ", &name, &value);
+		if (rc != 2 || !strlen(name) || !strlen(value)) {
+			free(name);
+			free(value);
+			continue;
+		}
+
+		/* create a new item and add to our list */
+		item = malloc(sizeof(*item));
+		item->name = name;
+		item->value = value;
+		item->next = config->items;
+		config->items = item;
+	}
+}
+
+struct config *config_init(const char *filename)
+{
+	struct config *config;
+	struct stat statbuf;
+	size_t len, i;
+	char *buf;
+	int fd, rc;
+
+	if (!filename)
+		filename = config_default_filename;
+
+	fd = open(filename, O_RDONLY);
+	if (fd < 0) {
+		warn("Can't open configuration file %s", filename);
+		return NULL;
+	}
+
+	rc = fstat(fd, &statbuf);
+	if (rc) {
+		warn("Can't stat %s", filename);
+		goto err_close;
+	}
+
+	len = statbuf.st_size;
+
+	buf = malloc(len + 1);
+	for (i = 0; i < len;) {
+		rc = read(fd, buf + i, len - i);
+		if (rc < 0) {
+			warn("Can't read configuration file %s", filename);
+			goto err_free;
+
+		} else if (!rc) {
+			break;
+		}
+		i += rc;
+
+	}
+	buf[len] = '\0';
+
+	close(fd);
+
+	config = malloc(sizeof(*config));
+	config->items = NULL;
+
+	config_parse(config, buf);
+
+	free(buf);
+
+	return config;
+
+err_free:
+	free(buf);
+err_close:
+	close(fd);
+	return NULL;
+}
+
+void config_fini(struct config *config)
+{
+	struct config_item *item, *next;
+
+	for (item = config->items; item; item = next) {
+		next = item->next;
+		free(item->name);
+		free(item->value);
+		free(item);
+	}
+
+	free(config);
+}