X-Git-Url: http://git.ozlabs.org/?p=petitboot;a=blobdiff_plain;f=lib%2Fpb-config%2Fstorage-powerpc-nvram.c;h=42de5984f02cc0e53537f864b8f3c067c2f0db03;hp=96d279c4041dc65d7a950e883d3342575de16bb2;hb=fafa0c268844aa3921f9df0ef72a1cb7c860793f;hpb=4a9725bb74e7a05731eff0b9166c4d1e99b7064d diff --git a/lib/pb-config/storage-powerpc-nvram.c b/lib/pb-config/storage-powerpc-nvram.c index 96d279c..42de598 100644 --- a/lib/pb-config/storage-powerpc-nvram.c +++ b/lib/pb-config/storage-powerpc-nvram.c @@ -1,12 +1,14 @@ #include #include +#include #include #include #include #include #include +#include #include "pb-config.h" #include "storage.h" @@ -28,6 +30,7 @@ struct powerpc_nvram_storage { static const char *known_params[] = { "auto-boot?", "petitboot,network", + "petitboot,timeout", NULL, }; @@ -78,9 +81,16 @@ static int parse_nvram_params(struct powerpc_nvram_storage *nv, return -1; } - for (pos = buf + i; pos < buf + len; pos += paramlen) { + 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); @@ -89,7 +99,9 @@ static int parse_nvram_params(struct powerpc_nvram_storage *nv, if (!value) continue; - namelen = name - value; + namelen = value - name; + if (namelen == 0) + continue; if (!param_is_known(name, namelen)) continue; @@ -108,64 +120,80 @@ static int parse_nvram_params(struct powerpc_nvram_storage *nv, 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; - } + struct process *process; + const char *argv[5]; + int rc; - pid = fork(); + argv[0] = "nvram"; + argv[1] = "--print-config"; + argv[2] = "--partition"; + argv[3] = partition; + argv[4] = NULL; - if (pid < 0) { - perror("fork"); - return -1; - } + process = process_create(nv); + process->path = "nvram"; + process->argv = argv; + process->keep_stdout = true; + + rc = process_run_sync(process); - 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); + if (rc || !WIFEXITED(process->exit_status) + || WEXITSTATUS(process->exit_status)) { + fprintf(stderr, "nvram process returned " + "non-zero exit status\n"); + rc = -1; + } else { + rc = parse_nvram_params(nv, process->stdout_buf, + process->stdout_len); } - close(pipefds[1]); + process_release(process); + return rc; +} - len = 0; - buf_len = max_partition_size; - buf = talloc_array(nv, char, buf_len); +static int write_nvram(struct powerpc_nvram_storage *nv) +{ + struct process *process; + struct param *param; + const char *argv[6]; + int rc; - for (;;) { - rc = read(pipefds[0], buf + len, buf_len - len); + argv[0] = "nvram"; + argv[1] = "--update-config"; + argv[2] = NULL; + argv[3] = "--partition"; + argv[4] = partition; + argv[5] = NULL; - if (rc < 0) { - perror("read"); - break; - } + process = process_create(nv); + process->path = "nvram"; + process->argv = argv; - if (rc == 0) - break; + list_for_each_entry(&nv->params, param, list) { + char *paramstr; - len += rc; - } + if (!param->modified) + continue; - waitpid(pid, &status, 0); - if (!WIFEXITED(status) || WEXITSTATUS(status)) { - fprintf(stderr, "nvram process returned " - "non-zero exit status\n"); - return -1; - } + paramstr = talloc_asprintf(nv, "%s=%s", + param->name, param->value); + argv[2] = paramstr; - if (rc < 0) - return rc; + rc = process_run_sync(process); + + talloc_free(paramstr); + + if (rc || !WIFEXITED(process->exit_status) + || WEXITSTATUS(process->exit_status)) { + rc = -1; + pb_log("nvram update process returned " + "non-zero exit status\n"); + break; + } + } - return parse_nvram_params(nv, buf, len); + process_release(process); + return rc; } static const char *get_param(struct powerpc_nvram_storage *nv, @@ -179,7 +207,33 @@ static const char *get_param(struct powerpc_nvram_storage *nv, return NULL; } -static int parse_hwaddr(struct network_config *config, char *str) +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; @@ -198,62 +252,89 @@ static int parse_hwaddr(struct network_config *config, char *str) if (endp != byte + 2) return -1; - config->hwaddr[i] = x & 0xff; + ifconf->hwaddr[i] = x & 0xff; } return 0; } -static int parse_one_network_config(struct network_config *config, +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)) - return -1; + goto out_err; /* first token should be the mac address */ tok = strtok_r(confstr, ",", &saveptr); if (!tok) - return -1; + goto out_err; - if (parse_hwaddr(config, tok)) - return -1; + 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")) { - config->ignore = true; - return 0; - } + ifconf->ignore = true; - if (!strcmp(tok, "dhcp")) { - config->method = CONFIG_METHOD_DHCP; + } else if (!strcmp(tok, "dhcp")) { + ifconf->method = CONFIG_METHOD_DHCP; } else if (!strcmp(tok, "static")) { - config->method = CONFIG_METHOD_STATIC; + ifconf->method = CONFIG_METHOD_STATIC; - /* ip/mask, [optional] gateway, [optional] dns */ + /* ip/mask, [optional] gateway */ tok = strtok_r(NULL, ",", &saveptr); if (!tok) - return -1; - config->static_config.address = - talloc_strdup(config, tok); + goto out_err; + ifconf->static_config.address = + talloc_strdup(ifconf, tok); tok = strtok_r(NULL, ",", &saveptr); if (tok) { - config->static_config.gateway = - talloc_strdup(config, tok); - tok = strtok_r(NULL, ",", &saveptr); + ifconf->static_config.gateway = + talloc_strdup(ifconf, tok); } - if (tok) { - config->static_config.dns = - talloc_strdup(config, tok); - } } else { pb_log("Unknown network configuration method %s\n", tok); - return -1; + 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; @@ -273,29 +354,17 @@ static void populate_network_config(struct powerpc_nvram_storage *nv, 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; - } + if (!strncasecmp(tok, "dns,", strlen("dns,"))) + parse_one_dns_config(config, tok + strlen("dns,")); + else + parse_one_interface_config(config, tok); - 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); @@ -305,15 +374,118 @@ 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_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); + } + + set_param(nv, "petitboot,network", val); + + talloc_free(val); +} + +static int update_config(struct powerpc_nvram_storage *nv, + struct config *config, struct config *defaults) +{ + char *val; + + if (config->autoboot_enabled != defaults->autoboot_enabled) { + val = config->autoboot_enabled ? "true" : "false"; + set_param(nv, "auto-boot?", val); + } + + if (config->autoboot_timeout_sec != defaults->autoboot_timeout_sec) { + val = talloc_asprintf(nv, "%d", config->autoboot_timeout_sec); + set_param(nv, "petitboot,timeout", val); + talloc_free(val); + } + + 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); @@ -328,12 +500,28 @@ static int load(struct config_storage *st, struct config *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;