9 #include <talloc/talloc.h>
10 #include <list/list.h>
12 #include <process/process.h>
16 static const char *partition = "common";
22 struct list_item list;
25 struct platform_powerpc {
29 static const char *known_params[] = {
36 #define to_platform_powerpc(p) \
37 (struct platform_powerpc *)(p->platform_data)
39 /* a partition max a max size of 64k * 16bytes = 1M */
40 static const int max_partition_size = 64 * 1024 * 16;
42 static bool param_is_known(const char *param, unsigned int len)
44 const char *known_param;
47 for (i = 0; known_params[i]; i++) {
48 known_param = known_params[i];
49 if (len == strlen(known_param) &&
50 !strncmp(param, known_param, len))
57 static int parse_nvram_params(struct platform_powerpc *platform,
60 char *pos, *name, *value;
61 unsigned int paramlen;
64 /* discard 2 header lines:
71 for (i = 0; i < len; i++) {
79 fprintf(stderr, "failure parsing nvram output\n");
83 for (pos = buf + i; pos < buf + len; pos += paramlen + 1) {
88 newline = strchr(pos, '\n');
94 paramlen = strlen(pos);
97 value = strchr(pos, '=');
101 namelen = value - name;
105 if (!param_is_known(name, namelen))
110 param = talloc(platform, struct param);
111 param->modified = false;
112 param->name = talloc_strndup(platform, name, namelen);
113 param->value = talloc_strdup(platform, value);
114 list_add(&platform->params, ¶m->list);
120 static int parse_nvram(struct platform_powerpc *platform)
122 struct process *process;
127 argv[1] = "--print-config";
128 argv[2] = "--partition";
132 process = process_create(platform);
133 process->path = "nvram";
134 process->argv = argv;
135 process->keep_stdout = true;
137 rc = process_run_sync(process);
139 if (rc || !process_exit_ok(process)) {
140 fprintf(stderr, "nvram process returned "
141 "non-zero exit status\n");
144 rc = parse_nvram_params(platform, process->stdout_buf,
145 process->stdout_len);
148 process_release(process);
152 static int write_nvram(struct platform_powerpc *platform)
154 struct process *process;
160 argv[1] = "--update-config";
162 argv[3] = "--partition";
166 process = process_create(platform);
167 process->path = "nvram";
168 process->argv = argv;
170 list_for_each_entry(&platform->params, param, list) {
173 if (!param->modified)
176 paramstr = talloc_asprintf(platform, "%s=%s",
177 param->name, param->value);
180 rc = process_run_sync(process);
182 talloc_free(paramstr);
184 if (rc || !process_exit_ok(process)) {
186 pb_log("nvram update process returned "
187 "non-zero exit status\n");
192 process_release(process);
196 static const char *get_param(struct platform_powerpc *platform,
201 list_for_each_entry(&platform->params, param, list)
202 if (!strcmp(param->name, name))
207 static void set_param(struct platform_powerpc *platform, const char *name,
212 list_for_each_entry(&platform->params, param, list) {
213 if (strcmp(param->name, name))
216 if (!strcmp(param->value, value))
219 talloc_free(param->value);
220 param->value = talloc_strdup(param, value);
221 param->modified = true;
226 param = talloc(platform, struct param);
227 param->modified = true;
228 param->name = talloc_strdup(platform, name);
229 param->value = talloc_strdup(platform, value);
230 list_add(&platform->params, ¶m->list);
233 static int parse_hwaddr(struct interface_config *ifconf, char *str)
237 if (strlen(str) != strlen("00:00:00:00:00:00"))
240 for (i = 0; i < HWADDR_SIZE; i++) {
244 byte[0] = str[i * 3 + 0];
245 byte[1] = str[i * 3 + 1];
248 x = strtoul(byte, &endp, 16);
249 if (endp != byte + 2)
252 ifconf->hwaddr[i] = x & 0xff;
258 static int parse_one_interface_config(struct config *config,
261 struct interface_config *ifconf;
264 ifconf = talloc_zero(config, struct interface_config);
266 if (!confstr || !strlen(confstr))
269 /* first token should be the mac address */
270 tok = strtok_r(confstr, ",", &saveptr);
274 if (parse_hwaddr(ifconf, tok))
277 /* second token is the method */
278 tok = strtok_r(NULL, ",", &saveptr);
279 if (!tok || !strlen(tok) || !strcmp(tok, "ignore")) {
280 ifconf->ignore = true;
282 } else if (!strcmp(tok, "dhcp")) {
283 ifconf->method = CONFIG_METHOD_DHCP;
285 } else if (!strcmp(tok, "static")) {
286 ifconf->method = CONFIG_METHOD_STATIC;
288 /* ip/mask, [optional] gateway */
289 tok = strtok_r(NULL, ",", &saveptr);
292 ifconf->static_config.address =
293 talloc_strdup(ifconf, tok);
295 tok = strtok_r(NULL, ",", &saveptr);
297 ifconf->static_config.gateway =
298 talloc_strdup(ifconf, tok);
302 pb_log("Unknown network configuration method %s\n", tok);
306 config->network.interfaces = talloc_realloc(config,
307 config->network.interfaces,
308 struct interface_config *,
309 ++config->network.n_interfaces);
311 config->network.interfaces[config->network.n_interfaces - 1] = ifconf;
319 static int parse_one_dns_config(struct config *config,
324 for (tok = strtok_r(confstr, ",", &saveptr); tok;
325 tok = strtok_r(NULL, ",", &saveptr)) {
327 char *server = talloc_strdup(config, tok);
329 config->network.dns_servers = talloc_realloc(config,
330 config->network.dns_servers, const char *,
331 ++config->network.n_dns_servers);
333 config->network.dns_servers[config->network.n_dns_servers - 1]
340 static void populate_network_config(struct platform_powerpc *platform,
341 struct config *config)
347 cval = get_param(platform, "petitboot,network");
348 if (!cval || !strlen(cval))
351 val = talloc_strdup(config, cval);
356 tok = strtok_r(i == 0 ? val : NULL, " ", &saveptr);
360 if (!strncasecmp(tok, "dns,", strlen("dns,")))
361 parse_one_dns_config(config, tok + strlen("dns,"));
363 parse_one_interface_config(config, tok);
370 static void populate_config(struct platform_powerpc *platform,
371 struct config *config)
375 unsigned long timeout;
377 /* if the "auto-boot?' property is present and "false", disable auto
379 val = get_param(platform, "auto-boot?");
380 config->autoboot_enabled = !val || strcmp(val, "false");
382 val = get_param(platform, "petitboot,timeout");
384 timeout = strtoul(val, &end, 10);
386 if (timeout >= INT_MAX)
388 config->autoboot_timeout_sec = (int)timeout;
392 populate_network_config(platform, config);
395 static char *iface_config_str(void *ctx, struct interface_config *config)
399 /* todo: HWADDR size is hardcoded as 6, but we may need to handle
400 * different hardware address formats */
401 str = talloc_asprintf(ctx, "%02x:%02x:%02x:%02x:%02x:%02x,",
402 config->hwaddr[0], config->hwaddr[1],
403 config->hwaddr[2], config->hwaddr[3],
404 config->hwaddr[4], config->hwaddr[5]);
406 if (config->ignore) {
407 str = talloc_asprintf_append(str, "ignore");
409 } else if (config->method == CONFIG_METHOD_DHCP) {
410 str = talloc_asprintf_append(str, "dhcp");
412 } else if (config->method == CONFIG_METHOD_STATIC) {
413 str = talloc_asprintf_append(str, "static,%s%s%s",
414 config->static_config.address,
415 config->static_config.gateway ? "," : "",
416 config->static_config.gateway ?: "");
421 static char *dns_config_str(void *ctx, const char **dns_servers, int n)
426 str = talloc_strdup(ctx, "dns,");
427 for (i = 0; i < n; i++) {
428 str = talloc_asprintf_append(str, "%s%s",
436 static void update_string_config(struct platform_powerpc *platform,
437 const char *name, const char *value)
441 cur = get_param(platform, name);
443 /* don't set an empty parameter if it doesn't already exist */
444 if (!cur && !strlen(value))
447 set_param(platform, name, value);
450 static void update_network_config(struct platform_powerpc *platform,
451 struct config *config)
456 val = talloc_strdup(platform, "");
458 for (i = 0; i < config->network.n_interfaces; i++) {
459 char *iface_str = iface_config_str(platform,
460 config->network.interfaces[i]);
461 val = talloc_asprintf_append(val, "%s%s",
462 *val == '\0' ? "" : " ", iface_str);
463 talloc_free(iface_str);
466 if (config->network.n_dns_servers) {
467 char *dns_str = dns_config_str(platform,
468 config->network.dns_servers,
469 config->network.n_dns_servers);
470 val = talloc_asprintf_append(val, "%s%s",
471 *val == '\0' ? "" : " ", dns_str);
472 talloc_free(dns_str);
475 update_string_config(platform, "petitboot,network", val);
480 static int update_config(struct platform_powerpc *platform,
481 struct config *config, struct config *defaults)
486 if (config->autoboot_enabled == defaults->autoboot_enabled)
489 val = config->autoboot_enabled ? "true" : "false";
490 update_string_config(platform, "auto-boot?", val);
492 if (config->autoboot_timeout_sec == defaults->autoboot_timeout_sec)
495 val = tmp = talloc_asprintf(platform, "%d",
496 config->autoboot_timeout_sec);
498 update_string_config(platform, "petitboot,timeout", val);
502 update_network_config(platform, config);
504 return write_nvram(platform);
507 static int load_config(struct platform *p, struct config *config)
509 struct platform_powerpc *platform = to_platform_powerpc(p);
512 rc = parse_nvram(platform);
516 populate_config(platform, config);
521 static int save_config(struct platform *p, struct config *config)
523 struct platform_powerpc *platform = to_platform_powerpc(p);
524 struct config *defaults;
527 defaults = talloc_zero(platform, struct config);
528 config_set_defaults(defaults);
530 rc = update_config(platform, config, defaults);
532 talloc_free(defaults);
536 static bool probe(struct platform *p, void *ctx)
538 struct platform_powerpc *platform;
542 /* we need a device tree and a working nvram binary */
543 rc = stat("/proc/device-tree", &statbuf);
547 if (!S_ISDIR(statbuf.st_mode))
550 rc = process_run_simple(ctx, "nvram", "--print-config", NULL);
551 if (!WIFEXITED(rc) || WEXITSTATUS(rc) != 0)
554 platform = talloc(ctx, struct platform_powerpc);
555 list_init(&platform->params);
557 p->platform_data = platform;
561 static struct platform platform_powerpc = {
563 .dhcp_arch_id = 0x000e,
565 .load_config = load_config,
566 .save_config = save_config,
569 register_platform(platform_powerpc);