8 #include <talloc/talloc.h>
11 #include <process/process.h>
13 #include "pb-config.h"
16 static const char *partition = "common";
22 struct list_item list;
25 struct powerpc_nvram_storage {
26 struct config_storage storage;
30 static const char *known_params[] = {
37 #define to_powerpc_nvram_storage(s) \
38 container_of(s, struct powerpc_nvram_storage, storage)
40 /* a partition max a max size of 64k * 16bytes = 1M */
41 static const int max_partition_size = 64 * 1024 * 16;
43 static bool param_is_known(const char *param, unsigned int len)
45 const char *known_param;
48 for (i = 0; known_params[i]; i++) {
49 known_param = known_params[i];
50 if (len == strlen(known_param) &&
51 !strncmp(param, known_param, len))
58 static int parse_nvram_params(struct powerpc_nvram_storage *nv,
61 char *pos, *name, *value;
62 unsigned int paramlen;
65 /* discard 2 header lines:
72 for (i = 0; i < len; i++) {
80 fprintf(stderr, "failure parsing nvram output\n");
84 for (pos = buf + i; pos < buf + len; pos += paramlen + 1) {
89 newline = strchr(pos, '\n');
95 paramlen = strlen(pos);
98 value = strchr(pos, '=');
102 namelen = value - name;
106 if (!param_is_known(name, namelen))
111 param = talloc(nv, struct param);
112 param->modified = false;
113 param->name = talloc_strndup(nv, name, namelen);
114 param->value = talloc_strdup(nv, value);
115 list_add(&nv->params, ¶m->list);
121 static int parse_nvram(struct powerpc_nvram_storage *nv)
123 struct process *process;
128 argv[1] = "--print-config";
129 argv[2] = "--partition";
133 process = process_create(nv);
134 process->path = "nvram";
135 process->argv = argv;
136 process->keep_stdout = true;
138 rc = process_run_sync(process);
140 if (rc || !WIFEXITED(process->exit_status)
141 || WEXITSTATUS(process->exit_status)) {
142 fprintf(stderr, "nvram process returned "
143 "non-zero exit status\n");
146 rc = parse_nvram_params(nv, process->stdout_buf,
147 process->stdout_len);
150 process_release(process);
154 static int write_nvram(struct powerpc_nvram_storage *nv)
156 struct process *process;
162 argv[1] = "--update-config";
164 argv[3] = "--partition";
168 process = process_create(nv);
169 process->path = "nvram";
170 process->argv = argv;
172 list_for_each_entry(&nv->params, param, list) {
175 if (!param->modified)
178 paramstr = talloc_asprintf(nv, "%s=%s",
179 param->name, param->value);
182 rc = process_run_sync(process);
184 talloc_free(paramstr);
186 if (rc || !WIFEXITED(process->exit_status)
187 || WEXITSTATUS(process->exit_status)) {
189 pb_log("nvram update process returned "
190 "non-zero exit status\n");
195 process_release(process);
199 static const char *get_param(struct powerpc_nvram_storage *nv,
204 list_for_each_entry(&nv->params, param, list)
205 if (!strcmp(param->name, name))
210 static void set_param(struct powerpc_nvram_storage *nv, const char *name,
215 list_for_each_entry(&nv->params, param, list) {
216 if (strcmp(param->name, name))
219 if (!strcmp(param->value, value))
222 talloc_free(param->value);
223 param->value = talloc_strdup(param, value);
224 param->modified = true;
229 param = talloc(nv, struct param);
230 param->modified = true;
231 param->name = talloc_strdup(nv, name);
232 param->value = talloc_strdup(nv, value);
233 list_add(&nv->params, ¶m->list);
236 static int parse_hwaddr(struct interface_config *ifconf, char *str)
240 if (strlen(str) != strlen("00:00:00:00:00:00"))
243 for (i = 0; i < HWADDR_SIZE; i++) {
247 byte[0] = str[i * 3 + 0];
248 byte[1] = str[i * 3 + 1];
251 x = strtoul(byte, &endp, 16);
252 if (endp != byte + 2)
255 ifconf->hwaddr[i] = x & 0xff;
261 static int parse_one_interface_config(struct config *config,
264 struct interface_config *ifconf;
267 ifconf = talloc_zero(config, struct interface_config);
269 if (!confstr || !strlen(confstr))
272 /* first token should be the mac address */
273 tok = strtok_r(confstr, ",", &saveptr);
277 if (parse_hwaddr(ifconf, tok))
280 /* second token is the method */
281 tok = strtok_r(NULL, ",", &saveptr);
282 if (!tok || !strlen(tok) || !strcmp(tok, "ignore")) {
283 ifconf->ignore = true;
285 } else if (!strcmp(tok, "dhcp")) {
286 ifconf->method = CONFIG_METHOD_DHCP;
288 } else if (!strcmp(tok, "static")) {
289 ifconf->method = CONFIG_METHOD_STATIC;
291 /* ip/mask, [optional] gateway */
292 tok = strtok_r(NULL, ",", &saveptr);
295 ifconf->static_config.address =
296 talloc_strdup(ifconf, tok);
298 tok = strtok_r(NULL, ",", &saveptr);
300 ifconf->static_config.gateway =
301 talloc_strdup(ifconf, tok);
305 pb_log("Unknown network configuration method %s\n", tok);
309 config->network.interfaces = talloc_realloc(config,
310 config->network.interfaces,
311 struct interface_config *,
312 ++config->network.n_interfaces);
314 config->network.interfaces[config->network.n_interfaces - 1] = ifconf;
322 static int parse_one_dns_config(struct config *config,
327 for (tok = strtok_r(confstr, ",", &saveptr); tok;
328 tok = strtok_r(NULL, ",", &saveptr)) {
330 char *server = talloc_strdup(config, tok);
332 config->network.dns_servers = talloc_realloc(config,
333 config->network.dns_servers, const char *,
334 ++config->network.n_dns_servers);
336 config->network.dns_servers[config->network.n_dns_servers - 1]
343 static void populate_network_config(struct powerpc_nvram_storage *nv,
344 struct config *config)
350 cval = get_param(nv, "petitboot,network");
351 if (!cval || !strlen(cval))
354 val = talloc_strdup(config, cval);
359 tok = strtok_r(i == 0 ? val : NULL, " ", &saveptr);
363 if (!strncasecmp(tok, "dns,", strlen("dns,")))
364 parse_one_dns_config(config, tok + strlen("dns,"));
366 parse_one_interface_config(config, tok);
373 static void populate_config(struct powerpc_nvram_storage *nv,
374 struct config *config)
378 unsigned long timeout;
380 /* if the "auto-boot?' property is present and "false", disable auto
382 val = get_param(nv, "auto-boot?");
383 config->autoboot_enabled = !val || strcmp(val, "false");
385 val = get_param(nv, "petitboot,timeout");
387 timeout = strtoul(val, &end, 10);
389 if (timeout >= INT_MAX)
391 config->autoboot_timeout_sec = (int)timeout;
395 populate_network_config(nv, config);
398 static char *iface_config_str(void *ctx, struct interface_config *config)
402 /* todo: HWADDR size is hardcoded as 6, but we may need to handle
403 * different hardware address formats */
404 str = talloc_asprintf(ctx, "%02x:%02x:%02x:%02x:%02x:%02x,",
405 config->hwaddr[0], config->hwaddr[1],
406 config->hwaddr[2], config->hwaddr[3],
407 config->hwaddr[4], config->hwaddr[5]);
409 if (config->ignore) {
410 str = talloc_asprintf_append(str, "ignore");
412 } else if (config->method == CONFIG_METHOD_DHCP) {
413 str = talloc_asprintf_append(str, "dhcp");
415 } else if (config->method == CONFIG_METHOD_STATIC) {
416 str = talloc_asprintf_append(str, "static,%s%s%s",
417 config->static_config.address,
418 config->static_config.gateway ? "," : "",
419 config->static_config.gateway ?: "");
424 static char *dns_config_str(void *ctx, const char **dns_servers, int n)
429 str = talloc_strdup(ctx, "dns,");
430 for (i = 0; i < n; i++) {
431 str = talloc_asprintf_append(str, "%s%s",
439 static void update_network_config(struct powerpc_nvram_storage *nv,
440 struct config *config)
445 val = talloc_strdup(nv, "");
447 for (i = 0; i < config->network.n_interfaces; i++) {
448 char *iface_str = iface_config_str(nv,
449 config->network.interfaces[i]);
450 val = talloc_asprintf_append(val, "%s%s",
451 *val == '\0' ? "" : " ", iface_str);
452 talloc_free(iface_str);
455 if (config->network.n_dns_servers) {
456 char *dns_str = dns_config_str(nv, config->network.dns_servers,
457 config->network.n_dns_servers);
458 val = talloc_asprintf_append(val, "%s%s",
459 *val == '\0' ? "" : " ", dns_str);
460 talloc_free(dns_str);
463 set_param(nv, "petitboot,network", val);
468 static int update_config(struct powerpc_nvram_storage *nv,
469 struct config *config, struct config *defaults)
473 if (config->autoboot_enabled != defaults->autoboot_enabled) {
474 val = config->autoboot_enabled ? "true" : "false";
475 set_param(nv, "auto-boot?", val);
478 if (config->autoboot_timeout_sec != defaults->autoboot_timeout_sec) {
479 val = talloc_asprintf(nv, "%d", config->autoboot_timeout_sec);
480 set_param(nv, "petitboot,timeout", val);
484 if (config->network.n_interfaces)
485 update_network_config(nv, config);
487 return write_nvram(nv);
490 static int load(struct config_storage *st, struct config *config)
492 struct powerpc_nvram_storage *nv = to_powerpc_nvram_storage(st);
495 rc = parse_nvram(nv);
499 populate_config(nv, config);
504 static int save(struct config_storage *st, struct config *config)
506 struct powerpc_nvram_storage *nv = to_powerpc_nvram_storage(st);
507 struct config *defaults;
510 defaults = talloc_zero(nv, struct config);
511 config_set_defaults(defaults);
513 rc = update_config(nv, config, defaults);
515 talloc_free(defaults);
519 struct config_storage *create_powerpc_nvram_storage(void *ctx)
521 struct powerpc_nvram_storage *nv;
523 nv = talloc(ctx, struct powerpc_nvram_storage);
524 nv->storage.load = load;
525 nv->storage.save = save;
526 list_init(&nv->params);