2 #if defined(HAVE_CONFIG_H)
12 #include <sys/types.h>
15 #include <pb-protocol/pb-protocol.h>
16 #include <process/process.h>
17 #include <system/system.h>
18 #include <talloc/talloc.h>
20 #include <util/util.h>
21 #include <i18n/i18n.h>
23 #include "device-handler.h"
29 #include <security/gpg.h>
31 static const char *boot_hook_dir = PKG_SYSCONF_DIR "/boot.d";
33 BOOT_HOOK_EXIT_OK = 0,
34 BOOT_HOOK_EXIT_UPDATE = 2,
38 * kexec_load - kexec load helper.
40 static int kexec_load(struct boot_task *boot_task)
45 char *s_initrd = NULL;
49 boot_task->local_initrd_override = NULL;
50 boot_task->local_dtb_override = NULL;
51 boot_task->local_image_override = NULL;
53 if ((result = gpg_validate_boot_files(boot_task))) {
54 if (result == KEXEC_LOAD_SIGNATURE_FAILURE) {
55 pb_log("%s: Aborting kexec due to"
56 " signature verification failure\n", __func__);
61 const char* local_initrd = (boot_task->local_initrd_override) ?
62 boot_task->local_initrd_override : boot_task->local_initrd;
63 const char* local_dtb = (boot_task->local_dtb_override) ?
64 boot_task->local_dtb_override : boot_task->local_dtb;
65 const char* local_image = (boot_task->local_image_override) ?
66 boot_task->local_image_override : boot_task->local_image;
69 *p++ = pb_system_apps.kexec; /* 1 */
73 s_initrd = talloc_asprintf(boot_task, "--initrd=%s",
76 *p++ = s_initrd; /* 3 */
80 s_dtb = talloc_asprintf(boot_task, "--dtb=%s",
86 s_args = talloc_asprintf(boot_task, "--append=%s",
87 boot_task->args ?: "\"\"");
89 *p++ = s_args; /* 5 */
91 *p++ = local_image; /* 6 */
94 result = process_run_simple_argv(boot_task, argv);
97 pb_log("%s: failed: (%d)\n", __func__, result);
100 gpg_validate_boot_files_cleanup(boot_task);
106 * kexec_reboot - Helper to boot the new kernel.
108 * Must only be called after a successful call to kexec_load().
111 static int kexec_reboot(struct boot_task *task)
115 /* First try running shutdown. Init scripts should run 'exec -e' */
116 result = process_run_simple(task, pb_system_apps.shutdown, "-r",
119 /* On error, force a kexec with the -e option */
121 result = process_run_simple(task, pb_system_apps.kexec,
126 pb_log("%s: failed: (%d)\n", __func__, result);
128 /* okay, kexec -e -f */
130 result = process_run_simple(task, pb_system_apps.kexec,
135 pb_log("%s: failed: (%d)\n", __func__, result);
141 static void __attribute__((format(__printf__, 4, 5))) update_status(
142 boot_status_fn fn, void *arg, int type, char *fmt, ...)
144 struct boot_status status;
148 status.message = talloc_vasprintf(NULL, fmt, ap);
152 status.progress = -1;
153 status.detail = NULL;
155 pb_debug("boot status: [%d] %s\n", type, status.message);
159 talloc_free(status.message);
162 static void boot_hook_update_param(void *ctx, struct boot_task *task,
163 const char *name, const char *value)
168 } *param, params[] = {
169 { "boot_image", &task->local_image },
170 { "boot_initrd", &task->local_initrd },
171 { "boot_dtb", &task->local_dtb },
172 { "boot_args", &task->args },
176 for (param = params; param->name; param++) {
177 if (strcmp(param->name, name))
180 *param->p = talloc_strdup(ctx, value);
185 static void boot_hook_update(struct boot_task *task, const char *hookname,
188 char *line, *name, *val, *sep;
189 char *saveptr = NULL;
191 for (;; buf = NULL) {
193 line = strtok_r(buf, "\n", &saveptr);
197 sep = strchr(line, '=');
205 boot_hook_update_param(task, task, name, val);
207 pb_log("boot hook %s specified %s=%s\n",
208 hookname, name, val);
212 static void boot_hook_setenv(struct boot_task *task)
214 unsetenv("boot_image");
215 unsetenv("boot_initrd");
216 unsetenv("boot_dtb");
217 unsetenv("boot_args");
218 unsetenv("boot_tty");
220 setenv("boot_image", task->local_image, 1);
221 if (task->local_initrd)
222 setenv("boot_initrd", task->local_initrd, 1);
224 setenv("boot_dtb", task->local_dtb, 1);
226 setenv("boot_args", task->args, 1);
228 setenv("boot_tty", task->boot_tty, 1);
231 static int hook_filter(const struct dirent *dirent)
233 return dirent->d_type == DT_REG || dirent->d_type == DT_LNK;
236 static int hook_cmp(const struct dirent **a, const struct dirent **b)
238 return strcmp((*a)->d_name, (*b)->d_name);
241 static void run_boot_hooks(struct boot_task *task)
243 struct dirent **hooks;
246 n = scandir(boot_hook_dir, &hooks, hook_filter, hook_cmp);
250 update_status(task->status_fn, task->status_arg, BOOT_STATUS_INFO,
251 _("running boot hooks"));
253 boot_hook_setenv(task);
255 for (i = 0; i < n; i++) {
256 const char *argv[2] = { NULL, NULL };
257 struct process *process;
261 path = join_paths(task, boot_hook_dir, hooks[i]->d_name);
263 if (access(path, X_OK)) {
268 process = process_create(task);
271 process->path = path;
272 process->argv = argv;
273 process->keep_stdout = true;
275 pb_log("running boot hook %s\n", hooks[i]->d_name);
277 rc = process_run_sync(process);
279 pb_log("boot hook exec failed!\n");
281 } else if (WIFEXITED(process->exit_status) &&
282 WEXITSTATUS(process->exit_status)
283 == BOOT_HOOK_EXIT_UPDATE) {
284 /* if the hook returned with BOOT_HOOK_EXIT_UPDATE,
285 * then we process stdout to look for updated params
287 boot_hook_update(task, hooks[i]->d_name,
288 process->stdout_buf);
289 boot_hook_setenv(task);
292 process_release(process);
299 static bool load_pending(struct load_url_result *result)
301 return result && result->status == LOAD_ASYNC;
304 static int check_load(struct boot_task *task, const char *name,
305 struct load_url_result *result)
309 if (result->status != LOAD_ERROR)
312 update_status(task->status_fn, task->status_arg,
314 _("Couldn't load %s"), name);
318 static void cleanup_load(struct load_url_result *result)
322 if (result->status != LOAD_OK)
324 if (!result->cleanup_local)
326 unlink(result->local);
329 static void cleanup_cancellations(struct boot_task *task,
330 struct load_url_result *cur_result)
332 struct load_url_result *result, **results[] = {
333 &task->image, &task->initrd, &task->dtb,
335 bool pending = false;
338 for (i = 0; i < ARRAY_SIZE(results); i++) {
339 result = *results[i];
344 /* We need to cleanup and free any completed loads */
345 if (result == cur_result || result->status == LOAD_OK
346 || result->status == LOAD_ERROR) {
347 cleanup_load(result);
351 /* ... and cancel any pending loads, which we'll free in
352 * the completion callback */
353 } else if (result->status == LOAD_ASYNC) {
354 load_url_async_cancel(result);
357 /* if we're waiting for a cancellation, we still need to
358 * wait for the completion before freeing the boot task */
359 } else if (result->status == LOAD_CANCELLED) {
368 static void boot_process(struct load_url_result *result, void *data)
370 struct boot_task *task = data;
373 if (task->cancelled) {
374 cleanup_cancellations(task, result);
378 if (load_pending(task->image) ||
379 load_pending(task->initrd) ||
380 load_pending(task->dtb))
383 if (check_load(task, "kernel image", task->image) ||
384 check_load(task, "initrd", task->initrd) ||
385 check_load(task, "dtb", task->dtb))
388 if (task->verify_signature) {
389 if (load_pending(task->image_signature) ||
390 load_pending(task->initrd_signature) ||
391 load_pending(task->dtb_signature) ||
392 load_pending(task->cmdline_signature))
395 if (check_load(task, "kernel image signature",
396 task->image_signature) ||
397 check_load(task, "initrd signature",
398 task->initrd_signature) ||
399 check_load(task, "dtb signature",
400 task->dtb_signature) ||
401 check_load(task, "command line signature",
402 task->cmdline_signature))
406 /* we make a copy of the local paths, as the boot hooks might update
407 * and/or create these */
408 task->local_image = task->image ? task->image->local : NULL;
409 task->local_initrd = task->initrd ? task->initrd->local : NULL;
410 task->local_dtb = task->dtb ? task->dtb->local : NULL;
412 if (task->verify_signature) {
413 task->local_image_signature = task->image_signature ?
414 task->image_signature->local : NULL;
415 task->local_initrd_signature = task->initrd_signature ?
416 task->initrd_signature->local : NULL;
417 task->local_dtb_signature = task->dtb_signature ?
418 task->dtb_signature->local : NULL;
419 task->local_cmdline_signature = task->cmdline_signature ?
420 task->cmdline_signature->local : NULL;
423 run_boot_hooks(task);
425 update_status(task->status_fn, task->status_arg, BOOT_STATUS_INFO,
426 _("performing kexec_load"));
428 rc = kexec_load(task);
429 if (rc == KEXEC_LOAD_SIGNATURE_FAILURE) {
430 update_status(task->status_fn, task->status_arg,
432 _("signature verification failed"));
434 else if (rc == KEXEC_LOAD_SIG_SETUP_INVALID) {
435 update_status(task->status_fn, task->status_arg,
437 _("invalid signature configuration"));
440 update_status(task->status_fn, task->status_arg,
442 _("kexec load failed"));
446 cleanup_load(task->image_signature);
447 cleanup_load(task->initrd_signature);
448 cleanup_load(task->dtb_signature);
449 cleanup_load(task->cmdline_signature);
452 cleanup_load(task->image);
453 cleanup_load(task->initrd);
454 cleanup_load(task->dtb);
457 update_status(task->status_fn, task->status_arg,
459 _("performing kexec reboot"));
461 rc = kexec_reboot(task);
463 update_status(task->status_fn, task->status_arg,
465 _("kexec reboot failed"));
470 static int start_url_load(struct boot_task *task, const char *name,
471 struct pb_url *url, struct load_url_result **result)
476 *result = load_url_async(task, url, boot_process, task);
478 update_status(task->status_fn, task->status_arg,
480 _("Error loading %s"), name);
486 struct boot_task *boot(void *ctx, struct discover_boot_option *opt,
487 struct boot_command *cmd, int dry_run,
488 boot_status_fn status_fn, void *status_arg)
490 struct pb_url *image = NULL, *initrd = NULL, *dtb = NULL;
491 struct pb_url *image_sig = NULL, *initrd_sig = NULL, *dtb_sig = NULL,
493 const struct config *config;
494 struct boot_task *boot_task;
495 const char *boot_desc;
498 if (opt && opt->option->name)
499 boot_desc = opt->option->name;
500 else if (cmd && cmd->boot_image_file)
501 boot_desc = cmd->boot_image_file;
503 boot_desc = _("(unknown)");
505 update_status(status_fn, status_arg, BOOT_STATUS_INFO,
506 _("Booting %s."), boot_desc);
508 if (cmd && cmd->boot_image_file) {
509 image = pb_url_parse(opt, cmd->boot_image_file);
510 } else if (opt && opt->boot_image) {
511 image = opt->boot_image->url;
513 pb_log("%s: no image specified\n", __func__);
514 update_status(status_fn, status_arg, BOOT_STATUS_INFO,
515 _("Boot failed: no image specified"));
519 if (cmd && cmd->initrd_file) {
520 initrd = pb_url_parse(opt, cmd->initrd_file);
521 } else if (opt && opt->initrd) {
522 initrd = opt->initrd->url;
525 if (cmd && cmd->dtb_file) {
526 dtb = pb_url_parse(opt, cmd->dtb_file);
527 } else if (opt && opt->dtb) {
531 boot_task = talloc_zero(ctx, struct boot_task);
532 boot_task->dry_run = dry_run;
533 boot_task->status_fn = status_fn;
534 boot_task->status_arg = status_arg;
536 boot_task->verify_signature = (lockdown_status() == PB_LOCKDOWN_SIGN);
538 if (cmd && cmd->boot_args) {
539 boot_task->args = talloc_strdup(boot_task, cmd->boot_args);
540 } else if (opt && opt->option->boot_args) {
541 boot_task->args = talloc_strdup(boot_task,
542 opt->option->boot_args);
544 boot_task->args = NULL;
548 boot_task->boot_tty = talloc_strdup(boot_task, cmd->tty);
550 config = config_get();
551 boot_task->boot_tty = config ? config->boot_tty : NULL;
554 if (boot_task->verify_signature) {
555 if (cmd && cmd->args_sig_file) {
556 cmdline_sig = pb_url_parse(opt, cmd->args_sig_file);
557 } else if (opt && opt->args_sig_file) {
558 cmdline_sig = opt->args_sig_file->url;
560 pb_log("%s: no command line signature file"
561 " specified\n", __func__);
562 update_status(status_fn, status_arg, BOOT_STATUS_INFO,
563 _("Boot failed: no command line"
564 " signature file specified"));
565 talloc_free(boot_task);
570 /* start async loads for boot resources */
571 rc = start_url_load(boot_task, "kernel image", image, &boot_task->image)
572 || start_url_load(boot_task, "initrd", initrd, &boot_task->initrd)
573 || start_url_load(boot_task, "dtb", dtb, &boot_task->dtb);
575 if (boot_task->verify_signature) {
576 /* Generate names of associated signature files and load */
578 image_sig = gpg_get_signature_url(ctx, image);
579 rc |= start_url_load(boot_task,
580 "kernel image signature", image_sig,
581 &boot_task->image_signature);
584 initrd_sig = gpg_get_signature_url(ctx, initrd);
585 rc |= start_url_load(boot_task, "initrd signature",
586 initrd_sig, &boot_task->initrd_signature);
589 dtb_sig = gpg_get_signature_url(ctx, dtb);
590 rc |= start_url_load(boot_task, "dtb signature",
591 dtb_sig, &boot_task->dtb_signature);
594 rc |= start_url_load(boot_task,
595 "kernel command line signature", cmdline_sig,
596 &boot_task->cmdline_signature);
599 /* If all URLs are local, we may be done. */
601 /* Don't call boot_cancel() to preserve the status update */
602 boot_task->cancelled = true;
603 cleanup_cancellations(boot_task, NULL);
607 boot_process(NULL, boot_task);
612 void boot_cancel(struct boot_task *task)
614 task->cancelled = true;
616 update_status(task->status_fn, task->status_arg, BOOT_STATUS_INFO,
617 _("Boot cancelled"));
619 cleanup_cancellations(task, NULL);