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/Makefile.am b/Makefile.am
index 3d0a9b0..d7272a6 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -5,12 +5,16 @@
AM_CFLAGS = -Wall -Wextra -Werror
-console_server_CPPFLAGS = -DLOCALSTATEDIR=\"$(localstatedir)\"
+EXTRA_DIST = openbmc-console.conf.sample
+
+console_server_CPPFLAGS = -DLOCALSTATEDIR=\"$(localstatedir)\" \
+ -DSYSCONFDIR=\"$(sysconfdir)\"
console_server_SOURCES = \
console-server.c \
console-server.h \
util.c \
+ config.c \
log-handler.c \
socket-handler.c
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);
+}
diff --git a/console-server.c b/console-server.c
index e0b4249..40e3a36 100644
--- a/console-server.c
+++ b/console-server.c
@@ -61,7 +61,7 @@
"usage: %s [options]\n"
"\n"
"Options:\n"
-" --device <TTY> Use serial device TTY (eg, ttyS0)\n"
+" --config <FILE> Use FILE for configuration\n"
"",
progname);
}
@@ -176,6 +176,43 @@
return 0;
}
+static int tty_init(struct console *console, struct config *config)
+{
+ const char *val;
+ char *endp;
+ int rc;
+
+ console->tty_kname = config_get_value(config, "device");
+
+ val = config_get_value(config, "lpc-address");
+ if (val) {
+ console->tty_lpc_addr = strtoul(val, &endp, 0);
+ if (endp == optarg) {
+ warn("Invalid LPC address: '%s'", val);
+ return -1;
+ }
+ }
+
+ val = config_get_value(config, "sirq");
+ if (val) {
+ console->tty_sirq = strtoul(val, &endp, 0);
+ if (endp == optarg)
+ warn("Invalid sirq: '%s'", val);
+ }
+
+ if (!console->tty_kname) {
+ warnx("Error: No TTY device specified");
+ return -1;
+ }
+
+ rc = tty_find_device(console);
+ if (rc)
+ return rc;
+
+ rc = tty_init_io(console);
+ return rc;
+}
+
int console_data_out(struct console *console, const uint8_t *data, size_t len)
{
@@ -419,73 +456,51 @@
return rc ? -1 : 0;
}
static const struct option options[] = {
- { "device", required_argument, 0, 'd'},
- { "sirq", required_argument, 0, 's'},
- { "lpc-addr", required_argument, 0, 'l'},
+ { "config", required_argument, 0, 'c'},
{ },
};
int main(int argc, char **argv)
{
+ const char *config_filename = NULL;
struct console *console;
- int rc, i;
+ struct config *config;
+ int rc;
- console = malloc(sizeof(struct console));
- memset(console, 0, sizeof(*console));
rc = -1;
for (;;) {
- char *endp;
int c, idx;
- c = getopt_long(argc, argv, "d:s:l:", options, &idx);
+ c = getopt_long(argc, argv, "c:", options, &idx);
if (c == -1)
break;
switch (c) {
- case 'd':
- console->tty_kname = optarg;
+ case 'c':
+ config_filename = optarg;
break;
- case 'l':
- console->tty_lpc_addr = strtoul(optarg, &endp, 0);
- if (endp == optarg) {
- warnx("Invalid sirq: '%s'", optarg);
- goto out_free;
- }
- break;
-
- case 's':
- console->tty_sirq = strtoul(optarg, &endp, 0);
- if (endp == optarg) {
- warnx("Invalid sirq: '%s'", optarg);
- goto out_free;
- }
- break;
-
case 'h':
case '?':
usage(argv[0]);
- rc = 0;
- goto out_free;
+ return EXIT_SUCCESS;
}
}
+ console = malloc(sizeof(struct console));
+ memset(console, 0, sizeof(*console));
console->pollfds = calloc(n_internal_pollfds,
sizeof(*console->pollfds));
- if (!console->tty_kname) {
- fprintf(stderr,
- "Error: No TTY device specified (use --device)\n");
- return EXIT_FAILURE;
+ config = config_init(config_filename);
+ if (!config) {
+ warnx("Can't read configuration, exiting.");
+ goto out_free;
}
- rc = tty_find_device(console);
+ rc = tty_init(console, config);
if (rc)
- return EXIT_FAILURE;
-
- rc = tty_init_io(console);
- if (rc)
- return EXIT_FAILURE;
+ goto out_config_fini;
handlers_init(console);
@@ -493,6 +508,9 @@
handlers_fini(console);
+out_config_fini:
+ config_fini(config);
+
out_free:
free(console->pollers);
free(console->pollfds);
diff --git a/console-server.h b/console-server.h
index 292b54a..dcedada 100644
--- a/console-server.h
+++ b/console-server.h
@@ -48,6 +48,12 @@
void console_unregister_poller(struct console *console, struct poller *poller);
+/* config API */
+struct config;
+const char *config_get_value(struct config *config, const char *name);
+struct config *config_init(const char *filename);
+void config_fini(struct config *config);
+
/* socket paths */
const char *console_socket_path;
const size_t console_socket_path_len;
diff --git a/openbmc-console.conf.sample b/openbmc-console.conf.sample
new file mode 100644
index 0000000..a5b8808
--- /dev/null
+++ b/openbmc-console.conf.sample
@@ -0,0 +1,6 @@
+# Device to use for our UART console
+device = ttyUSB0
+
+# For VUART devices, we can specify the LPC address and SIRQ parameters
+lpc-address = 0x3f8
+sirq = 4