11 #include <file/file.h>
12 #include <types/types.h>
13 #include <talloc/talloc.h>
19 static struct platform *platform;
20 static struct config *config;
22 static const char *kernel_cmdline_debug = "petitboot.debug";
24 static void dump_config(struct config *config)
28 pb_log("configuration:\n");
30 if (config->autoboot_enabled)
31 pb_log(" autoboot: enabled, %d sec\n",
32 config->autoboot_timeout_sec);
34 pb_log(" autoboot: disabled\n");
36 if (config->network.n_interfaces || config->network.n_dns_servers)
37 pb_log(" network configuration:\n");
39 if (config->safe_mode)
40 pb_log(" safe mode: active\n");
42 if (config->disable_snapshots)
43 pb_log(" dm-snapshots disabled\n");
45 for (i = 0; i < config->network.n_interfaces; i++) {
46 struct interface_config *ifconf =
47 config->network.interfaces[i];
49 pb_log(" interface %02x:%02x:%02x:%02x:%02x:%02x\n",
50 ifconf->hwaddr[0], ifconf->hwaddr[1],
51 ifconf->hwaddr[2], ifconf->hwaddr[3],
52 ifconf->hwaddr[4], ifconf->hwaddr[5]);
59 if (ifconf->method == CONFIG_METHOD_DHCP) {
62 } else if (ifconf->method == CONFIG_METHOD_STATIC) {
64 pb_log(" ip: %s\n", ifconf->static_config.address);
65 pb_log(" gw: %s\n", ifconf->static_config.gateway);
66 pb_log(" url: %s\n", ifconf->static_config.url);
70 for (i = 0; i < config->network.n_dns_servers; i++)
71 pb_log(" dns server %s\n", config->network.dns_servers[i]);
73 for (i = 0; i < config->n_autoboot_opts; i++) {
74 if (config->autoboot_opts[i].boot_type == BOOT_DEVICE_TYPE)
75 pb_log(" boot device %d: %s\n", i,
76 device_type_name(config->autoboot_opts[i].type));
78 pb_log(" boot device %d: uuid: %s\n",
79 i, config->autoboot_opts[i].uuid);
82 pb_log(" IPMI boot device 0x%02x%s\n", config->ipmi_bootdev,
83 config->ipmi_bootdev_persistent ? " (persistent)" : "");
85 pb_log(" Modifications allowed to disks: %s\n",
86 config->allow_writes ? "yes" : "no");
88 pb_log(" Default UI to boot on: %s\n",
89 config->boot_console ?: "none set");
90 if (config->manual_console)
91 pb_log(" (Manually set)\n");
93 if (config->http_proxy)
94 pb_log(" HTTP Proxy: %s\n", config->http_proxy);
95 if (config->https_proxy)
96 pb_log(" HTTPS Proxy: %s\n", config->https_proxy);
99 pb_log(" language: %s\n", config->lang ?: "");
102 static bool config_debug_on_cmdline(void)
107 fd = open("/proc/cmdline", O_RDONLY);
111 rc = read(fd, buf, sizeof(buf));
117 return memmem(buf, rc, kernel_cmdline_debug,
118 strlen(kernel_cmdline_debug)) != NULL;
121 void config_set_defaults(struct config *config)
125 config->autoboot_enabled = true;
126 config->autoboot_timeout_sec = 10;
127 config->autoboot_enabled = true;
128 config->network.interfaces = NULL;
129 config->network.n_interfaces = 0;
130 config->network.dns_servers = NULL;
131 config->network.n_dns_servers = 0;
132 config->http_proxy = NULL;
133 config->https_proxy = NULL;
134 config->safe_mode = false;
135 config->allow_writes = true;
136 config->disable_snapshots = false;
138 config->n_consoles = 0;
139 config->consoles = NULL;
140 config->boot_console = NULL;
142 config->n_autoboot_opts = 2;
143 config->autoboot_opts = talloc_array(config, struct autoboot_option,
144 config->n_autoboot_opts);
145 config->autoboot_opts[0].boot_type = BOOT_DEVICE_TYPE;
146 config->autoboot_opts[0].type = DEVICE_TYPE_NETWORK;
147 config->autoboot_opts[1].boot_type = BOOT_DEVICE_TYPE;
148 config->autoboot_opts[1].type = DEVICE_TYPE_ANY;
150 config->ipmi_bootdev = 0;
151 config->ipmi_bootdev_persistent = false;
153 config->debug = config_debug_on_cmdline();
155 lang = setlocale(LC_ALL, NULL);
156 pb_log("lang: %s\n", lang);
157 if (lang && strlen(lang))
158 config->lang = talloc_strdup(config, lang);
164 int platform_init(void *ctx)
166 extern struct platform *__start_platforms, *__stop_platforms;
169 platform_ctx = talloc_new(ctx);
171 for (p = &__start_platforms; p < &__stop_platforms; p++) {
172 pb_debug("%s: Try platform %s\n", __func__, (*p)->name);
173 if (!(*p)->probe(*p, platform_ctx))
179 config = talloc(platform_ctx, struct config);
180 config_set_defaults(config);
183 pb_log("Detected platform type: %s\n", platform->name);
184 if (platform->load_config)
185 platform->load_config(platform, config);
187 pb_log("No platform type detected, some platform-specific "
188 "functionality will be disabled\n");
196 const struct platform *platform_get(void)
201 void platform_pre_boot(void)
203 const struct config *config = config_get();
205 if (platform && config && platform->pre_boot)
206 platform->pre_boot(platform, config);
209 int platform_get_sysinfo(struct system_info *info)
211 if (platform && platform->get_sysinfo)
212 return platform->get_sysinfo(platform, info);
216 int config_set(struct config *newconfig)
220 if (!platform || !platform->save_config)
223 if (newconfig == config)
226 pb_log("new configuration data received\n");
227 dump_config(newconfig);
229 rc = platform->save_config(platform, newconfig);
232 config = talloc_steal(platform_ctx, newconfig);
234 pb_log("error saving new configuration; changes lost\n");
239 /* A non-exported function to allow the test infrastructure to initialise
240 * (and change) the configuration variables */
242 struct config __attribute__((unused)) *test_config_init(
243 struct parser_test *test);
244 struct config *test_config_init(struct parser_test *test)
246 config = talloc(test, struct config);
247 config_set_defaults(config);
251 const struct config *config_get(void)
256 void config_set_autoboot(bool autoboot_enabled)
258 config->autoboot_enabled = autoboot_enabled;
260 pb_log("set autoboot: %s\n",
261 config->autoboot_enabled ? "enabled" : "disabled");
264 int platform_fini(void)
266 talloc_free(platform_ctx);
270 static int parse_hwaddr(struct interface_config *ifconf, const char *str)
274 if (strlen(str) != strlen("00:00:00:00:00:00"))
277 for (i = 0; i < HWADDR_SIZE; i++) {
281 byte[0] = str[i * 3 + 0];
282 byte[1] = str[i * 3 + 1];
285 x = strtoul(byte, &endp, 16);
286 if (endp != byte + 2)
289 ifconf->hwaddr[i] = x & 0xff;
295 static int config_parse_one_interface(struct config *config, char *confstr)
297 struct interface_config *ifconf;
298 char *tok, *tok_gw, *tok_url, *saveptr;
300 ifconf = talloc_zero(config, struct interface_config);
302 if (!confstr || !strlen(confstr))
305 /* first token should be the mac address */
306 tok = strtok_r(confstr, ",", &saveptr);
310 if (parse_hwaddr(ifconf, tok))
313 /* second token is the method */
314 tok = strtok_r(NULL, ",", &saveptr);
315 if (!tok || !strlen(tok) || !strcmp(tok, "ignore")) {
316 ifconf->ignore = true;
318 } else if (!strcmp(tok, "dhcp")) {
319 ifconf->method = CONFIG_METHOD_DHCP;
321 } else if (!strcmp(tok, "static")) {
322 ifconf->method = CONFIG_METHOD_STATIC;
324 /* ip/mask, [optional] gateway, [optional] url */
325 tok = strtok_r(NULL, ",", &saveptr);
328 ifconf->static_config.address =
329 talloc_strdup(ifconf, tok);
332 * If a url is set but not a gateway, we can accidentally
333 * interpret the url as the gateway. To avoid changing the
334 * parameter format check if the "gateway" is actually a
335 * pb-url if it's the last token.
337 tok_gw = strtok_r(NULL, ",", &saveptr);
338 tok_url = strtok_r(NULL, ",", &saveptr);
341 if (tok_url || !is_url(tok_gw))
342 ifconf->static_config.gateway =
343 talloc_strdup(ifconf, tok_gw);
349 ifconf->static_config.url =
350 talloc_strdup(ifconf, tok_url);
352 pb_log("Unknown network configuration method %s\n", tok);
356 config->network.interfaces = talloc_realloc(config,
357 config->network.interfaces,
358 struct interface_config *,
359 ++config->network.n_interfaces);
361 config->network.interfaces[config->network.n_interfaces - 1] = ifconf;
369 static int config_parse_one_dns(struct config *config, char *confstr)
371 char *tok, *saveptr = NULL;
373 for (tok = strtok_r(confstr, ",", &saveptr); tok;
374 tok = strtok_r(NULL, ",", &saveptr)) {
376 char *server = talloc_strdup(config, tok);
378 config->network.dns_servers = talloc_realloc(config,
379 config->network.dns_servers, const char *,
380 ++config->network.n_dns_servers);
382 config->network.dns_servers[config->network.n_dns_servers - 1]
389 static void config_populate_network(struct config *config, const char *cval)
391 char *val, *saveptr = NULL;
394 if (!cval || !strlen(cval))
397 val = talloc_strdup(config, cval);
402 tok = strtok_r(i == 0 ? val : NULL, " ", &saveptr);
406 if (!strncasecmp(tok, "dns,", strlen("dns,")))
407 config_parse_one_dns(config, tok + strlen("dns,"));
409 config_parse_one_interface(config, tok);
416 static int read_bootdev(void *ctx, char **pos, struct autoboot_option *opt)
418 char *delim = strchr(*pos, ' ');
419 int len, prefix = 0, rc = -1;
420 enum device_type type;
422 if (!strncmp(*pos, "uuid:", strlen("uuid:"))) {
423 prefix = strlen("uuid:");
424 opt->boot_type = BOOT_DEVICE_UUID;
425 } else if (!strncmp(*pos, "mac:", strlen("mac:"))) {
426 prefix = strlen("mac:");
427 opt->boot_type = BOOT_DEVICE_UUID;
429 type = find_device_type(*pos);
430 if (type != DEVICE_TYPE_UNKNOWN) {
432 opt->boot_type = BOOT_DEVICE_TYPE;
437 if (opt->boot_type == BOOT_DEVICE_UUID) {
439 len = (int)(delim - *pos) - prefix;
441 len = strlen(*pos) - prefix;
444 opt->uuid = talloc_strndup(ctx, *pos + prefix, len);
449 /* Always advance pointer to next option or end */
453 *pos += strlen(*pos);
458 static void config_populate_bootdev(struct config *config,
459 const struct param_list *pl)
461 struct autoboot_option *opt, *new = NULL;
463 unsigned int n_new = 0;
466 /* Check for ordered bootdevs */
467 val = param_list_get_value(pl, "petitboot,bootdevs");
468 if (!val || !strlen(val)) {
471 pos = talloc_strdup(config, val);
472 end = strchr(pos, '\0');
475 while (pos && pos < end) {
476 opt = talloc(config, struct autoboot_option);
478 if (read_bootdev(config, &pos, opt)) {
479 pb_log("bootdev config is in an unknown format "
480 "(expected uuid:... or mac:...)\n");
485 new = talloc_realloc(config, new, struct autoboot_option,
494 /* If autoboot has been disabled, clear the default options */
495 if (!config->autoboot_enabled) {
496 talloc_free(config->autoboot_opts);
497 config->n_autoboot_opts = 0;
502 talloc_free(config->autoboot_opts);
503 config->autoboot_opts = new;
504 config->n_autoboot_opts = n_new;
507 void config_populate_all(struct config *config, const struct param_list *pl)
511 unsigned long timeout;
513 /* if the "auto-boot?' property is present and "false", disable auto
515 val = param_list_get_value(pl, "auto-boot?");
516 config->autoboot_enabled = !val || strcmp(val, "false");
518 val = param_list_get_value(pl, "petitboot,timeout");
520 timeout = strtoul(val, &end, 10);
522 if (timeout >= INT_MAX)
524 config->autoboot_timeout_sec = (int)timeout;
528 val = param_list_get_value(pl, "petitboot,language");
529 config->lang = val ? talloc_strdup(config, val) : NULL;
531 val = param_list_get_value(pl, "petitboot,network");
532 config_populate_network(config, val);
534 config_populate_bootdev(config, pl);
536 if (!config->debug) {
537 val = param_list_get_value(pl, "petitboot,debug?");
538 config->debug = val && !strcmp(val, "true");
541 val = param_list_get_value(pl, "petitboot,write?");
543 config->allow_writes = !strcmp(val, "true");
545 val = param_list_get_value(pl, "petitboot,snapshots?");
547 config->disable_snapshots = !strcmp(val, "false");
549 val = param_list_get_value(pl, "petitboot,console");
551 config->boot_console = talloc_strdup(config, val);
552 /* If a full path is already set we don't want to override it */
553 config->manual_console = config->boot_console &&
554 !strchr(config->boot_console, '[');
556 val = param_list_get_value(pl, "petitboot,http_proxy");
558 config->http_proxy = talloc_strdup(config, val);
559 val = param_list_get_value(pl, "petitboot,https_proxy");
561 config->https_proxy = talloc_strdup(config, val);