]> git.ozlabs.org Git - petitboot/blobdiff - lib/pb-config/storage-powerpc-nvram.c
lib/pb-config: Add config_copy
[petitboot] / lib / pb-config / storage-powerpc-nvram.c
index fa2437c586a289408c829fbaea6ce730a735eb3c..e3719761606f1010e244a7b7e89b44b21d725558 100644 (file)
@@ -137,8 +137,7 @@ static int parse_nvram(struct powerpc_nvram_storage *nv)
 
        rc = process_run_sync(process);
 
-       if (rc || !WIFEXITED(process->exit_status)
-                       || WEXITSTATUS(process->exit_status)) {
+       if (rc || !process_exit_ok(process)) {
                fprintf(stderr, "nvram process returned "
                                "non-zero exit status\n");
                rc = -1;
@@ -151,6 +150,50 @@ static int parse_nvram(struct powerpc_nvram_storage *nv)
        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)
 {
@@ -162,6 +205,32 @@ static const char *get_param(struct powerpc_nvram_storage *nv,
        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, &param->list);
+}
+
 static int parse_hwaddr(struct interface_config *ifconf, char *str)
 {
        int i;
@@ -193,7 +262,7 @@ static int parse_one_interface_config(struct config *config,
        struct interface_config *ifconf;
        char *tok, *saveptr;
 
-       ifconf = talloc(config, struct interface_config);
+       ifconf = talloc_zero(config, struct interface_config);
 
        if (!confstr || !strlen(confstr))
                goto out_err;
@@ -324,6 +393,117 @@ static void populate_config(struct powerpc_nvram_storage *nv,
        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);
@@ -338,12 +518,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;