10 #include <sys/types.h>
13 #include <pb-protocol/pb-protocol.h>
14 #include <system/system.h>
15 #include <talloc/talloc.h>
18 #include "device-handler.h"
23 static const char *boot_hook_dir = PKG_SYSCONF_DIR "/boot.d";
35 * kexec_load - kexec load helper.
37 static int kexec_load(struct boot_task *boot_task)
42 char *s_initrd = NULL;
47 *p++ = pb_system_apps.kexec; /* 1 */
50 if (boot_task->local_initrd) {
51 s_initrd = talloc_asprintf(NULL, "--initrd=%s",
52 boot_task->local_initrd);
54 *p++ = s_initrd; /* 3 */
57 if (boot_task->local_dtb) {
58 s_dtb = talloc_asprintf(NULL, "--dtb=%s", boot_task->local_dtb);
63 if (boot_task->args) {
64 s_args = talloc_asprintf(NULL, "--append=%s", boot_task->args);
66 *p++ = s_args; /* 5 */
69 *p++ = boot_task->local_image; /* 6 */
72 result = pb_run_cmd(argv, 1, boot_task->dry_run);
75 pb_log("%s: failed: (%d)\n", __func__, result);
77 talloc_free(s_initrd);
85 * kexec_reboot - Helper to boot the new kernel.
87 * Must only be called after a successful call to kexec_load().
90 static int kexec_reboot(bool dry_run)
96 /* First try running shutdown. Init scripts should run 'exec -e' */
99 *p++ = pb_system_apps.shutdown; /* 1 */
101 *p++ = "now"; /* 3 */
104 result = pb_run_cmd(argv, 1, dry_run);
106 /* On error, force a kexec with the -e option */
110 *p++ = pb_system_apps.kexec; /* 1 */
114 result = pb_run_cmd(argv, 1, 0);
118 pb_log("%s: failed: (%d)\n", __func__, result);
120 /* okay, kexec -e -f */
123 *p++ = pb_system_apps.kexec; /* 1 */
128 result = pb_run_cmd(argv, 1, 0);
132 pb_log("%s: failed: (%d)\n", __func__, result);
138 static void update_status(boot_status_fn fn, void *arg, int type,
141 struct boot_status status;
144 status.message = message;
145 status.progress = -1;
146 status.detail = NULL;
151 static int hook_filter(const struct dirent *dirent)
153 return dirent->d_type == DT_REG || dirent->d_type == DT_LNK;
156 static int hook_cmp(const struct dirent **a, const struct dirent **b)
158 return strcmp((*a)->d_name, (*b)->d_name);
161 static void run_boot_hooks(void *ctx, struct boot_task *task,
162 boot_status_fn status_fn, void *status_arg)
164 struct dirent **hooks;
167 n = scandir(boot_hook_dir, &hooks, hook_filter, hook_cmp);
171 update_status(status_fn, status_arg, BOOT_STATUS_INFO,
172 "running boot hooks");
174 /* pass boot data to hooks */
175 setenv("boot_image", task->local_image, 1);
176 if (task->local_initrd)
177 setenv("boot_initrd", task->local_initrd, 1);
179 setenv("boot_dtb", task->local_dtb, 1);
181 setenv("boot_args", task->args, 1);
183 for (i = 0; i < n; i++) {
185 const char *argv[2] = { NULL, NULL };
187 path = join_paths(ctx, boot_hook_dir, hooks[i]->d_name);
189 if (access(path, X_OK))
192 pb_log("running boot hook %s\n", hooks[i]->d_name);
195 pb_run_cmd(argv, 1, task->dry_run);
203 int boot(void *ctx, struct discover_boot_option *opt, struct boot_command *cmd,
204 int dry_run, boot_status_fn status_fn, void *status_arg)
206 struct boot_task boot_task;
207 struct pb_url *image, *initrd, *dtb;
208 unsigned int clean_image = 0;
209 unsigned int clean_initrd = 0;
210 unsigned int clean_dtb = 0;
216 boot_task.dry_run = dry_run;
218 if (cmd && cmd->boot_image_file) {
219 image = pb_url_parse(opt, cmd->boot_image_file);
220 } else if (opt && opt->boot_image) {
221 image = opt->boot_image->url;
223 pb_log("%s: no image specified", __func__);
227 if (cmd && cmd->initrd_file) {
228 initrd = pb_url_parse(opt, cmd->initrd_file);
229 } else if (opt && opt->initrd) {
230 initrd = opt->initrd->url;
233 if (cmd && cmd->dtb_file) {
234 dtb = pb_url_parse(opt, cmd->dtb_file);
235 } else if (opt && opt->dtb) {
239 if (cmd && cmd->boot_args) {
240 boot_task.args = talloc_strdup(ctx, cmd->boot_args);
241 } else if (opt && opt->option->boot_args) {
242 boot_task.args = talloc_strdup(ctx, opt->option->boot_args);
244 boot_task.args = NULL;
249 update_status(status_fn, status_arg, BOOT_STATUS_INFO,
251 boot_task.local_image = load_url(NULL, image, &clean_image);
252 if (!boot_task.local_image) {
253 update_status(status_fn, status_arg, BOOT_STATUS_ERROR,
254 "Couldn't load kernel image");
258 boot_task.local_initrd = NULL;
260 update_status(status_fn, status_arg, BOOT_STATUS_INFO,
262 boot_task.local_initrd = load_url(NULL, initrd, &clean_initrd);
263 if (!boot_task.local_initrd) {
264 update_status(status_fn, status_arg, BOOT_STATUS_ERROR,
265 "Couldn't load initrd image");
270 boot_task.local_dtb = NULL;
272 update_status(status_fn, status_arg, BOOT_STATUS_INFO,
273 "loading device tree");
274 boot_task.local_dtb = load_url(NULL, dtb, &clean_dtb);
275 if (!boot_task.local_dtb) {
276 update_status(status_fn, status_arg, BOOT_STATUS_ERROR,
277 "Couldn't load device tree");
282 run_boot_hooks(ctx, &boot_task, status_fn, status_arg);
284 update_status(status_fn, status_arg, BOOT_STATUS_INFO,
285 "performing kexec_load");
287 result = kexec_load(&boot_task);
290 update_status(status_fn, status_arg, BOOT_STATUS_ERROR,
291 "kexec load failed");
296 unlink(boot_task.local_image);
298 unlink(boot_task.local_initrd);
300 unlink(boot_task.local_dtb);
302 talloc_free(boot_task.local_image);
303 talloc_free(boot_task.local_initrd);
304 talloc_free(boot_task.local_dtb);
307 update_status(status_fn, status_arg, BOOT_STATUS_INFO,
308 "performing kexec reboot");
310 result = kexec_reboot(boot_task.dry_run);
313 update_status(status_fn, status_arg, BOOT_STATUS_ERROR,
314 "kexec reboot failed");