summaryrefslogtreecommitdiffstats
path: root/lib/pb-config
diff options
context:
space:
mode:
authorJeremy Kerr <jk@ozlabs.org>2013-05-29 17:24:42 +1000
committerJeremy Kerr <jk@ozlabs.org>2013-06-24 13:07:22 +0800
commit32fe8024f5af5cd8de23c638ddad8ada67a46cd5 (patch)
treecd64dcd7c093f7d10fe9325e5b1c5479aadfe01a /lib/pb-config
parent0f9597ab801ad4591e943bd7efcb8f1549997fdd (diff)
downloadtalos-petitboot-32fe8024f5af5cd8de23c638ddad8ada67a46cd5.tar.gz
talos-petitboot-32fe8024f5af5cd8de23c638ddad8ada67a46cd5.zip
lib: Add pb-config module
Add a library for (name, value) configuration. Different storage backends are allowed (although currently hardcoded to powerpc nvram), and config is read-only at present. Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
Diffstat (limited to 'lib/pb-config')
-rw-r--r--lib/pb-config/pb-config.c81
-rw-r--r--lib/pb-config/pb-config.h39
-rw-r--r--lib/pb-config/storage-null.c19
-rw-r--r--lib/pb-config/storage-powerpc-nvram.c323
-rw-r--r--lib/pb-config/storage-test.c56
-rw-r--r--lib/pb-config/storage.h17
6 files changed, 535 insertions, 0 deletions
diff --git a/lib/pb-config/pb-config.c b/lib/pb-config/pb-config.c
new file mode 100644
index 0000000..9f7d240
--- /dev/null
+++ b/lib/pb-config/pb-config.c
@@ -0,0 +1,81 @@
+
+#include <log/log.h>
+#include <talloc/talloc.h>
+
+#include "pb-config.h"
+
+#include "storage.h"
+
+static struct config *config;
+static struct config_storage *storage;
+
+
+static void config_set_defaults(struct config *config)
+{
+ config->autoboot_enabled = true;
+ config->network_configs = NULL;
+ config->n_network_configs = 0;
+}
+
+static void dump_config(struct config *config)
+{
+ int i;
+
+ pb_log("configuration:\n");
+
+ pb_log(" autoboot enabled: %s\n",
+ config->autoboot_enabled ? "yes" : "no");
+
+ if (config->n_network_configs > 0)
+ pb_log(" network configuration:\n");
+
+ for (i = 0; i < config->n_network_configs; i++) {
+ struct network_config *netconf = config->network_configs[i];
+
+ pb_log(" interface %02x:%02x:%02x:%02x:%02x:%02x\n",
+ netconf->hwaddr[0], netconf->hwaddr[1],
+ netconf->hwaddr[2], netconf->hwaddr[3],
+ netconf->hwaddr[4], netconf->hwaddr[5]);
+
+ if (netconf->ignore) {
+ pb_log(" ignore\n");
+ continue;
+ }
+
+ if (netconf->method == CONFIG_METHOD_DHCP) {
+ pb_log(" dhcp\n");
+
+ } else if (netconf->method == CONFIG_METHOD_STATIC) {
+ pb_log(" static:\n");
+ pb_log(" ip: %s\n", netconf->static_config.address);
+ pb_log(" gw: %s\n", netconf->static_config.gateway);
+ pb_log(" dns: %s\n", netconf->static_config.dns);
+
+ }
+ }
+}
+
+int config_init(void *ctx)
+{
+ config = talloc(ctx, struct config);
+ config_set_defaults(config);
+
+ storage = create_powerpc_nvram_storage(config);
+
+ storage->load(storage, config);
+
+ dump_config(config);
+
+ return 0;
+}
+
+const struct config *config_get(void)
+{
+ return config;
+}
+
+int config_fini(void)
+{
+ talloc_free(config);
+ return 0;
+}
diff --git a/lib/pb-config/pb-config.h b/lib/pb-config/pb-config.h
new file mode 100644
index 0000000..cfcf025
--- /dev/null
+++ b/lib/pb-config/pb-config.h
@@ -0,0 +1,39 @@
+#ifndef CONFIGURATION_H
+#define CONFIGURATION_H
+
+#include <stdbool.h>
+#include <stdint.h>
+
+#define HWADDR_SIZE 6
+
+struct network_config {
+ uint8_t hwaddr[HWADDR_SIZE];
+ bool ignore;
+ enum {
+ CONFIG_METHOD_DHCP,
+ CONFIG_METHOD_STATIC,
+ } method;
+ union {
+ struct {
+ } dhcp_config;
+ struct {
+ char *address;
+ char *gateway;
+ char *dns;
+ } static_config;
+ };
+};
+
+struct config {
+ bool autoboot_enabled;
+ struct network_config **network_configs;
+ int n_network_configs;
+};
+
+
+int config_init(void *ctx);
+const struct config *config_get(void);
+int config_fini(void);
+
+#endif /* CONFIGURATION_H */
+
diff --git a/lib/pb-config/storage-null.c b/lib/pb-config/storage-null.c
new file mode 100644
index 0000000..b9fe6ed
--- /dev/null
+++ b/lib/pb-config/storage-null.c
@@ -0,0 +1,19 @@
+
+#include <stdlib.h>
+
+#include "storage.h"
+
+static int load(struct config_storage *st __attribute__((unused)),
+ struct config *config __attribute__((unused)))
+{
+ return 0;
+}
+
+static struct config_storage st = {
+ .load = load,
+};
+
+struct config_storage *create_null_storage(void *ctx __attribute__((unused)))
+{
+ return &st;
+}
diff --git a/lib/pb-config/storage-powerpc-nvram.c b/lib/pb-config/storage-powerpc-nvram.c
new file mode 100644
index 0000000..4e4d29a
--- /dev/null
+++ b/lib/pb-config/storage-powerpc-nvram.c
@@ -0,0 +1,323 @@
+
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <talloc/talloc.h>
+#include <list/list.h>
+#include <log/log.h>
+
+#include "pb-config.h"
+#include "storage.h"
+
+static const char *partition = "common";
+static const char *prefix = "petitboot,";
+
+struct param {
+ char *name;
+ char *value;
+ bool modified;
+ struct list_item list;
+};
+
+struct powerpc_nvram_storage {
+ struct config_storage storage;
+ struct list params;
+};
+
+#define to_powerpc_nvram_storage(s) \
+ container_of(s, struct powerpc_nvram_storage, storage)
+
+/* a partition max a max size of 64k * 16bytes = 1M */
+static const int max_partition_size = 64 * 1024 * 16;
+
+static int parse_nvram_params(struct powerpc_nvram_storage *nv,
+ char *buf, int len)
+{
+ char *pos, *name, *value;
+ unsigned int paramlen;
+ int i, count;
+
+ /* discard 2 header lines:
+ * "common" partiton"
+ * ------------------
+ */
+ pos = buf;
+ count = 0;
+
+ for (i = 0; i < len; i++) {
+ if (pos[i] == '\n')
+ count++;
+ if (count == 2)
+ break;
+ }
+
+ if (i == len) {
+ fprintf(stderr, "failure parsing nvram output\n");
+ return -1;
+ }
+
+ for (pos = buf + i; pos < buf + len; pos += paramlen) {
+ unsigned int namelen;
+ struct param *param;
+
+ paramlen = strlen(pos);
+
+ name = pos;
+ value = strchr(pos, '=');
+ if (!value)
+ continue;
+
+ namelen = name - value;
+ if (namelen <= strlen(prefix))
+ continue;
+
+ if (strncmp(name, prefix, strlen(prefix)))
+ continue;
+
+ name += strlen(prefix);
+ value++;
+
+ param = talloc(nv, struct param);
+ param->modified = false;
+ param->name = talloc_strndup(nv, name, namelen);
+ param->value = talloc_strdup(nv, value);
+ list_add(&nv->params, &param->list);
+ }
+
+ return 0;
+}
+
+static int parse_nvram(struct powerpc_nvram_storage *nv)
+{
+ int rc, len, buf_len;
+ int pipefds[2], status;
+ char *buf;
+ pid_t pid;
+
+ rc = pipe(pipefds);
+ if (rc) {
+ perror("pipe");
+ return -1;
+ }
+
+ pid = fork();
+
+ if (pid < 0) {
+ perror("fork");
+ return -1;
+ }
+
+ if (pid == 0) {
+ close(STDIN_FILENO);
+ close(pipefds[0]);
+ dup2(pipefds[1], STDOUT_FILENO);
+ execlp("nvram", "nvram", "--print-config",
+ "--partition", partition, NULL);
+ exit(EXIT_FAILURE);
+ }
+
+ close(pipefds[1]);
+
+ len = 0;
+ buf_len = max_partition_size;
+ buf = talloc_array(nv, char, buf_len);
+
+ for (;;) {
+ rc = read(pipefds[0], buf + len, buf_len - len);
+
+ if (rc < 0) {
+ perror("read");
+ break;
+ }
+
+ if (rc == 0)
+ break;
+
+ len += rc;
+ }
+
+ waitpid(pid, &status, 0);
+ if (!WIFEXITED(status) || WEXITSTATUS(status)) {
+ fprintf(stderr, "nvram process returned "
+ "non-zero exit status\n");
+ return -1;
+ }
+
+ if (rc < 0)
+ return rc;
+
+ return parse_nvram_params(nv, buf, len);
+}
+
+static const char *get_param(struct powerpc_nvram_storage *nv,
+ const char *name)
+{
+ struct param *param;
+
+ list_for_each_entry(&nv->params, param, list)
+ if (!strcmp(param->name, name))
+ return param->value;
+ return NULL;
+}
+
+static int parse_hwaddr(struct network_config *config, char *str)
+{
+ int i;
+
+ if (strlen(str) != strlen("00:00:00:00:00:00"))
+ return -1;
+
+ for (i = 0; i < HWADDR_SIZE; i++) {
+ char byte[3], *endp;
+ unsigned long x;
+
+ byte[0] = str[i * 3 + 0];
+ byte[1] = str[i * 3 + 1];
+ byte[2] = '\0';
+
+ x = strtoul(byte, &endp, 16);
+ if (endp != byte + 2)
+ return -1;
+
+ config->hwaddr[i] = x & 0xff;
+ }
+
+ return 0;
+}
+
+static int parse_one_network_config(struct network_config *config,
+ char *confstr)
+{
+ char *tok, *saveptr;
+
+ if (!confstr || !strlen(confstr))
+ return -1;
+
+ /* first token should be the mac address */
+ tok = strtok_r(confstr, ",", &saveptr);
+ if (!tok)
+ return -1;
+
+ if (parse_hwaddr(config, tok))
+ return -1;
+
+ /* second token is the method */
+ tok = strtok_r(NULL, ",", &saveptr);
+ if (!tok || !strlen(tok) || !strcmp(tok, "ignore")) {
+ config->ignore = true;
+ return 0;
+ }
+
+ if (!strcmp(tok, "dhcp")) {
+ config->method = CONFIG_METHOD_DHCP;
+
+ } else if (!strcmp(tok, "static")) {
+ config->method = CONFIG_METHOD_STATIC;
+
+ /* ip/mask, [optional] gateway, [optional] dns */
+ tok = strtok_r(NULL, ",", &saveptr);
+ if (!tok)
+ return -1;
+ config->static_config.address =
+ talloc_strdup(config, tok);
+
+ tok = strtok_r(NULL, ",", &saveptr);
+ if (tok) {
+ config->static_config.gateway =
+ talloc_strdup(config, tok);
+ tok = strtok_r(NULL, ",", &saveptr);
+ }
+
+ if (tok) {
+ config->static_config.dns =
+ talloc_strdup(config, tok);
+ }
+ } else {
+ pb_log("Unknown network configuration method %s\n", tok);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void populate_network_config(struct powerpc_nvram_storage *nv,
+ struct config *config)
+{
+ const char *cval;
+ char *val;
+ int i;
+
+ cval = get_param(nv, "network");
+ if (!cval || !strlen(cval))
+ return;
+
+ val = talloc_strdup(config, cval);
+
+ for (i = 0; ; i++) {
+ struct network_config *netconf;
+ char *tok, *saveptr;
+ int rc;
+
+ tok = strtok_r(i == 0 ? val : NULL, " ", &saveptr);
+ if (!tok)
+ break;
+
+ netconf = talloc(nv, struct network_config);
+
+ rc = parse_one_network_config(netconf, tok);
+ if (rc) {
+ talloc_free(netconf);
+ continue;
+ }
+
+ config->network_configs = talloc_realloc(nv,
+ config->network_configs,
+ struct network_config *,
+ ++config->n_network_configs);
+
+ config->network_configs[config->n_network_configs - 1] =
+ netconf;
+ }
+
+ talloc_free(val);
+}
+
+static void populate_config(struct powerpc_nvram_storage *nv,
+ struct config *config)
+{
+ const char *val;
+
+ /* if the "auto-boot?' property is present and "false", disable auto
+ * boot */
+ val = get_param(nv, "auto-boot?");
+ config->autoboot_enabled = !val || strcmp(val, "false");
+
+ populate_network_config(nv, config);
+}
+
+static int load(struct config_storage *st, struct config *config)
+{
+ struct powerpc_nvram_storage *nv = to_powerpc_nvram_storage(st);
+ int rc;
+
+ rc = parse_nvram(nv);
+ if (rc)
+ return rc;
+
+ populate_config(nv, config);
+
+ return 0;
+}
+
+struct config_storage *create_powerpc_nvram_storage(void *ctx)
+{
+ struct powerpc_nvram_storage *nv;
+
+ nv = talloc(ctx, struct powerpc_nvram_storage);
+ nv->storage.load = load;
+ list_init(&nv->params);
+
+ return &nv->storage;
+}
diff --git a/lib/pb-config/storage-test.c b/lib/pb-config/storage-test.c
new file mode 100644
index 0000000..ba4e952
--- /dev/null
+++ b/lib/pb-config/storage-test.c
@@ -0,0 +1,56 @@
+
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include "pb-config.h"
+#include "storage.h"
+
+struct network_config net1 = {
+ .hwaddr = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 },
+ .method = CONFIG_METHOD_DHCP,
+};
+
+struct network_config net2 = {
+ .hwaddr = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x56 },
+ .method = CONFIG_METHOD_STATIC,
+ .static_config = {
+ .address = "192.168.0.2/24",
+ .gateway = "192.168.0.1",
+ },
+};
+
+struct network_config *network_configs[] = { &net1, &net2 };
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
+
+struct config test_config = {
+ .autoboot_enabled = true,
+ .network_configs = network_configs,
+ .n_network_configs = ARRAY_SIZE(network_configs),
+};
+
+struct test_storage {
+ struct config_storage storage;
+ struct param *params;
+ int n_params;
+};
+
+static int load(struct config_storage *st __attribute__((unused)),
+ struct config *config)
+{
+ memcpy(config, &test_config, sizeof(test_config));
+ return 0;
+}
+
+static struct test_storage st = {
+ .storage = {
+ .load = load,
+ },
+};
+
+struct config_storage *create_test_storage(void *ctx __attribute__((unused)))
+{
+ return &st.storage;
+}
diff --git a/lib/pb-config/storage.h b/lib/pb-config/storage.h
new file mode 100644
index 0000000..a1d5269
--- /dev/null
+++ b/lib/pb-config/storage.h
@@ -0,0 +1,17 @@
+#ifndef STORAGE_H
+#define STORAGE_H
+
+#include <stdbool.h>
+
+struct config;
+
+struct config_storage {
+ int (*load)(struct config_storage *st, struct config *config);
+};
+
+struct config_storage *create_powerpc_nvram_storage(void *ctx);
+struct config_storage *create_test_storage(void *ctx);
+struct config_storage *create_null_storage(void *ctx);
+
+#endif /* STORAGE_H */
+
OpenPOWER on IntegriCloud