From: Jeremy Kerr Date: Wed, 29 Jan 2014 05:28:06 +0000 (+0800) Subject: pb-config: Move config storage modules to "platform" modules in discover code X-Git-Tag: v1.0.0~249 X-Git-Url: https://git.ozlabs.org/?p=petitboot;a=commitdiff_plain;h=c14b12980885edd035322cd3bc87efff444c39b1 pb-config: Move config storage modules to "platform" modules in discover code There's no need to include the config storage code in lib/ as only the discover server should be using it. This change moves the config-storage code to discover/, with the platform-specific parts moved to a 'struct platform'. Each platform has a probe function, which is called during init. The first probe function to return a platform is used. At present we only have the one platform, but it's now non-intrusive to add others. We keep an array of platform pointers in a separate ("platforms") section, to allow the test module to drop-in its own test "platform". Signed-off-by: Jeremy Kerr --- diff --git a/discover/Makefile.am b/discover/Makefile.am index 84c0436..5d5f5b4 100644 --- a/discover/Makefile.am +++ b/discover/Makefile.am @@ -54,6 +54,9 @@ pb_discover_SOURCES = \ paths.h \ pb-discover.c \ pb-discover.h \ + platform.c \ + platform.h \ + platform-powerpc.c \ resource.c \ resource.h \ sysinfo.c \ diff --git a/discover/device-handler.c b/discover/device-handler.c index d3256fa..c57b7b6 100644 --- a/discover/device-handler.c +++ b/discover/device-handler.c @@ -8,7 +8,6 @@ #include #include -#include #include #include #include @@ -19,6 +18,7 @@ #include "device-handler.h" #include "discover-server.h" +#include "platform.h" #include "event.h" #include "parser.h" #include "resource.h" diff --git a/discover/discover-server.c b/discover/discover-server.c index 3cf9fac..1765074 100644 --- a/discover/discover-server.c +++ b/discover/discover-server.c @@ -20,6 +20,7 @@ #include "device-handler.h" #include "discover-server.h" +#include "platform.h" #include "sysinfo.h" struct discover_server { diff --git a/discover/network.c b/discover/network.c index cf340da..9da0f7a 100644 --- a/discover/network.c +++ b/discover/network.c @@ -14,13 +14,13 @@ #include #include #include -#include #include #include #include "file.h" #include "network.h" #include "sysinfo.h" +#include "platform.h" #include "device-handler.h" #define HWADDR_SIZE 6 diff --git a/discover/pb-discover.c b/discover/pb-discover.c index d8708a3..bb590a9 100644 --- a/discover/pb-discover.c +++ b/discover/pb-discover.c @@ -11,7 +11,6 @@ #include #include -#include #include #include @@ -21,6 +20,7 @@ #include "device-handler.h" #include "network.h" #include "sysinfo.h" +#include "platform.h" static void print_version(void) { @@ -170,7 +170,7 @@ int main(int argc, char *argv[]) if (!procset) return EXIT_FAILURE; - config_init(NULL); + platform_init(NULL); if (opts.no_autoboot == opt_yes) config_set_autoboot(false); @@ -205,7 +205,7 @@ int main(int argc, char *argv[]) user_event_destroy(uev); udev_destroy(udev); discover_server_destroy(server); - config_fini(); + platform_fini(); talloc_free(waitset); pb_log("--- end ---\n"); diff --git a/discover/platform-powerpc.c b/discover/platform-powerpc.c new file mode 100644 index 0000000..e2a8631 --- /dev/null +++ b/discover/platform-powerpc.c @@ -0,0 +1,553 @@ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "platform.h" + +static const char *partition = "common"; + +struct param { + char *name; + char *value; + bool modified; + struct list_item list; +}; + +struct platform_powerpc { + struct list params; +}; + +static const char *known_params[] = { + "auto-boot?", + "petitboot,network", + "petitboot,timeout", + NULL, +}; + +#define to_platform_powerpc(p) \ + (struct platform_powerpc *)(p->platform_data) + +/* a partition max a max size of 64k * 16bytes = 1M */ +static const int max_partition_size = 64 * 1024 * 16; + +static bool param_is_known(const char *param, unsigned int len) +{ + const char *known_param; + unsigned int i; + + for (i = 0; known_params[i]; i++) { + known_param = known_params[i]; + if (len == strlen(known_param) && + !strncmp(param, known_param, len)) + return true; + } + + return false; +} + +static int parse_nvram_params(struct platform_powerpc *platform, + 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 + 1) { + unsigned int namelen; + struct param *param; + char *newline; + + newline = strchr(pos, '\n'); + if (!newline) + break; + + *newline = '\0'; + + paramlen = strlen(pos); + + name = pos; + value = strchr(pos, '='); + if (!value) + continue; + + namelen = value - name; + if (namelen == 0) + continue; + + if (!param_is_known(name, namelen)) + continue; + + value++; + + param = talloc(platform, struct param); + param->modified = false; + param->name = talloc_strndup(platform, name, namelen); + param->value = talloc_strdup(platform, value); + list_add(&platform->params, ¶m->list); + } + + return 0; +} + +static int parse_nvram(struct platform_powerpc *platform) +{ + struct process *process; + const char *argv[5]; + int rc; + + argv[0] = "nvram"; + argv[1] = "--print-config"; + argv[2] = "--partition"; + argv[3] = partition; + argv[4] = NULL; + + process = process_create(platform); + process->path = "nvram"; + process->argv = argv; + process->keep_stdout = true; + + rc = process_run_sync(process); + + if (rc || !process_exit_ok(process)) { + fprintf(stderr, "nvram process returned " + "non-zero exit status\n"); + rc = -1; + } else { + rc = parse_nvram_params(platform, process->stdout_buf, + process->stdout_len); + } + + process_release(process); + return rc; +} + +static int write_nvram(struct platform_powerpc *platform) +{ + struct process *process; + struct param *param; + const char *argv[6]; + int rc; + + argv[0] = "nvram"; + argv[1] = "--update-config"; + argv[2] = NULL; + argv[3] = "--partition"; + argv[4] = partition; + argv[5] = NULL; + + process = process_create(platform); + process->path = "nvram"; + process->argv = argv; + + list_for_each_entry(&platform->params, param, list) { + char *paramstr; + + if (!param->modified) + continue; + + paramstr = talloc_asprintf(platform, "%s=%s", + param->name, param->value); + argv[2] = paramstr; + + rc = process_run_sync(process); + + talloc_free(paramstr); + + if (rc || !process_exit_ok(process)) { + rc = -1; + pb_log("nvram update process returned " + "non-zero exit status\n"); + break; + } + } + + process_release(process); + return rc; +} + +static const char *get_param(struct platform_powerpc *platform, + const char *name) +{ + struct param *param; + + list_for_each_entry(&platform->params, param, list) + if (!strcmp(param->name, name)) + return param->value; + return NULL; +} + +static void set_param(struct platform_powerpc *platform, const char *name, + const char *value) +{ + struct param *param; + + list_for_each_entry(&platform->params, param, list) { + if (strcmp(param->name, name)) + continue; + + if (!strcmp(param->value, value)) + return; + + talloc_free(param->value); + param->value = talloc_strdup(param, value); + param->modified = true; + return; + } + + + param = talloc(platform, struct param); + param->modified = true; + param->name = talloc_strdup(platform, name); + param->value = talloc_strdup(platform, value); + list_add(&platform->params, ¶m->list); +} + +static int parse_hwaddr(struct interface_config *ifconf, 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; + + ifconf->hwaddr[i] = x & 0xff; + } + + return 0; +} + +static int parse_one_interface_config(struct config *config, + char *confstr) +{ + struct interface_config *ifconf; + char *tok, *saveptr; + + ifconf = talloc_zero(config, struct interface_config); + + if (!confstr || !strlen(confstr)) + goto out_err; + + /* first token should be the mac address */ + tok = strtok_r(confstr, ",", &saveptr); + if (!tok) + goto out_err; + + if (parse_hwaddr(ifconf, tok)) + goto out_err; + + /* second token is the method */ + tok = strtok_r(NULL, ",", &saveptr); + if (!tok || !strlen(tok) || !strcmp(tok, "ignore")) { + ifconf->ignore = true; + + } else if (!strcmp(tok, "dhcp")) { + ifconf->method = CONFIG_METHOD_DHCP; + + } else if (!strcmp(tok, "static")) { + ifconf->method = CONFIG_METHOD_STATIC; + + /* ip/mask, [optional] gateway */ + tok = strtok_r(NULL, ",", &saveptr); + if (!tok) + goto out_err; + ifconf->static_config.address = + talloc_strdup(ifconf, tok); + + tok = strtok_r(NULL, ",", &saveptr); + if (tok) { + ifconf->static_config.gateway = + talloc_strdup(ifconf, tok); + } + + } else { + pb_log("Unknown network configuration method %s\n", tok); + goto out_err; + } + + config->network.interfaces = talloc_realloc(config, + config->network.interfaces, + struct interface_config *, + ++config->network.n_interfaces); + + config->network.interfaces[config->network.n_interfaces - 1] = ifconf; + + return 0; +out_err: + talloc_free(ifconf); + return -1; +} + +static int parse_one_dns_config(struct config *config, + char *confstr) +{ + char *tok, *saveptr; + + for (tok = strtok_r(confstr, ",", &saveptr); tok; + tok = strtok_r(NULL, ",", &saveptr)) { + + char *server = talloc_strdup(config, tok); + + config->network.dns_servers = talloc_realloc(config, + config->network.dns_servers, const char *, + ++config->network.n_dns_servers); + + config->network.dns_servers[config->network.n_dns_servers - 1] + = server; + } + + return 0; +} + +static void populate_network_config(struct platform_powerpc *platform, + struct config *config) +{ + const char *cval; + char *val; + int i; + + cval = get_param(platform, "petitboot,network"); + if (!cval || !strlen(cval)) + return; + + val = talloc_strdup(config, cval); + + for (i = 0; ; i++) { + char *tok, *saveptr; + + tok = strtok_r(i == 0 ? val : NULL, " ", &saveptr); + if (!tok) + break; + + if (!strncasecmp(tok, "dns,", strlen("dns,"))) + parse_one_dns_config(config, tok + strlen("dns,")); + else + parse_one_interface_config(config, tok); + + } + + talloc_free(val); +} + +static void populate_config(struct platform_powerpc *platform, + struct config *config) +{ + const char *val; + char *end; + unsigned long timeout; + + /* if the "auto-boot?' property is present and "false", disable auto + * boot */ + val = get_param(platform, "auto-boot?"); + config->autoboot_enabled = !val || strcmp(val, "false"); + + val = get_param(platform, "petitboot,timeout"); + if (val) { + timeout = strtoul(val, &end, 10); + if (end != val) { + if (timeout >= INT_MAX) + timeout = INT_MAX; + config->autoboot_timeout_sec = (int)timeout; + } + } + + populate_network_config(platform, config); +} + +static char *iface_config_str(void *ctx, struct interface_config *config) +{ + char *str; + + /* todo: HWADDR size is hardcoded as 6, but we may need to handle + * different hardware address formats */ + str = talloc_asprintf(ctx, "%02x:%02x:%02x:%02x:%02x:%02x,", + config->hwaddr[0], config->hwaddr[1], + config->hwaddr[2], config->hwaddr[3], + config->hwaddr[4], config->hwaddr[5]); + + if (config->ignore) { + str = talloc_asprintf_append(str, "ignore"); + + } else if (config->method == CONFIG_METHOD_DHCP) { + str = talloc_asprintf_append(str, "dhcp"); + + } else if (config->method == CONFIG_METHOD_STATIC) { + str = talloc_asprintf_append(str, "static,%s%s%s", + config->static_config.address, + config->static_config.gateway ? "," : "", + config->static_config.gateway ?: ""); + } + return str; +} + +static char *dns_config_str(void *ctx, const char **dns_servers, int n) +{ + char *str; + int i; + + str = talloc_strdup(ctx, "dns,"); + for (i = 0; i < n; i++) { + str = talloc_asprintf_append(str, "%s%s", + i == 0 ? "" : ",", + dns_servers[i]); + } + + return str; +} + +static void update_string_config(struct platform_powerpc *platform, + const char *name, const char *value) +{ + const char *cur; + + cur = get_param(platform, name); + + /* don't set an empty parameter if it doesn't already exist */ + if (!cur && !strlen(value)) + return; + + set_param(platform, name, value); +} + +static void update_network_config(struct platform_powerpc *platform, + struct config *config) +{ + unsigned int i; + char *val; + + val = talloc_strdup(platform, ""); + + for (i = 0; i < config->network.n_interfaces; i++) { + char *iface_str = iface_config_str(platform, + config->network.interfaces[i]); + val = talloc_asprintf_append(val, "%s%s", + *val == '\0' ? "" : " ", iface_str); + talloc_free(iface_str); + } + + if (config->network.n_dns_servers) { + char *dns_str = dns_config_str(platform, + config->network.dns_servers, + config->network.n_dns_servers); + val = talloc_asprintf_append(val, "%s%s", + *val == '\0' ? "" : " ", dns_str); + talloc_free(dns_str); + } + + update_string_config(platform, "petitboot,network", val); + + talloc_free(val); +} + +static int update_config(struct platform_powerpc *platform, + struct config *config, struct config *defaults) +{ + char *tmp = NULL; + const char *val; + + if (config->autoboot_enabled == defaults->autoboot_enabled) + val = ""; + else + val = config->autoboot_enabled ? "true" : "false"; + update_string_config(platform, "auto-boot?", val); + + if (config->autoboot_timeout_sec == defaults->autoboot_timeout_sec) + val = ""; + else + val = tmp = talloc_asprintf(platform, "%d", + config->autoboot_timeout_sec); + + update_string_config(platform, "petitboot,timeout", val); + if (tmp) + talloc_free(tmp); + + update_network_config(platform, config); + + return write_nvram(platform); +} + +static int load_config(struct platform *p, struct config *config) +{ + struct platform_powerpc *platform = to_platform_powerpc(p); + int rc; + + rc = parse_nvram(platform); + if (rc) + return rc; + + populate_config(platform, config); + + return 0; +} + +static int save_config(struct platform *p, struct config *config) +{ + struct platform_powerpc *platform = to_platform_powerpc(p); + struct config *defaults; + int rc; + + defaults = talloc_zero(platform, struct config); + config_set_defaults(defaults); + + rc = update_config(platform, config, defaults); + + talloc_free(defaults); + return rc; +} + +static bool probe(struct platform *p, void *ctx) +{ + struct platform_powerpc *platform; + + platform = talloc(ctx, struct platform_powerpc); + list_init(&platform->params); + + p->platform_data = platform; + return true; +} + +static struct platform platform_powerpc = { + .name = "powerpc", + .probe = probe, + .load_config = load_config, + .save_config = save_config, +}; + +register_platform(platform_powerpc); diff --git a/discover/platform.c b/discover/platform.c new file mode 100644 index 0000000..66e776e --- /dev/null +++ b/discover/platform.c @@ -0,0 +1,157 @@ + +#include + +#include +#include +#include + +#include "platform.h" + +void *platform_ctx; +static struct platform *platform; +static struct config *config; + +static void dump_config(struct config *config) +{ + unsigned int i; + + pb_log("configuration:\n"); + + if (config->autoboot_enabled) + pb_log(" autoboot: enabled, %d sec\n", + config->autoboot_timeout_sec); + else + pb_log(" autoboot: disabled\n"); + + if (config->network.n_interfaces || config->network.n_dns_servers) + pb_log(" network configuration:\n"); + + for (i = 0; i < config->network.n_interfaces; i++) { + struct interface_config *ifconf = + config->network.interfaces[i]; + + pb_log(" interface %02x:%02x:%02x:%02x:%02x:%02x\n", + ifconf->hwaddr[0], ifconf->hwaddr[1], + ifconf->hwaddr[2], ifconf->hwaddr[3], + ifconf->hwaddr[4], ifconf->hwaddr[5]); + + if (ifconf->ignore) { + pb_log(" ignore\n"); + continue; + } + + if (ifconf->method == CONFIG_METHOD_DHCP) { + pb_log(" dhcp\n"); + + } else if (ifconf->method == CONFIG_METHOD_STATIC) { + pb_log(" static:\n"); + pb_log(" ip: %s\n", ifconf->static_config.address); + pb_log(" gw: %s\n", ifconf->static_config.gateway); + + } + } + for (i = 0; i < config->network.n_dns_servers; i++) + pb_log(" dns server %s\n", config->network.dns_servers[i]); +} + +void config_set_defaults(struct config *config) +{ + config->autoboot_enabled = true; + config->autoboot_timeout_sec = 10; + config->network.interfaces = NULL; + config->network.n_interfaces = 0; + config->network.dns_servers = NULL; + config->network.n_dns_servers = 0; + + config->n_boot_priorities = 2; + config->boot_priorities = talloc_array(config, struct boot_priority, + config->n_boot_priorities); + config->boot_priorities[0].type = DEVICE_TYPE_NETWORK; + config->boot_priorities[1].type = DEVICE_TYPE_DISK; + +} + +int platform_init(void *ctx) +{ + extern struct platform *__start_platforms, *__stop_platforms; + struct platform **p; + + platform_ctx = talloc_new(ctx); + + for (p = &__start_platforms; p < &__stop_platforms; p++) { + if (!(*p)->probe(*p, platform_ctx)) + continue; + platform = *p; + break; + } + + config = talloc(platform_ctx, struct config); + config_set_defaults(config); + + if (platform) { + pb_log("Detected platform type: %s\n", platform->name); + if (platform->load_config) + platform->load_config(platform, config); + } else { + pb_log("No platform type detected, some platform-specific " + "functionality will be disabled\n"); + } + + dump_config(config); + + return 0; +} + +int config_set(struct config *newconfig) +{ + int rc; + + if (!platform || !platform->save_config) + return -1; + + if (newconfig == config) + return 0; + + pb_log("new configuration data received\n"); + dump_config(newconfig); + + rc = platform->save_config(platform, newconfig); + + if (!rc) + config = talloc_steal(platform_ctx, newconfig); + else + pb_log("error saving new configuration; changes lost\n"); + + return rc; +} + +/* A non-exported function to allow the test infrastructure to initialise + * (and change) the configuration variables */ +struct parser_test; +struct config __attribute__((unused)) *test_config_init( + struct parser_test *test); +struct config *test_config_init(struct parser_test *test) +{ + config = talloc(test, struct config); + config_set_defaults(config); + return config; +} + +const struct config *config_get(void) +{ + return config; +} + +void config_set_autoboot(bool autoboot_enabled) +{ + config->autoboot_enabled = autoboot_enabled; + + pb_log("set autoboot: %s\n", + config->autoboot_enabled ? "enabled" : "disabled"); +} + +int platform_fini(void) +{ + talloc_free(platform_ctx); + return 0; +} diff --git a/discover/platform.h b/discover/platform.h new file mode 100644 index 0000000..44315fa --- /dev/null +++ b/discover/platform.h @@ -0,0 +1,34 @@ +#ifndef PLATFORM_H +#define PLATFORM_H + +#include + +struct platform { + const char *name; + bool (*probe)(struct platform *, void *); + int (*load_config)(struct platform *, struct config *); + int (*save_config)(struct platform *, struct config *); + void *platform_data; +}; + +int platform_init(void *ctx); +int platform_fini(void); + +/* configuration interface */ +const struct config *config_get(void); +int config_set(struct config *config); +void config_set_autoboot(bool autoboot_enabled); + +/* for use by the platform-specific storage code */ +void config_set_defaults(struct config *config); + +#define __platform_ptrname(_n) __platform_ ## _n +#define _platform_ptrname(_n) __platform_ptrname(_n) + +#define register_platform(p) \ + static __attribute__((section("platforms"))) \ + __attribute__((used)) \ + struct platform * _platform_ptrname(__COUNTER__) = &p; + +#endif /* PLATFORM_H */ + diff --git a/lib/Makefile.am b/lib/Makefile.am index e3ec2dc..1c19e11 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -30,10 +30,6 @@ libpbcore_la_SOURCES = \ pb-protocol/pb-protocol.h \ pb-config/pb-config.c \ pb-config/pb-config.h \ - pb-config/storage.h \ - pb-config/storage-powerpc-nvram.c \ - pb-config/storage-null.c \ - pb-config/storage-test.c \ process/process.c \ process/process.h \ types/types.h \ diff --git a/lib/pb-config/pb-config.c b/lib/pb-config/pb-config.c index 9f696d5..35008cc 100644 --- a/lib/pb-config/pb-config.c +++ b/lib/pb-config/pb-config.c @@ -7,30 +7,6 @@ #include "pb-config.h" -#include "storage.h" - -void *config_ctx; -static struct config *config; -static struct config_storage *storage; - - -void config_set_defaults(struct config *config) -{ - config->autoboot_enabled = true; - config->autoboot_timeout_sec = 10; - config->network.interfaces = NULL; - config->network.n_interfaces = 0; - config->network.dns_servers = NULL; - config->network.n_dns_servers = 0; - - config->n_boot_priorities = 2; - config->boot_priorities = talloc_array(config, struct boot_priority, - config->n_boot_priorities); - config->boot_priorities[0].type = DEVICE_TYPE_NETWORK; - config->boot_priorities[1].type = DEVICE_TYPE_DISK; - -} - static struct interface_config *config_copy_interface(struct config *ctx, struct interface_config *src) { @@ -91,117 +67,3 @@ struct config *config_copy(void *ctx, const struct config *src) return dest; } - -void dump_config(struct config *config); -void dump_config(struct config *config) -{ - unsigned int i; - - pb_log("configuration:\n"); - - if (config->autoboot_enabled) - pb_log(" autoboot: enabled, %d sec\n", - config->autoboot_timeout_sec); - else - pb_log(" autoboot: disabled\n"); - - if (config->network.n_interfaces || config->network.n_dns_servers) - pb_log(" network configuration:\n"); - - for (i = 0; i < config->network.n_interfaces; i++) { - struct interface_config *ifconf = - config->network.interfaces[i]; - - pb_log(" interface %02x:%02x:%02x:%02x:%02x:%02x\n", - ifconf->hwaddr[0], ifconf->hwaddr[1], - ifconf->hwaddr[2], ifconf->hwaddr[3], - ifconf->hwaddr[4], ifconf->hwaddr[5]); - - if (ifconf->ignore) { - pb_log(" ignore\n"); - continue; - } - - if (ifconf->method == CONFIG_METHOD_DHCP) { - pb_log(" dhcp\n"); - - } else if (ifconf->method == CONFIG_METHOD_STATIC) { - pb_log(" static:\n"); - pb_log(" ip: %s\n", ifconf->static_config.address); - pb_log(" gw: %s\n", ifconf->static_config.gateway); - - } - } - for (i = 0; i < config->network.n_dns_servers; i++) - pb_log(" dns server %s\n", config->network.dns_servers[i]); -} - -int config_init(void *ctx) -{ - config_ctx = talloc_new(ctx); - - config = talloc(config_ctx, struct config); - config_set_defaults(config); - - storage = create_powerpc_nvram_storage(config); - - storage->load(storage, config); - - dump_config(config); - - return 0; -} - -int config_set(struct config *newconfig) -{ - int rc; - - if (!storage || !storage->save) - return -1; - - if (newconfig == config) - return 0; - - pb_log("new configuration data received\n"); - dump_config(newconfig); - - rc = storage->save(storage, newconfig); - - if (!rc) - config = talloc_steal(config_ctx, newconfig); - else - pb_log("error saving new configuration; changes lost\n"); - - return rc; -} - -/* A non-exported function to allow the test infrastructure to initialise - * (and change) the configuration variables */ -struct parser_test; -struct config __attribute__((unused)) *test_config_init( - struct parser_test *test); -struct config *test_config_init(struct parser_test *test) -{ - config = talloc(test, struct config); - config_set_defaults(config); - return config; -} - -const struct config *config_get(void) -{ - return config; -} - -void config_set_autoboot(bool autoboot_enabled) -{ - config->autoboot_enabled = autoboot_enabled; - - pb_log("set autoboot: %s\n", - config->autoboot_enabled ? "enabled" : "disabled"); -} - -int config_fini(void) -{ - talloc_free(config_ctx); - return 0; -} diff --git a/lib/pb-config/pb-config.h b/lib/pb-config/pb-config.h index e430301..2bcc251 100644 --- a/lib/pb-config/pb-config.h +++ b/lib/pb-config/pb-config.h @@ -1,22 +1,9 @@ -#ifndef CONFIGURATION_H -#define CONFIGURATION_H - -#include -#include +#ifndef PB_CONFIG_H +#define PB_CONFIG_H #include - -int config_init(void *ctx); -const struct config *config_get(void); -int config_set(struct config *config); -void config_set_autoboot(bool autoboot_enabled); -int config_fini(void); - -/* for use by the storage backends */ -void config_set_defaults(struct config *config); - struct config *config_copy(void *ctx, const struct config *src); -#endif /* CONFIGURATION_H */ +#endif /* PB_CONFIG_H */ diff --git a/lib/pb-config/storage-null.c b/lib/pb-config/storage-null.c deleted file mode 100644 index b9fe6ed..0000000 --- a/lib/pb-config/storage-null.c +++ /dev/null @@ -1,19 +0,0 @@ - -#include - -#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 deleted file mode 100644 index e371976..0000000 --- a/lib/pb-config/storage-powerpc-nvram.c +++ /dev/null @@ -1,546 +0,0 @@ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "pb-config.h" -#include "storage.h" - -static const char *partition = "common"; - -struct param { - char *name; - char *value; - bool modified; - struct list_item list; -}; - -struct powerpc_nvram_storage { - struct config_storage storage; - struct list params; -}; - -static const char *known_params[] = { - "auto-boot?", - "petitboot,network", - "petitboot,timeout", - NULL, -}; - -#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 bool param_is_known(const char *param, unsigned int len) -{ - const char *known_param; - unsigned int i; - - for (i = 0; known_params[i]; i++) { - known_param = known_params[i]; - if (len == strlen(known_param) && - !strncmp(param, known_param, len)) - return true; - } - - return false; -} - -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 + 1) { - unsigned int namelen; - struct param *param; - char *newline; - - newline = strchr(pos, '\n'); - if (!newline) - break; - - *newline = '\0'; - - paramlen = strlen(pos); - - name = pos; - value = strchr(pos, '='); - if (!value) - continue; - - namelen = value - name; - if (namelen == 0) - continue; - - if (!param_is_known(name, namelen)) - continue; - - 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, ¶m->list); - } - - return 0; -} - -static int parse_nvram(struct powerpc_nvram_storage *nv) -{ - struct process *process; - const char *argv[5]; - int rc; - - argv[0] = "nvram"; - argv[1] = "--print-config"; - argv[2] = "--partition"; - argv[3] = partition; - argv[4] = NULL; - - process = process_create(nv); - process->path = "nvram"; - process->argv = argv; - process->keep_stdout = true; - - rc = process_run_sync(process); - - if (rc || !process_exit_ok(process)) { - fprintf(stderr, "nvram process returned " - "non-zero exit status\n"); - rc = -1; - } else { - rc = parse_nvram_params(nv, process->stdout_buf, - process->stdout_len); - } - - process_release(process); - return rc; -} - -static int write_nvram(struct powerpc_nvram_storage *nv) -{ - struct process *process; - struct param *param; - const char *argv[6]; - int rc; - - argv[0] = "nvram"; - argv[1] = "--update-config"; - argv[2] = NULL; - argv[3] = "--partition"; - argv[4] = partition; - argv[5] = NULL; - - process = process_create(nv); - process->path = "nvram"; - process->argv = argv; - - list_for_each_entry(&nv->params, param, list) { - char *paramstr; - - if (!param->modified) - continue; - - paramstr = talloc_asprintf(nv, "%s=%s", - param->name, param->value); - argv[2] = paramstr; - - rc = process_run_sync(process); - - talloc_free(paramstr); - - if (rc || !process_exit_ok(process)) { - rc = -1; - pb_log("nvram update process returned " - "non-zero exit status\n"); - break; - } - } - - process_release(process); - return rc; -} - -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 void set_param(struct powerpc_nvram_storage *nv, const char *name, - const char *value) -{ - struct param *param; - - list_for_each_entry(&nv->params, param, list) { - if (strcmp(param->name, name)) - continue; - - if (!strcmp(param->value, value)) - return; - - talloc_free(param->value); - param->value = talloc_strdup(param, value); - param->modified = true; - return; - } - - - param = talloc(nv, struct param); - param->modified = true; - param->name = talloc_strdup(nv, name); - param->value = talloc_strdup(nv, value); - list_add(&nv->params, ¶m->list); -} - -static int parse_hwaddr(struct interface_config *ifconf, 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; - - ifconf->hwaddr[i] = x & 0xff; - } - - return 0; -} - -static int parse_one_interface_config(struct config *config, - char *confstr) -{ - struct interface_config *ifconf; - char *tok, *saveptr; - - ifconf = talloc_zero(config, struct interface_config); - - if (!confstr || !strlen(confstr)) - goto out_err; - - /* first token should be the mac address */ - tok = strtok_r(confstr, ",", &saveptr); - if (!tok) - goto out_err; - - if (parse_hwaddr(ifconf, tok)) - goto out_err; - - /* second token is the method */ - tok = strtok_r(NULL, ",", &saveptr); - if (!tok || !strlen(tok) || !strcmp(tok, "ignore")) { - ifconf->ignore = true; - - } else if (!strcmp(tok, "dhcp")) { - ifconf->method = CONFIG_METHOD_DHCP; - - } else if (!strcmp(tok, "static")) { - ifconf->method = CONFIG_METHOD_STATIC; - - /* ip/mask, [optional] gateway */ - tok = strtok_r(NULL, ",", &saveptr); - if (!tok) - goto out_err; - ifconf->static_config.address = - talloc_strdup(ifconf, tok); - - tok = strtok_r(NULL, ",", &saveptr); - if (tok) { - ifconf->static_config.gateway = - talloc_strdup(ifconf, tok); - } - - } else { - pb_log("Unknown network configuration method %s\n", tok); - goto out_err; - } - - config->network.interfaces = talloc_realloc(config, - config->network.interfaces, - struct interface_config *, - ++config->network.n_interfaces); - - config->network.interfaces[config->network.n_interfaces - 1] = ifconf; - - return 0; -out_err: - talloc_free(ifconf); - return -1; -} - -static int parse_one_dns_config(struct config *config, - char *confstr) -{ - char *tok, *saveptr; - - for (tok = strtok_r(confstr, ",", &saveptr); tok; - tok = strtok_r(NULL, ",", &saveptr)) { - - char *server = talloc_strdup(config, tok); - - config->network.dns_servers = talloc_realloc(config, - config->network.dns_servers, const char *, - ++config->network.n_dns_servers); - - config->network.dns_servers[config->network.n_dns_servers - 1] - = server; - } - - 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, "petitboot,network"); - if (!cval || !strlen(cval)) - return; - - val = talloc_strdup(config, cval); - - for (i = 0; ; i++) { - char *tok, *saveptr; - - tok = strtok_r(i == 0 ? val : NULL, " ", &saveptr); - if (!tok) - break; - - if (!strncasecmp(tok, "dns,", strlen("dns,"))) - parse_one_dns_config(config, tok + strlen("dns,")); - else - parse_one_interface_config(config, tok); - - } - - talloc_free(val); -} - -static void populate_config(struct powerpc_nvram_storage *nv, - struct config *config) -{ - const char *val; - char *end; - unsigned long timeout; - - /* 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"); - - val = get_param(nv, "petitboot,timeout"); - if (val) { - timeout = strtoul(val, &end, 10); - if (end != val) { - if (timeout >= INT_MAX) - timeout = INT_MAX; - config->autoboot_timeout_sec = (int)timeout; - } - } - - populate_network_config(nv, config); -} - -static char *iface_config_str(void *ctx, struct interface_config *config) -{ - char *str; - - /* todo: HWADDR size is hardcoded as 6, but we may need to handle - * different hardware address formats */ - str = talloc_asprintf(ctx, "%02x:%02x:%02x:%02x:%02x:%02x,", - config->hwaddr[0], config->hwaddr[1], - config->hwaddr[2], config->hwaddr[3], - config->hwaddr[4], config->hwaddr[5]); - - if (config->ignore) { - str = talloc_asprintf_append(str, "ignore"); - - } else if (config->method == CONFIG_METHOD_DHCP) { - str = talloc_asprintf_append(str, "dhcp"); - - } else if (config->method == CONFIG_METHOD_STATIC) { - str = talloc_asprintf_append(str, "static,%s%s%s", - config->static_config.address, - config->static_config.gateway ? "," : "", - config->static_config.gateway ?: ""); - } - return str; -} - -static char *dns_config_str(void *ctx, const char **dns_servers, int n) -{ - char *str; - int i; - - str = talloc_strdup(ctx, "dns,"); - for (i = 0; i < n; i++) { - str = talloc_asprintf_append(str, "%s%s", - i == 0 ? "" : ",", - dns_servers[i]); - } - - return str; -} - -static void update_string_config(struct powerpc_nvram_storage *nv, - const char *name, const char *value) -{ - const char *cur; - - cur = get_param(nv, name); - - /* don't set an empty parameter if it doesn't already exist */ - if (!cur && !strlen(value)) - return; - - set_param(nv, name, value); -} - -static void update_network_config(struct powerpc_nvram_storage *nv, - struct config *config) -{ - unsigned int i; - char *val; - - val = talloc_strdup(nv, ""); - - for (i = 0; i < config->network.n_interfaces; i++) { - char *iface_str = iface_config_str(nv, - config->network.interfaces[i]); - val = talloc_asprintf_append(val, "%s%s", - *val == '\0' ? "" : " ", iface_str); - talloc_free(iface_str); - } - - if (config->network.n_dns_servers) { - char *dns_str = dns_config_str(nv, config->network.dns_servers, - config->network.n_dns_servers); - val = talloc_asprintf_append(val, "%s%s", - *val == '\0' ? "" : " ", dns_str); - talloc_free(dns_str); - } - - update_string_config(nv, "petitboot,network", val); - - talloc_free(val); -} - -static int update_config(struct powerpc_nvram_storage *nv, - struct config *config, struct config *defaults) -{ - char *tmp = NULL; - const char *val; - - if (config->autoboot_enabled == defaults->autoboot_enabled) - val = ""; - else - val = config->autoboot_enabled ? "true" : "false"; - update_string_config(nv, "auto-boot?", val); - - if (config->autoboot_timeout_sec == defaults->autoboot_timeout_sec) - val = ""; - else - val = tmp = talloc_asprintf(nv, "%d", - config->autoboot_timeout_sec); - - update_string_config(nv, "petitboot,timeout", val); - if (tmp) - talloc_free(tmp); - - update_network_config(nv, config); - - return write_nvram(nv); -} - -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; -} - -static int save(struct config_storage *st, struct config *config) -{ - struct powerpc_nvram_storage *nv = to_powerpc_nvram_storage(st); - struct config *defaults; - int rc; - - defaults = talloc_zero(nv, struct config); - config_set_defaults(defaults); - - rc = update_config(nv, config, defaults); - - talloc_free(defaults); - return rc; -} - -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; - nv->storage.save = save; - list_init(&nv->params); - - return &nv->storage; -} diff --git a/lib/pb-config/storage-test.c b/lib/pb-config/storage-test.c deleted file mode 100644 index 48cb238..0000000 --- a/lib/pb-config/storage-test.c +++ /dev/null @@ -1,73 +0,0 @@ - -#include -#include -#include -#include - -#include - -#include "pb-config.h" -#include "storage.h" - -struct interface_config net1 = { - .hwaddr = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 }, - .method = CONFIG_METHOD_DHCP, -}; - -struct interface_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 interface_config *interface_configs[] = { &net1, &net2 }; -const char *dns_servers[] = { "192.168.1.1", "192.168.1.2" }; - -struct config test_config = { - .autoboot_enabled = true, - .network = { - .interfaces = interface_configs, - .n_interfaces = ARRAY_SIZE(interface_configs), - .dns_servers = dns_servers, - .n_dns_servers = ARRAY_SIZE(dns_servers), - } -}; - -struct test_storage { - struct config_storage storage; - struct param *params; - int n_params; - struct config *config; -}; - -#define to_test_storage(st) container_of(st, struct test_storage, storage) - -static int load(struct config_storage *st, struct config *config) -{ - struct test_storage *ts = to_test_storage(st); - memcpy(config, ts->config, sizeof(test_config)); - return 0; -} - -static int save(struct config_storage *st, struct config *newconfig) -{ - struct test_storage *ts = to_test_storage(st); - ts->config = newconfig; - return 0; -} - -static struct test_storage st = { - .storage = { - .load = load, - .save = save, - }, -}; - -struct config_storage *create_test_storage(void *ctx __attribute__((unused))) -{ - st.config = &test_config; - return &st.storage; -} diff --git a/lib/pb-config/storage.h b/lib/pb-config/storage.h deleted file mode 100644 index 5b4af56..0000000 --- a/lib/pb-config/storage.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef STORAGE_H -#define STORAGE_H - -#include - -struct config; - -struct config_storage { - int (*load)(struct config_storage *st, struct config *config); - int (*save)(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 */ - diff --git a/test/parser/Makefile.am b/test/parser/Makefile.am index 9393b2a..aeb16d8 100644 --- a/test/parser/Makefile.am +++ b/test/parser/Makefile.am @@ -82,6 +82,7 @@ parser_objs = \ $(top_srcdir)/discover/yaboot-parser.c \ $(top_srcdir)/discover/kboot-parser.c \ $(top_srcdir)/discover/pxe-parser.c \ + $(top_srcdir)/discover/platform.c \ $(top_srcdir)/discover/resource.c \ $(top_srcdir)/discover/paths.c \ $(top_srcdir)/discover/device-handler.c \ diff --git a/test/parser/parser-test.h b/test/parser/parser-test.h index 631f1e5..c0339b8 100644 --- a/test/parser/parser-test.h +++ b/test/parser/parser-test.h @@ -10,7 +10,6 @@ struct parser_test { struct device_handler *handler; struct discover_context *ctx; struct list files; - struct config *config; }; /* interface required for parsers */ diff --git a/test/parser/utils.c b/test/parser/utils.c index 838250b..8a6314b 100644 --- a/test/parser/utils.c +++ b/test/parser/utils.c @@ -16,6 +16,7 @@ #include "parser.h" #include "resource.h" #include "event.h" +#include "platform.h" #include "parser-test.h" @@ -95,14 +96,26 @@ static struct discover_context *test_create_context(struct parser_test *test) return ctx; } -extern struct config *test_config_init(struct parser_test *test); +/* define our own test platform */ +static bool test_platform_probe(struct platform *p __attribute__((unused)), + void *ctx __attribute__((unused))) +{ + return true; +} + +struct platform test_platform = { + .name = "test", + .probe = test_platform_probe, +}; + +register_platform(test_platform); struct parser_test *test_init(void) { struct parser_test *test; test = talloc_zero(NULL, struct parser_test); - test->config = test_config_init(test); + platform_init(NULL); test->handler = device_handler_init(NULL, NULL, 0); test->ctx = test_create_context(test); list_init(&test->files); @@ -114,6 +127,7 @@ void test_fini(struct parser_test *test) { device_handler_destroy(test->handler); talloc_free(test); + platform_fini(); } void __test_read_conf_data(struct parser_test *test,