1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
24 * Copyright 2019 Toomas Soome <tsoome@me.com>
25 * Copyright 2025 Edgecast Cloud LLC.
26 */
27
28 #include <stdio.h>
29 #include <stdbool.h>
30 #include <errno.h>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <assert.h>
34 #include <locale.h>
35 #include <strings.h>
36 #include <libfdisk.h>
37 #include <err.h>
38 #include <time.h>
39 #include <spawn.h>
40
41 #include <sys/dktp/fdisk.h>
42 #include <sys/dkio.h>
43 #include <sys/vtoc.h>
44 #include <sys/multiboot.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <sys/sysmacros.h>
48 #include <sys/efi_partition.h>
49 #include <sys/queue.h>
50 #include <sys/mount.h>
51 #include <sys/mntent.h>
52 #include <sys/mnttab.h>
53 #include <sys/wait.h>
54 #include <libfstyp.h>
55 #include <libgen.h>
56 #include <uuid/uuid.h>
57
58 #include "installboot.h"
59 #include "bblk_einfo.h"
60 #include "boot_utils.h"
61 #include "mboot_extra.h"
62 #include "getresponse.h"
63
64 #ifndef TEXT_DOMAIN
65 #define TEXT_DOMAIN "SUNW_OST_OSCMD"
66 #endif
67
68 /*
69 * BIOS bootblock installation:
70 *
71 * 1. MBR is first sector of the disk. If the file system on target is
72 * ufs or zfs, the same MBR code is installed on first sector of the
73 * partition as well; this will allow to have real MBR sector to be
74 * replaced by some other boot loader and have illumos chainloaded.
75 *
76 * installboot will record the start LBA and size of stage2 code in MBR code.
77 * On boot, the MBR code will read the stage2 code and executes it.
78 *
79 * 2. Stage2 location depends on file system type;
80 * In case of zfs, installboot will store stage2 to zfs bootblk area,
81 * which is 512k bytes from partition start and size is 3.5MB.
82 *
83 * In case of ufs, the stage2 location is 50 512B sectors from
84 * Solaris2 MBR partition start, within boot slice, boot slice size is
85 * one cylinder.
86 *
87 * In case of pcfs, the stage2 location is 50 512B sectors from beginning
88 * of the disk, filling the space between MBR and first partition.
89 * This location assumes no other bootloader and the space is one cylinder,
90 * as first partition is starting from cylinder 1.
91 *
92 * In case of GPT partitioning and if file system is not zfs, the boot
93 * support is only possible with dedicated boot partition. For GPT,
94 * the current implementation is using BOOT partition, which must exist.
95 * BOOT partition does only contain raw boot blocks, without any file system.
96 *
97 * Loader stage2 is created with embedded version, by using fake multiboot (MB)
98 * header within first 32k and EINFO block is at the end of the actual
99 * boot block. MB header load_addr is set to 0 and load_end_addr is set to
100 * actual block end, so the EINFO size is (file size - load_end_addr).
101 * installboot does also store the illumos boot partition LBA to MB space,
102 * starting from bss_end_addr structure member location; stage2 will
103 * detect the partition and file system based on this value.
104 *
105 * Stored location values in MBR/stage2 also mean the bootblocks must be
106 * reinstalled in case the partition content is relocated.
107 */
108
109 static bool write_mbr = false;
110 static bool write_vbr = false;
111 static bool force_mbr = false;
112 static bool force_update = false;
113 static bool do_getinfo = false;
114 static bool do_version = false;
115 static bool do_mirror_bblk = false;
116 static bool strip = false;
117 static bool verbose_dump = false;
118 static size_t sector_size = SECTOR_SIZE;
119
120 /* Versioning string, if present. */
121 static char *update_str;
122
123 /* Default location of boot programs. */
124 static char *boot_dir = "/boot";
125
126 /* Our boot programs */
127 #define STAGE1 "pmbr"
128 #define STAGE2 "gptzfsboot"
129 #define BOOTIA32 "bootia32.efi"
130 #define BOOTX64 "bootx64.efi"
131 #define LOADER32 "loader32.efi"
132 #define LOADER64 "loader64.efi"
133
134 static char *stage1;
135 static char *stage2;
136 static char *efi32;
137 static char *efi64;
138
139 #define GRUB_VERSION_OFF (0x3e)
140 #define GRUB_COMPAT_VERSION_MAJOR 3
141 #define GRUB_COMPAT_VERSION_MINOR 2
142 #define GRUB_VERSION (2 << 8 | 3) /* 3.2 */
143
144 #define LOADER_VERSION (1)
145 #define LOADER_JOYENT_VERSION (2)
146
147 typedef enum {
148 MBR_TYPE_UNKNOWN,
149 MBR_TYPE_GRUB1,
150 MBR_TYPE_LOADER,
151 MBR_TYPE_LOADER_JOYENT,
152 } mbr_type_t;
153
154 /*
155 * Temporary buffer to store the first 32K of data looking for a multiboot
156 * signature.
157 */
158 char mboot_scan[MBOOT_SCAN_SIZE];
159
160 /* Function prototypes. */
161 static void check_options(char *);
162 static int open_device(const char *);
163 static char *make_blkdev(const char *);
164
165 static int read_bootblock_from_file(const char *, ib_bootblock_t *);
166 static void add_bootblock_einfo(ib_bootblock_t *, char *);
167 static void prepare_bootblock(ib_data_t *, struct partlist *, char *);
168 static int handle_install(char *, int, char **);
169 static int handle_getinfo(char *, int, char **);
170 static int handle_mirror(char *, int, char **);
171 static void usage(char *, int) __NORETURN;
172
173 static char *
stagefs_mount(char * blkdev,struct partlist * plist)174 stagefs_mount(char *blkdev, struct partlist *plist)
175 {
176 char *path;
177 char optbuf[MAX_MNTOPT_STR] = { '\0', };
178 char *template = strdup("/tmp/ibootXXXXXX");
179 int ret;
180
181 if (template == NULL)
182 return (NULL);
183
184 if ((path = mkdtemp(template)) == NULL) {
185 free(template);
186 return (NULL);
187 }
188
189 (void) snprintf(optbuf, MAX_MNTOPT_STR, "timezone=%d",
190 timezone);
191 ret = mount(blkdev, path, MS_OPTIONSTR,
192 MNTTYPE_PCFS, NULL, 0, optbuf, MAX_MNTOPT_STR);
193 if (ret != 0) {
194 (void) rmdir(path);
195 free(path);
196 path = NULL;
197 }
198 plist->pl_device->stage.mntpnt = path;
199 return (path);
200 }
201
202 static void
install_stage1_cb(void * data,struct partlist * plist)203 install_stage1_cb(void *data, struct partlist *plist)
204 {
205 int rv, fd;
206 ib_device_t *device = plist->pl_device;
207
208 if (plist->pl_type == IB_BBLK_MBR && !write_mbr)
209 return;
210
211 if ((fd = open_device(plist->pl_devname)) == -1) {
212 (void) fprintf(stdout, gettext("cannot open "
213 "device %s\n"), plist->pl_devname);
214 perror("open");
215 return;
216 }
217
218 rv = write_out(fd, plist->pl_stage, sector_size, 0);
219 if (rv != BC_SUCCESS) {
220 (void) fprintf(stdout, gettext("cannot write "
221 "partition boot sector\n"));
222 perror("write");
223 } else {
224 (void) fprintf(stdout, gettext("stage1 written to "
225 "%s %d sector 0 (abs %d)\n\n"),
226 device->devtype == IB_DEV_MBR? "partition" : "slice",
227 device->stage.id, device->stage.start);
228 }
229 }
230
231 static void
install_stage2_cb(void * data,struct partlist * plist)232 install_stage2_cb(void *data, struct partlist *plist)
233 {
234 ib_bootblock_t *bblock = plist->pl_src_data;
235 int fd, ret;
236 off_t offset;
237 uint64_t abs;
238
239 /*
240 * ZFS bootblock area is 3.5MB, make sure we can fit.
241 * buf_size is size of bootblk+EINFO.
242 */
243 if (bblock->buf_size > BBLK_ZFS_BLK_SIZE) {
244 (void) fprintf(stderr, gettext("bootblock is too large\n"));
245 return;
246 }
247
248 abs = plist->pl_device->stage.start + plist->pl_device->stage.offset;
249
250 if ((fd = open_device(plist->pl_devname)) == -1) {
251 (void) fprintf(stdout, gettext("cannot open "
252 "device %s\n"), plist->pl_devname);
253 perror("open");
254 return;
255 }
256 offset = plist->pl_device->stage.offset * sector_size;
257 ret = write_out(fd, bblock->buf, bblock->buf_size, offset);
258 (void) close(fd);
259 if (ret != BC_SUCCESS) {
260 BOOT_DEBUG("Error writing the ZFS bootblock "
261 "to %s at offset %d\n", plist->pl_devname, offset);
262 return;
263 }
264 (void) fprintf(stdout, gettext("bootblock written for %s,"
265 " %d sectors starting at %d (abs %lld)\n\n"), plist->pl_devname,
266 bblock->buf_size / sector_size, offset / sector_size, abs);
267 }
268
269 static bool
mkfs_pcfs(const char * dev)270 mkfs_pcfs(const char *dev)
271 {
272 pid_t pid, w;
273 posix_spawnattr_t attr;
274 posix_spawn_file_actions_t file_actions;
275 int status;
276 char *cmd[7];
277
278 if (posix_spawnattr_init(&attr))
279 return (false);
280 if (posix_spawn_file_actions_init(&file_actions)) {
281 (void) posix_spawnattr_destroy(&attr);
282 return (false);
283 }
284
285 if (posix_spawnattr_setflags(&attr,
286 POSIX_SPAWN_NOSIGCHLD_NP | POSIX_SPAWN_WAITPID_NP)) {
287 (void) posix_spawnattr_destroy(&attr);
288 (void) posix_spawn_file_actions_destroy(&file_actions);
289 return (false);
290 }
291 if (posix_spawn_file_actions_addopen(&file_actions, 0, "/dev/null",
292 O_RDONLY, 0)) {
293 (void) posix_spawnattr_destroy(&attr);
294 (void) posix_spawn_file_actions_destroy(&file_actions);
295 return (false);
296 }
297
298 cmd[0] = "/usr/sbin/mkfs";
299 cmd[1] = "-F";
300 cmd[2] = "pcfs";
301 cmd[3] = "-o";
302 cmd[4] = "fat=32";
303 cmd[5] = (char *)dev;
304 cmd[6] = NULL;
305
306 if (posix_spawn(&pid, cmd[0], &file_actions, &attr, cmd, NULL))
307 return (false);
308 (void) posix_spawnattr_destroy(&attr);
309 (void) posix_spawn_file_actions_destroy(&file_actions);
310
311 do {
312 w = waitpid(pid, &status, 0);
313 } while (w == -1 && errno == EINTR);
314 if (w == -1)
315 status = -1;
316
317 return (status != -1);
318 }
319
320 static void
install_esp_cb(void * data,struct partlist * plist)321 install_esp_cb(void *data, struct partlist *plist)
322 {
323 fstyp_handle_t fhdl;
324 const char *fident;
325 bool pcfs;
326 char *blkdev, *path, *file;
327 FILE *fp;
328 struct mnttab mp, mpref = { 0 };
329 ib_bootblock_t *bblock = plist->pl_src_data;
330 int fd, ret;
331
332 if ((fd = open_device(plist->pl_devname)) == -1)
333 return;
334
335 if (fstyp_init(fd, 0, NULL, &fhdl) != 0) {
336 (void) close(fd);
337 return;
338 }
339
340 pcfs = false;
341 if (fstyp_ident(fhdl, NULL, &fident) == 0) {
342 if (strcmp(fident, MNTTYPE_PCFS) == 0)
343 pcfs = true;
344 }
345 fstyp_fini(fhdl);
346 (void) close(fd);
347
348 if (!pcfs) {
349 (void) printf(gettext("Creating pcfs on ESP %s\n"),
350 plist->pl_devname);
351
352 if (!mkfs_pcfs(plist->pl_devname)) {
353 (void) fprintf(stderr, gettext("mkfs -F pcfs failed "
354 "on %s\n"), plist->pl_devname);
355 return;
356 }
357 }
358 blkdev = make_blkdev(plist->pl_devname);
359 if (blkdev == NULL)
360 return;
361
362 fp = fopen(MNTTAB, "r");
363 if (fp == NULL) {
364 perror("fopen");
365 free(blkdev);
366 return;
367 }
368
369 mpref.mnt_special = blkdev;
370 ret = getmntany(fp, &mp, &mpref);
371 (void) fclose(fp);
372 if (ret == 0)
373 path = mp.mnt_mountp;
374 else
375 path = stagefs_mount(blkdev, plist);
376
377 free(blkdev);
378 if (path == NULL)
379 return;
380
381 if (asprintf(&file, "%s%s", path, "/EFI") < 0) {
382 perror(gettext("Memory allocation failure"));
383 return;
384 }
385
386 ret = mkdir(file, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
387 if (ret == 0 || errno == EEXIST) {
388 free(file);
389 if (asprintf(&file, "%s%s", path, "/EFI/Boot") < 0) {
390 perror(gettext("Memory allocation failure"));
391 return;
392 }
393 ret = mkdir(file,
394 S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
395 if (errno == EEXIST)
396 ret = 0;
397 }
398 free(file);
399 if (ret < 0) {
400 perror("mkdir");
401 return;
402 }
403
404 if (asprintf(&file, "%s%s", path, plist->pl_device->stage.path) < 0) {
405 perror(gettext("Memory allocation failure"));
406 return;
407 }
408
409 /* Write stage file. Should create temp file and rename. */
410 (void) chmod(file, S_IRUSR | S_IWUSR);
411 fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
412 if (fd != -1) {
413 ret = write_out(fd, bblock->buf, bblock->buf_size, 0);
414 if (ret == BC_SUCCESS) {
415 (void) fprintf(stdout,
416 gettext("bootblock written to %s\n\n"), file);
417 } else {
418 (void) fprintf(stdout,
419 gettext("error while writing %s\n"), file);
420 }
421 (void) fchmod(fd, S_IRUSR | S_IRGRP | S_IROTH);
422 (void) close(fd);
423 }
424 free(file);
425 }
426
427 /*
428 * MBR setup only depends on write_mbr toggle.
429 */
430 static bool
compare_mbr_cb(struct partlist * plist)431 compare_mbr_cb(struct partlist *plist)
432 {
433 /* get confirmation for -m */
434 if (write_mbr && !force_mbr) {
435 (void) fprintf(stdout, gettext("Updating master boot sector "
436 "destroys existing boot managers (if any).\n"
437 "continue (y/n)? "));
438 if (!yes()) {
439 write_mbr = false;
440 (void) fprintf(stdout, gettext("master boot sector "
441 "not updated\n"));
442 }
443 }
444 if (write_mbr)
445 (void) printf("%s is newer than one in %s\n",
446 plist->pl_src_name, plist->pl_devname);
447 return (write_mbr);
448 }
449
450 /*
451 * VBR setup is done in pair with stage2.
452 */
453 static bool
compare_stage1_cb(struct partlist * plist)454 compare_stage1_cb(struct partlist *plist)
455 {
456 if (write_vbr) {
457 (void) printf("%s is newer than one in %s\n",
458 plist->pl_src_name, plist->pl_devname);
459 }
460 return (write_vbr);
461 }
462
463 /*
464 * Return true if we can update, false if not.
465 */
466 static bool
compare_einfo_cb(struct partlist * plist)467 compare_einfo_cb(struct partlist *plist)
468 {
469 ib_bootblock_t *bblock, *bblock_file;
470 bblk_einfo_t *einfo, *einfo_file;
471 bblk_hs_t bblock_hs;
472 bool rv;
473
474 bblock_file = plist->pl_src_data;
475 if (bblock_file == NULL)
476 return (false); /* source is missing, cannot update */
477
478 bblock = plist->pl_stage;
479 if (bblock == NULL ||
480 bblock->extra == NULL ||
481 bblock->extra_size == 0) {
482 if (plist->pl_type == IB_BBLK_STAGE2)
483 write_vbr = true;
484 return (true);
485 }
486
487 einfo = find_einfo(bblock->extra, bblock->extra_size);
488 if (einfo == NULL) {
489 BOOT_DEBUG("No extended information available on disk\n");
490 if (plist->pl_type == IB_BBLK_STAGE2)
491 write_vbr = true;
492 return (true);
493 }
494
495 einfo_file = find_einfo(bblock_file->extra, bblock_file->extra_size);
496 if (einfo_file == NULL) {
497 /*
498 * loader bootblock is versioned. missing version means
499 * probably incompatible block. installboot can not install
500 * grub, for example.
501 */
502 (void) fprintf(stderr,
503 gettext("ERROR: non versioned bootblock in file\n"));
504 return (false);
505 } else {
506 if (update_str == NULL) {
507 update_str = einfo_get_string(einfo_file);
508 do_version = true;
509 }
510 }
511
512 if (!do_version || update_str == NULL) {
513 (void) fprintf(stderr,
514 gettext("WARNING: target device %s has a "
515 "versioned bootblock that is going to be overwritten by a "
516 "non versioned one\n"), plist->pl_devname);
517 if (plist->pl_type == IB_BBLK_STAGE2)
518 write_vbr = true;
519 return (true);
520 }
521
522 if (force_update) {
523 BOOT_DEBUG("Forcing update of %s bootblock\n",
524 plist->pl_devname);
525 if (plist->pl_type == IB_BBLK_STAGE2)
526 write_vbr = true;
527 return (true);
528 }
529
530 BOOT_DEBUG("Ready to check installed version vs %s\n", update_str);
531
532 bblock_hs.src_buf = (unsigned char *)bblock_file->file;
533 bblock_hs.src_size = bblock_file->file_size;
534
535 rv = einfo_should_update(einfo, &bblock_hs, update_str);
536 if (rv == false) {
537 (void) fprintf(stderr, gettext("Bootblock version installed "
538 "on %s is more recent or identical to\n%s\n"
539 "Use -F to override or install without the -u option.\n\n"),
540 plist->pl_devname, plist->pl_src_name);
541 } else {
542 (void) printf("%s is newer than one in %s\n",
543 plist->pl_src_name, plist->pl_devname);
544 if (plist->pl_type == IB_BBLK_STAGE2)
545 write_vbr = true;
546 }
547 return (rv);
548 }
549
550 static bool
read_stage1_cb(struct partlist * plist)551 read_stage1_cb(struct partlist *plist)
552 {
553 int fd;
554 bool rv = false;
555
556 if ((fd = open_device(plist->pl_devname)) == -1)
557 return (rv);
558
559 if (plist->pl_stage == NULL)
560 plist->pl_stage = calloc(1, sector_size);
561
562 if (plist->pl_stage == NULL) {
563 perror("calloc");
564 goto done;
565 }
566
567 if (pread(fd, plist->pl_stage, sector_size, 0) == -1) {
568 perror("pread");
569 goto done;
570 }
571 rv = true;
572 done:
573 (void) close(fd);
574 return (rv);
575 }
576
577 static bool
read_stage1_bbl_cb(struct partlist * plist)578 read_stage1_bbl_cb(struct partlist *plist)
579 {
580 int fd;
581 void *data;
582 bool rv = false;
583
584 /* Allocate actual sector size. */
585 data = calloc(1, sector_size);
586 if (data == NULL)
587 return (rv);
588
589 /* read the stage1 file from filesystem */
590 fd = open(plist->pl_src_name, O_RDONLY);
591 if (fd == -1 ||
592 read(fd, data, SECTOR_SIZE) != SECTOR_SIZE) {
593 (void) fprintf(stderr, gettext("cannot read stage1 file %s\n"),
594 plist->pl_src_name);
595 free(data);
596 if (fd != -1)
597 (void) close(fd);
598 return (rv);
599 }
600
601 plist->pl_src_data = data;
602 (void) close(fd);
603 return (true);
604 }
605
606 static bool
read_stage2_cb(struct partlist * plist)607 read_stage2_cb(struct partlist *plist)
608 {
609 ib_device_t *device;
610 ib_bootblock_t *bblock;
611 int fd;
612 uint32_t size, offset;
613 uint32_t buf_size;
614 uint32_t mboot_off;
615 multiboot_header_t *mboot;
616 size_t scan_size;
617
618 bblock = calloc(1, sizeof (ib_bootblock_t));
619 if (bblock == NULL)
620 return (false);
621
622 if ((fd = open_device(plist->pl_devname)) == -1) {
623 free(bblock);
624 return (false);
625 }
626
627 device = plist->pl_device;
628 plist->pl_stage = bblock;
629 offset = device->stage.offset * sector_size;
630 scan_size = MIN(sizeof (mboot_scan),
631 (device->stage.size - device->stage.offset) * sector_size);
632
633 if (read_in(fd, mboot_scan, scan_size, offset)
634 != BC_SUCCESS) {
635 BOOT_DEBUG("Error reading bootblock area\n");
636 perror("read");
637 (void) close(fd);
638 return (false);
639 }
640
641 /* No multiboot means no chance of knowing bootblock size */
642 if (find_multiboot(mboot_scan, scan_size, &mboot_off)
643 != BC_SUCCESS) {
644 BOOT_DEBUG("Unable to find multiboot header\n");
645 (void) close(fd);
646 return (false);
647 }
648 mboot = (multiboot_header_t *)(mboot_scan + mboot_off);
649
650 /*
651 * make sure mboot has sane values
652 */
653 if (mboot->load_end_addr == 0 ||
654 mboot->load_end_addr < mboot->load_addr) {
655 (void) close(fd);
656 return (false);
657 }
658
659 /*
660 * Currently, the amount of space reserved for extra information
661 * is "fixed". We may have to scan for the terminating extra payload
662 * in the future.
663 */
664 size = mboot->load_end_addr - mboot->load_addr;
665 buf_size = P2ROUNDUP(size + sector_size, sector_size);
666 bblock->file_size = size;
667
668 bblock->buf = malloc(buf_size);
669 if (bblock->buf == NULL) {
670 BOOT_DEBUG("Unable to allocate enough memory to read"
671 " the extra bootblock from the disk\n");
672 perror(gettext("Memory allocation failure"));
673 (void) close(fd);
674 return (false);
675 }
676 bblock->buf_size = buf_size;
677
678 if (read_in(fd, bblock->buf, buf_size, offset) != BC_SUCCESS) {
679 BOOT_DEBUG("Error reading the bootblock\n");
680 (void) free(bblock->buf);
681 bblock->buf = NULL;
682 (void) close(fd);
683 return (false);
684 }
685
686 /* Update pointers. */
687 bblock->file = bblock->buf;
688 bblock->mboot_off = mboot_off;
689 bblock->mboot = (multiboot_header_t *)(bblock->buf + bblock->mboot_off);
690 bblock->extra = bblock->buf + P2ROUNDUP(bblock->file_size, 8);
691 bblock->extra_size = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8);
692
693 BOOT_DEBUG("mboot at %p offset %d, extra at %p size %d, buf=%p "
694 "(size=%d)\n", bblock->mboot, bblock->mboot_off, bblock->extra,
695 bblock->extra_size, bblock->buf, bblock->buf_size);
696
697 return (true);
698 }
699
700 static bool
read_einfo_file_cb(struct partlist * plist)701 read_einfo_file_cb(struct partlist *plist)
702 {
703 int rc;
704 void *stage;
705
706 stage = calloc(1, sizeof (ib_bootblock_t));
707 if (stage == NULL)
708 return (false);
709
710 rc = read_bootblock_from_file(plist->pl_devname, stage);
711 if (rc != BC_SUCCESS) {
712 free(stage);
713 stage = NULL;
714 }
715 plist->pl_stage = stage;
716 return (rc == BC_SUCCESS);
717 }
718
719 static bool
read_stage2_file_cb(struct partlist * plist)720 read_stage2_file_cb(struct partlist *plist)
721 {
722 int rc;
723 void *data;
724
725 data = calloc(1, sizeof (ib_bootblock_t));
726 if (data == NULL)
727 return (false);
728
729 rc = read_bootblock_from_file(plist->pl_src_name, data);
730 if (rc != BC_SUCCESS) {
731 free(data);
732 data = NULL;
733 }
734 plist->pl_src_data = data;
735 return (rc == BC_SUCCESS);
736 }
737
738 /*
739 * convert /dev/rdsk/... to /dev/dsk/...
740 */
741 static char *
make_blkdev(const char * path)742 make_blkdev(const char *path)
743 {
744 char *tmp;
745 char *ptr = strdup(path);
746
747 if (ptr == NULL)
748 return (ptr);
749
750 tmp = strstr(ptr, "rdsk");
751 if (tmp == NULL) {
752 free(ptr);
753 return (NULL); /* Something is very wrong */
754 }
755 /* This is safe because we do shorten the string */
756 (void) memmove(tmp, tmp + 1, strlen(tmp));
757 return (ptr);
758 }
759
760 /*
761 * Try to mount ESP and read boot program.
762 */
763 static bool
read_einfo_esp_cb(struct partlist * plist)764 read_einfo_esp_cb(struct partlist *plist)
765 {
766 fstyp_handle_t fhdl;
767 const char *fident;
768 char *blkdev, *path, *file;
769 bool rv = false;
770 FILE *fp;
771 struct mnttab mp, mpref = { 0 };
772 int fd, ret;
773
774 if ((fd = open_device(plist->pl_devname)) == -1)
775 return (rv);
776
777 if (fstyp_init(fd, 0, NULL, &fhdl) != 0) {
778 (void) close(fd);
779 return (rv);
780 }
781
782 if (fstyp_ident(fhdl, NULL, &fident) != 0) {
783 fstyp_fini(fhdl);
784 (void) close(fd);
785 (void) fprintf(stderr, gettext("Failed to detect file "
786 "system type\n"));
787 return (rv);
788 }
789
790 /* We only do expect pcfs. */
791 if (strcmp(fident, MNTTYPE_PCFS) != 0) {
792 (void) fprintf(stderr,
793 gettext("File system %s is not supported.\n"), fident);
794 fstyp_fini(fhdl);
795 (void) close(fd);
796 return (rv);
797 }
798 fstyp_fini(fhdl);
799 (void) close(fd);
800
801 blkdev = make_blkdev(plist->pl_devname);
802 if (blkdev == NULL)
803 return (rv);
804
805 /* mount ESP if needed, read boot program(s) and unmount. */
806 fp = fopen(MNTTAB, "r");
807 if (fp == NULL) {
808 perror("fopen");
809 free(blkdev);
810 return (rv);
811 }
812
813 mpref.mnt_special = blkdev;
814 ret = getmntany(fp, &mp, &mpref);
815 (void) fclose(fp);
816 if (ret == 0)
817 path = mp.mnt_mountp;
818 else
819 path = stagefs_mount(blkdev, plist);
820
821 free(blkdev);
822 if (path == NULL)
823 return (rv);
824
825 if (asprintf(&file, "%s%s", path, plist->pl_device->stage.path) < 0) {
826 return (rv);
827 }
828
829 plist->pl_stage = calloc(1, sizeof (ib_bootblock_t));
830 if (plist->pl_stage == NULL) {
831 free(file);
832 return (rv);
833 }
834 if (read_bootblock_from_file(file, plist->pl_stage) != BC_SUCCESS) {
835 free(plist->pl_stage);
836 plist->pl_stage = NULL;
837 } else {
838 rv = true;
839 }
840
841 free(file);
842 return (rv);
843 }
844
845 static void
print_stage1_cb(struct partlist * plist)846 print_stage1_cb(struct partlist *plist)
847 {
848 struct mboot *mbr;
849 struct ipart *part;
850 mbr_type_t type = MBR_TYPE_UNKNOWN;
851 bool pmbr = false;
852 char *label;
853
854 mbr = plist->pl_stage;
855
856 if (*((uint16_t *)&mbr->bootinst[GRUB_VERSION_OFF]) == GRUB_VERSION) {
857 type = MBR_TYPE_GRUB1;
858 } else if (mbr->bootinst[STAGE1_MBR_VERSION] == LOADER_VERSION) {
859 type = MBR_TYPE_LOADER;
860 } else if (mbr->bootinst[STAGE1_MBR_VERSION] == LOADER_JOYENT_VERSION) {
861 type = MBR_TYPE_LOADER_JOYENT;
862 }
863
864 part = (struct ipart *)mbr->parts;
865 for (int i = 0; i < FD_NUMPART; i++) {
866 if (part[i].systid == EFI_PMBR)
867 pmbr = true;
868 }
869
870 if (plist->pl_type == IB_BBLK_MBR)
871 label = pmbr ? "PMBR" : "MBR";
872 else
873 label = "VBR";
874
875 printf("%s block from %s:\n", label, plist->pl_devname);
876
877 switch (type) {
878 case MBR_TYPE_UNKNOWN:
879 printf("Format: unknown\n");
880 break;
881 case MBR_TYPE_GRUB1:
882 printf("Format: grub1\n");
883 break;
884 case MBR_TYPE_LOADER:
885 printf("Format: loader (illumos)\n");
886 break;
887 case MBR_TYPE_LOADER_JOYENT:
888 printf("Format: loader (joyent)\n");
889 break;
890 }
891
892 printf("Signature: 0x%hx (%s)\n", mbr->signature,
893 mbr->signature == MBB_MAGIC ? "valid" : "invalid");
894
895 printf("UniqueMBRDiskSignature: %#lx\n",
896 *(uint32_t *)&mbr->bootinst[STAGE1_SIG]);
897
898 if (type == MBR_TYPE_LOADER || type == MBR_TYPE_LOADER_JOYENT) {
899 char uuid[UUID_PRINTABLE_STRING_LENGTH];
900
901 printf("Loader STAGE1_STAGE2_LBA: %llu\n",
902 *(uint64_t *)&mbr->bootinst[STAGE1_STAGE2_LBA]);
903
904 printf("Loader STAGE1_STAGE2_SIZE: %hu\n",
905 *(uint16_t *)&mbr->bootinst[STAGE1_STAGE2_SIZE]);
906
907 uuid_unparse((uchar_t *)&mbr->bootinst[STAGE1_STAGE2_UUID],
908 uuid);
909
910 printf("Loader STAGE1_STAGE2_UUID: %s\n", uuid);
911 }
912 printf("\n");
913 }
914
915 static void
print_einfo_cb(struct partlist * plist)916 print_einfo_cb(struct partlist *plist)
917 {
918 uint8_t flags = 0;
919 ib_bootblock_t *bblock;
920 bblk_einfo_t *einfo = NULL;
921 const char *filepath;
922
923 /* No stage, get out. */
924 bblock = plist->pl_stage;
925 if (bblock == NULL)
926 return;
927
928 if (plist->pl_device->stage.path == NULL)
929 filepath = "";
930 else
931 filepath = plist->pl_device->stage.path;
932
933 printf("Boot block from %s:%s\n", plist->pl_devname, filepath);
934
935 if (bblock->extra != NULL)
936 einfo = find_einfo(bblock->extra, bblock->extra_size);
937
938 if (einfo == NULL) {
939 (void) fprintf(stderr,
940 gettext("No extended information found.\n\n"));
941 return;
942 }
943
944 /* Print the extended information. */
945 if (strip)
946 flags |= EINFO_EASY_PARSE;
947 if (verbose_dump)
948 flags |= EINFO_PRINT_HEADER;
949
950 print_einfo(flags, einfo, bblock->extra_size);
951 printf("\n");
952 }
953
954 static size_t
get_media_info(int fd)955 get_media_info(int fd)
956 {
957 struct dk_minfo disk_info;
958
959 if ((ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info)) == -1)
960 return (SECTOR_SIZE);
961
962 return (disk_info.dki_lbsize);
963 }
964
965 static struct partlist *
partlist_alloc(void)966 partlist_alloc(void)
967 {
968 struct partlist *pl;
969
970 if ((pl = calloc(1, sizeof (*pl))) == NULL) {
971 perror("calloc");
972 return (NULL);
973 }
974
975 pl->pl_device = calloc(1, sizeof (*pl->pl_device));
976 if (pl->pl_device == NULL) {
977 perror("calloc");
978 free(pl);
979 return (NULL);
980 }
981
982 return (pl);
983 }
984
985 static void
partlist_free(struct partlist * pl)986 partlist_free(struct partlist *pl)
987 {
988 ib_bootblock_t *bblock;
989 ib_device_t *device;
990
991 switch (pl->pl_type) {
992 case IB_BBLK_MBR:
993 case IB_BBLK_STAGE1:
994 free(pl->pl_stage);
995 break;
996 default:
997 if (pl->pl_stage != NULL) {
998 bblock = pl->pl_stage;
999 free(bblock->buf);
1000 free(bblock);
1001 }
1002 }
1003
1004 /* umount the stage fs. */
1005 if (pl->pl_device->stage.mntpnt != NULL) {
1006 if (umount(pl->pl_device->stage.mntpnt) == 0)
1007 (void) rmdir(pl->pl_device->stage.mntpnt);
1008 free(pl->pl_device->stage.mntpnt);
1009 }
1010 device = pl->pl_device;
1011 free(device->target.path);
1012 free(pl->pl_device);
1013
1014 free(pl->pl_src_data);
1015 free(pl->pl_devname);
1016 free(pl);
1017 }
1018
1019 static bool
probe_fstyp(ib_data_t * data)1020 probe_fstyp(ib_data_t *data)
1021 {
1022 fstyp_handle_t fhdl;
1023 const char *fident;
1024 char *ptr;
1025 int fd;
1026 bool rv = false;
1027
1028 /* Record partition id */
1029 ptr = strrchr(data->target.path, 'p');
1030 if (ptr == NULL)
1031 ptr = strrchr(data->target.path, 's');
1032 data->target.id = atoi(++ptr);
1033 if ((fd = open_device(data->target.path)) == -1)
1034 return (rv);
1035
1036 if (fstyp_init(fd, 0, NULL, &fhdl) != 0) {
1037 (void) close(fd);
1038 return (rv);
1039 }
1040
1041 if (fstyp_ident(fhdl, NULL, &fident) != 0) {
1042 fstyp_fini(fhdl);
1043 (void) fprintf(stderr, gettext("Failed to detect file "
1044 "system type\n"));
1045 (void) close(fd);
1046 return (rv);
1047 }
1048
1049 rv = true;
1050 if (strcmp(fident, MNTTYPE_ZFS) == 0)
1051 data->target.fstype = IB_FS_ZFS;
1052 else if (strcmp(fident, MNTTYPE_UFS) == 0) {
1053 data->target.fstype = IB_FS_UFS;
1054 } else if (strcmp(fident, MNTTYPE_PCFS) == 0) {
1055 data->target.fstype = IB_FS_PCFS;
1056 /* with pcfs we always write MBR */
1057 force_mbr = true;
1058 write_mbr = true;
1059 } else {
1060 (void) fprintf(stderr, gettext("File system %s is not "
1061 "supported by loader\n"), fident);
1062 rv = false;
1063 }
1064 fstyp_fini(fhdl);
1065 (void) close(fd);
1066 return (rv);
1067 }
1068
1069 static bool
get_slice(ib_data_t * data,struct partlist * pl,struct dk_gpt * vtoc,uint16_t tag)1070 get_slice(ib_data_t *data, struct partlist *pl, struct dk_gpt *vtoc,
1071 uint16_t tag)
1072 {
1073 uint_t i;
1074 ib_device_t *device = pl->pl_device;
1075 char *path, *ptr;
1076
1077 if (tag != V_BOOT && tag != V_SYSTEM)
1078 return (false);
1079
1080 for (i = 0; i < vtoc->efi_nparts; i++) {
1081 if (vtoc->efi_parts[i].p_tag == tag) {
1082 if ((path = strdup(data->target.path)) == NULL) {
1083 perror(gettext("Memory allocation failure"));
1084 return (false);
1085 }
1086 ptr = strrchr(path, 's');
1087 ptr++;
1088 *ptr = '\0';
1089 (void) asprintf(&ptr, "%s%d", path, i);
1090 free(path);
1091 if (ptr == NULL) {
1092 perror(gettext("Memory allocation failure"));
1093 return (false);
1094 }
1095 pl->pl_devname = ptr;
1096 device->stage.id = i;
1097 device->stage.devtype = IB_DEV_EFI;
1098 switch (vtoc->efi_parts[i].p_tag) {
1099 case V_BOOT:
1100 device->stage.fstype = IB_FS_NONE;
1101 /* leave sector 0 for VBR */
1102 device->stage.offset = 1;
1103 break;
1104 case V_SYSTEM:
1105 device->stage.fstype = IB_FS_PCFS;
1106 break;
1107 }
1108 device->stage.tag = vtoc->efi_parts[i].p_tag;
1109 device->stage.start = vtoc->efi_parts[i].p_start;
1110 device->stage.size = vtoc->efi_parts[i].p_size;
1111 break;
1112 }
1113 }
1114 return (true);
1115 }
1116
1117 static bool
allocate_slice(ib_data_t * data,struct dk_gpt * vtoc,uint16_t tag,struct partlist ** plp)1118 allocate_slice(ib_data_t *data, struct dk_gpt *vtoc, uint16_t tag,
1119 struct partlist **plp)
1120 {
1121 struct partlist *pl;
1122
1123 *plp = NULL;
1124 if ((pl = partlist_alloc()) == NULL)
1125 return (false);
1126
1127 pl->pl_device = calloc(1, sizeof (*pl->pl_device));
1128 if (pl->pl_device == NULL) {
1129 perror("calloc");
1130 partlist_free(pl);
1131 return (false);
1132 }
1133 if (!get_slice(data, pl, vtoc, tag)) {
1134 partlist_free(pl);
1135 return (false);
1136 }
1137
1138 /* tag was not found */
1139 if (pl->pl_devname == NULL)
1140 partlist_free(pl);
1141 else
1142 *plp = pl;
1143
1144 return (true);
1145 }
1146
1147 static bool
probe_gpt(ib_data_t * data)1148 probe_gpt(ib_data_t *data)
1149 {
1150 struct partlist *pl;
1151 struct dk_gpt *vtoc;
1152 ib_device_t *device;
1153 int slice, fd;
1154 bool rv = false;
1155
1156 if ((fd = open_device(data->target.path)) < 0)
1157 return (rv);
1158
1159 slice = efi_alloc_and_read(fd, &vtoc);
1160 (void) close(fd);
1161 if (slice < 0)
1162 return (rv);
1163
1164 data->device.devtype = IB_DEV_EFI;
1165 data->target.start = vtoc->efi_parts[slice].p_start;
1166 data->target.size = vtoc->efi_parts[slice].p_size;
1167
1168 /* Always update PMBR. */
1169 force_mbr = true;
1170 write_mbr = true;
1171
1172 /*
1173 * With GPT we can have boot partition and ESP.
1174 * Boot partition can have both stage 1 and stage 2.
1175 */
1176 if (!allocate_slice(data, vtoc, V_BOOT, &pl))
1177 goto done;
1178 if (pl != NULL) {
1179 pl->pl_src_name = stage1;
1180 pl->pl_type = IB_BBLK_STAGE1;
1181 pl->pl_cb.compare = compare_stage1_cb;
1182 pl->pl_cb.install = install_stage1_cb;
1183 pl->pl_cb.read = read_stage1_cb;
1184 pl->pl_cb.read_bbl = read_stage1_bbl_cb;
1185 pl->pl_cb.print = print_stage1_cb;
1186 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1187 } else if (data->target.fstype != IB_FS_ZFS) {
1188 (void) fprintf(stderr, gettext("Booting %s from EFI "
1189 "labeled disks requires the boot partition.\n"),
1190 data->target.fstype == IB_FS_UFS?
1191 MNTTYPE_UFS : MNTTYPE_PCFS);
1192 goto done;
1193 }
1194 /* Add stage 2 */
1195 if (!allocate_slice(data, vtoc, V_BOOT, &pl))
1196 goto done;
1197 if (pl != NULL) {
1198 pl->pl_src_name = stage2;
1199 pl->pl_type = IB_BBLK_STAGE2;
1200 pl->pl_cb.compare = compare_einfo_cb;
1201 pl->pl_cb.install = install_stage2_cb;
1202 pl->pl_cb.read = read_stage2_cb;
1203 pl->pl_cb.read_bbl = read_stage2_file_cb;
1204 pl->pl_cb.print = print_einfo_cb;
1205 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1206 }
1207
1208 /* ESP can have 32- and 64-bit boot code. */
1209 if (!allocate_slice(data, vtoc, V_SYSTEM, &pl))
1210 goto done;
1211 if (pl != NULL) {
1212 pl->pl_device->stage.path = "/EFI/Boot/" BOOTIA32;
1213 pl->pl_src_name = efi32;
1214 pl->pl_type = IB_BBLK_EFI;
1215 pl->pl_cb.compare = compare_einfo_cb;
1216 pl->pl_cb.install = install_esp_cb;
1217 pl->pl_cb.read = read_einfo_esp_cb;
1218 pl->pl_cb.read_bbl = read_stage2_file_cb;
1219 pl->pl_cb.print = print_einfo_cb;
1220 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1221 }
1222 if (!allocate_slice(data, vtoc, V_SYSTEM, &pl))
1223 goto done;
1224 if (pl != NULL) {
1225 pl->pl_device->stage.path = "/EFI/Boot/" BOOTX64;
1226 pl->pl_src_name = efi64;
1227 pl->pl_type = IB_BBLK_EFI;
1228 pl->pl_cb.compare = compare_einfo_cb;
1229 pl->pl_cb.install = install_esp_cb;
1230 pl->pl_cb.read = read_einfo_esp_cb;
1231 pl->pl_cb.read_bbl = read_stage2_file_cb;
1232 pl->pl_cb.print = print_einfo_cb;
1233 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1234 }
1235
1236 /* add stage for our target file system slice */
1237 pl = partlist_alloc();
1238 if (pl == NULL)
1239 goto done;
1240
1241 device = pl->pl_device;
1242 device->stage.devtype = data->device.devtype;
1243 if ((pl->pl_devname = strdup(data->target.path)) == NULL) {
1244 perror(gettext("Memory allocation failure"));
1245 partlist_free(pl);
1246 goto done;
1247 }
1248
1249 device->stage.id = slice;
1250 device->stage.start = vtoc->efi_parts[slice].p_start;
1251 device->stage.size = vtoc->efi_parts[slice].p_size;
1252
1253 /* ZFS and UFS can have stage1 in boot area. */
1254 if (data->target.fstype == IB_FS_ZFS ||
1255 data->target.fstype == IB_FS_UFS) {
1256 pl->pl_src_name = stage1;
1257 pl->pl_type = IB_BBLK_STAGE1;
1258 pl->pl_cb.compare = compare_stage1_cb;
1259 pl->pl_cb.install = install_stage1_cb;
1260 pl->pl_cb.read = read_stage1_cb;
1261 pl->pl_cb.read_bbl = read_stage1_bbl_cb;
1262 pl->pl_cb.print = print_stage1_cb;
1263 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1264 }
1265
1266 if (data->target.fstype == IB_FS_ZFS) {
1267 pl = partlist_alloc();
1268 if (pl == NULL)
1269 goto done;
1270
1271 device = pl->pl_device;
1272 device->stage.devtype = data->device.devtype;
1273
1274 if ((pl->pl_devname = strdup(data->target.path)) == NULL) {
1275 perror(gettext("Memory allocation failure"));
1276 goto done;
1277 }
1278
1279 device->stage.id = slice;
1280 device->stage.start = vtoc->efi_parts[slice].p_start;
1281 device->stage.size = vtoc->efi_parts[slice].p_size;
1282
1283 device->stage.offset = BBLK_ZFS_BLK_OFF / sector_size;
1284 pl->pl_src_name = stage2;
1285 pl->pl_type = IB_BBLK_STAGE2;
1286 pl->pl_cb.compare = compare_einfo_cb;
1287 pl->pl_cb.install = install_stage2_cb;
1288 pl->pl_cb.read = read_stage2_cb;
1289 pl->pl_cb.read_bbl = read_stage2_file_cb;
1290 pl->pl_cb.print = print_einfo_cb;
1291 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1292 }
1293 rv = true;
1294 done:
1295 efi_free(vtoc);
1296 return (rv);
1297 }
1298
1299 static bool
get_start_sector(ib_data_t * data,struct extpartition * v_part,diskaddr_t * start)1300 get_start_sector(ib_data_t *data, struct extpartition *v_part,
1301 diskaddr_t *start)
1302 {
1303 struct partlist *pl;
1304 struct mboot *mbr;
1305 struct ipart *part;
1306 struct part_info dkpi;
1307 struct extpart_info edkpi;
1308 uint32_t secnum, numsec;
1309 ext_part_t *epp;
1310 ushort_t i;
1311 int fd, rval, pno;
1312
1313 if ((fd = open_device(data->target.path)) < 0)
1314 return (false);
1315
1316 if (ioctl(fd, DKIOCEXTPARTINFO, &edkpi) < 0) {
1317 if (ioctl(fd, DKIOCPARTINFO, &dkpi) < 0) {
1318 (void) fprintf(stderr, gettext("cannot get the "
1319 "slice information of the disk\n"));
1320 (void) close(fd);
1321 return (false);
1322 } else {
1323 edkpi.p_start = dkpi.p_start;
1324 edkpi.p_length = dkpi.p_length;
1325 }
1326 }
1327 (void) close(fd);
1328
1329 /* Set target file system start and size */
1330 data->target.start = edkpi.p_start;
1331 data->target.size = edkpi.p_length;
1332
1333 /* This is our MBR partition start. */
1334 edkpi.p_start -= v_part->p_start;
1335
1336 /* Head is always MBR */
1337 pl = STAILQ_FIRST(data->plist);
1338 if (!read_stage1_cb(pl))
1339 return (false);
1340
1341 mbr = (struct mboot *)pl->pl_stage;
1342 part = (struct ipart *)mbr->parts;
1343
1344 for (i = 0; i < FD_NUMPART; i++) {
1345 if (part[i].relsect == edkpi.p_start) {
1346 *start = part[i].relsect;
1347 return (true);
1348 }
1349 }
1350
1351 rval = libfdisk_init(&epp, pl->pl_devname, part, FDISK_READ_DISK);
1352 if (rval != FDISK_SUCCESS) {
1353 switch (rval) {
1354 /*
1355 * The first 3 cases are not an error per-se, just that
1356 * there is no Solaris logical partition
1357 */
1358 case FDISK_EBADLOGDRIVE:
1359 case FDISK_ENOLOGDRIVE:
1360 case FDISK_EBADMAGIC:
1361 (void) fprintf(stderr, gettext("Solaris "
1362 "partition not found. "
1363 "Aborting operation. %d\n"), rval);
1364 return (false);
1365 case FDISK_ENOVGEOM:
1366 (void) fprintf(stderr, gettext("Could not get "
1367 "virtual geometry\n"));
1368 return (false);
1369 case FDISK_ENOPGEOM:
1370 (void) fprintf(stderr, gettext("Could not get "
1371 "physical geometry\n"));
1372 return (false);
1373 case FDISK_ENOLGEOM:
1374 (void) fprintf(stderr, gettext("Could not get "
1375 "label geometry\n"));
1376 return (false);
1377 default:
1378 (void) fprintf(stderr, gettext("Failed to "
1379 "initialize libfdisk.\n"));
1380 return (false);
1381 }
1382 }
1383 rval = fdisk_get_solaris_part(epp, &pno, &secnum, &numsec);
1384 libfdisk_fini(&epp);
1385 if (rval != FDISK_SUCCESS) {
1386 /* No solaris logical partition */
1387 (void) fprintf(stderr, gettext("Solaris partition not found. "
1388 "Aborting operation.\n"));
1389 return (false);
1390 }
1391 *start = secnum;
1392 return (true);
1393 }
1394
1395 /*
1396 * On x86 the VTOC table is inside MBR partition and to get
1397 * absolute sectors, we need to add MBR partition start to VTOC slice start.
1398 */
1399 static bool
probe_vtoc(ib_data_t * data)1400 probe_vtoc(ib_data_t *data)
1401 {
1402 struct partlist *pl;
1403 struct extvtoc exvtoc;
1404 ib_device_t *device;
1405 char *path, *ptr;
1406 ushort_t i;
1407 int slice, fd;
1408 diskaddr_t start;
1409 bool rv;
1410
1411 rv = false;
1412
1413 if ((fd = open_device(data->target.path)) < 0)
1414 return (rv);
1415
1416 slice = read_extvtoc(fd, &exvtoc);
1417 (void) close(fd);
1418 if (slice < 0)
1419 return (rv);
1420 data->device.devtype = IB_DEV_VTOC;
1421
1422 if (!get_start_sector(data, exvtoc.v_part + slice, &start))
1423 return (rv);
1424
1425 if (exvtoc.v_part[slice].p_tag == V_BACKUP) {
1426 /*
1427 * NOTE: we could relax there and allow zfs boot on
1428 * slice 2, but lets keep traditional limits.
1429 */
1430 (void) fprintf(stderr, gettext(
1431 "raw device must be a root slice (not backup)\n"));
1432 return (rv);
1433 }
1434
1435 if ((path = strdup(data->target.path)) == NULL) {
1436 perror(gettext("Memory allocation failure"));
1437 return (false);
1438 }
1439
1440 data->target.start = start + exvtoc.v_part[slice].p_start;
1441 data->target.size = exvtoc.v_part[slice].p_size;
1442
1443 /* Search for boot slice. */
1444 for (i = 0; i < exvtoc.v_nparts; i++) {
1445 if (exvtoc.v_part[i].p_tag == V_BOOT)
1446 break;
1447 }
1448
1449 if (i == exvtoc.v_nparts ||
1450 exvtoc.v_part[i].p_size == 0) {
1451 /* fall back to slice V_BACKUP */
1452 for (i = 0; i < exvtoc.v_nparts; i++) {
1453 if (exvtoc.v_part[i].p_tag == V_BACKUP)
1454 break;
1455 }
1456 /* Still nothing? Error out. */
1457 if (i == exvtoc.v_nparts ||
1458 exvtoc.v_part[i].p_size == 0) {
1459 free(path);
1460 return (false);
1461 }
1462 }
1463
1464 /* Create path. */
1465 ptr = strrchr(path, 's');
1466 ptr++;
1467 *ptr = '\0';
1468 (void) asprintf(&ptr, "%s%d", path, i);
1469 free(path);
1470 if (ptr == NULL) {
1471 perror(gettext("Memory allocation failure"));
1472 return (false);
1473 }
1474
1475 pl = partlist_alloc();
1476 if (pl == NULL) {
1477 free(ptr);
1478 return (false);
1479 }
1480 pl->pl_devname = ptr;
1481 device = pl->pl_device;
1482 device->stage.devtype = data->device.devtype;
1483 device->stage.id = i;
1484 device->stage.tag = exvtoc.v_part[i].p_tag;
1485 device->stage.start = start + exvtoc.v_part[i].p_start;
1486 device->stage.size = exvtoc.v_part[i].p_size;
1487
1488 /* Fix size if this slice is in fact V_BACKUP */
1489 if (exvtoc.v_part[i].p_tag == V_BACKUP) {
1490 for (i = 0; i < exvtoc.v_nparts; i++) {
1491 if (exvtoc.v_part[i].p_start == 0)
1492 continue;
1493 if (exvtoc.v_part[i].p_size == 0)
1494 continue;
1495 if (exvtoc.v_part[i].p_start <
1496 device->stage.size)
1497 device->stage.size =
1498 exvtoc.v_part[i].p_start;
1499 }
1500 }
1501
1502 pl->pl_src_name = stage1;
1503 pl->pl_type = IB_BBLK_STAGE1;
1504 pl->pl_cb.compare = compare_stage1_cb;
1505 pl->pl_cb.install = install_stage1_cb;
1506 pl->pl_cb.read = read_stage1_cb;
1507 pl->pl_cb.read_bbl = read_stage1_bbl_cb;
1508 pl->pl_cb.print = print_stage1_cb;
1509 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1510
1511 /* Create instance for stage 2 */
1512 pl = partlist_alloc();
1513 if (pl == NULL) {
1514 free(ptr);
1515 return (false);
1516 }
1517 pl->pl_devname = strdup(ptr);
1518 if (pl->pl_devname == NULL) {
1519 partlist_free(pl);
1520 return (false);
1521 }
1522 pl->pl_device->stage.devtype = data->device.devtype;
1523 pl->pl_device->stage.id = device->stage.id;
1524 pl->pl_device->stage.offset = BBLK_BLKLIST_OFF;
1525 pl->pl_device->stage.tag = device->stage.tag;
1526 pl->pl_device->stage.start = device->stage.start;
1527 pl->pl_device->stage.size = device->stage.size;
1528 pl->pl_src_name = stage2;
1529 pl->pl_type = IB_BBLK_STAGE2;
1530 pl->pl_cb.compare = compare_einfo_cb;
1531 pl->pl_cb.install = install_stage2_cb;
1532 pl->pl_cb.read = read_stage2_cb;
1533 pl->pl_cb.read_bbl = read_stage2_file_cb;
1534 pl->pl_cb.print = print_einfo_cb;
1535 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1536
1537 /* And we are done. */
1538 rv = true;
1539 return (rv);
1540 }
1541
1542 static bool
probe_mbr(ib_data_t * data)1543 probe_mbr(ib_data_t *data)
1544 {
1545 struct partlist *pl;
1546 struct ipart *part;
1547 struct mboot *mbr;
1548 ib_device_t *device;
1549 char *path, *ptr;
1550 int i, rv;
1551
1552 data->device.devtype = IB_DEV_MBR;
1553
1554 /* Head is always MBR */
1555 pl = STAILQ_FIRST(data->plist);
1556 if (!read_stage1_cb(pl))
1557 return (false);
1558
1559 mbr = (struct mboot *)pl->pl_stage;
1560 part = (struct ipart *)mbr->parts;
1561
1562 /* Set target file system start and size */
1563 data->target.start = part[data->target.id - 1].relsect;
1564 data->target.size = part[data->target.id - 1].numsect;
1565
1566 /* Use X86BOOT partition if we have one. */
1567 for (i = 0; i < FD_NUMPART; i++) {
1568 if (part[i].systid == X86BOOT)
1569 break;
1570 }
1571
1572 /* Keep device name of whole disk device. */
1573 path = (char *)pl->pl_devname;
1574 if ((pl = partlist_alloc()) == NULL)
1575 return (false);
1576 device = pl->pl_device;
1577
1578 /*
1579 * No X86BOOT, try to use space between MBR and first
1580 * partition.
1581 */
1582 if (i == FD_NUMPART) {
1583 pl->pl_devname = strdup(path);
1584 if (pl->pl_devname == NULL) {
1585 perror(gettext("Memory allocation failure"));
1586 partlist_free(pl);
1587 return (false);
1588 }
1589 device->stage.id = 0;
1590 device->stage.devtype = IB_DEV_MBR;
1591 device->stage.fstype = IB_FS_NONE;
1592 device->stage.start = 0;
1593 device->stage.size = part[0].relsect;
1594 device->stage.offset = BBLK_BLKLIST_OFF;
1595 pl->pl_src_name = stage2;
1596 pl->pl_type = IB_BBLK_STAGE2;
1597 pl->pl_cb.compare = compare_einfo_cb;
1598 pl->pl_cb.install = install_stage2_cb;
1599 pl->pl_cb.read = read_stage2_cb;
1600 pl->pl_cb.read_bbl = read_stage2_file_cb;
1601 pl->pl_cb.print = print_einfo_cb;
1602 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1603
1604 /* We have MBR for stage1 and gap for stage2, we are done. */
1605 return (true);
1606 }
1607
1608 if ((path = strdup(path)) == NULL) {
1609 perror(gettext("Memory allocation failure"));
1610 partlist_free(pl);
1611 return (false);
1612 }
1613 ptr = strrchr(path, 'p');
1614 ptr++;
1615 *ptr = '\0';
1616 /* partitions are p1..p4 */
1617 rv = asprintf(&ptr, "%s%d", path, i + 1);
1618 free(path);
1619 if (rv < 0) {
1620 perror(gettext("Memory allocation failure"));
1621 partlist_free(pl);
1622 return (false);
1623 }
1624 pl->pl_devname = ptr;
1625 device->stage.id = i + 1;
1626 device->stage.devtype = IB_DEV_MBR;
1627 device->stage.fstype = IB_FS_NONE;
1628 device->stage.start = part[i].relsect;
1629 device->stage.size = part[i].numsect;
1630 pl->pl_src_name = stage1;
1631 pl->pl_type = IB_BBLK_STAGE1;
1632 pl->pl_cb.compare = compare_stage1_cb;
1633 pl->pl_cb.install = install_stage1_cb;
1634 pl->pl_cb.read = read_stage1_cb;
1635 pl->pl_cb.read_bbl = read_stage1_bbl_cb;
1636 pl->pl_cb.print = print_stage1_cb;
1637 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1638
1639 pl = partlist_alloc();
1640 if (pl == NULL)
1641 return (false);
1642 device = pl->pl_device;
1643 pl->pl_devname = strdup(ptr);
1644 if (pl->pl_devname == NULL) {
1645 perror(gettext("Memory allocation failure"));
1646 partlist_free(pl);
1647 return (false);
1648 }
1649 device->stage.id = i + 1;
1650 device->stage.devtype = IB_DEV_MBR;
1651 device->stage.fstype = IB_FS_NONE;
1652 device->stage.start = part[i].relsect;
1653 device->stage.size = part[i].numsect;
1654 device->stage.offset = 1;
1655 /* This is boot partition */
1656 device->stage.tag = V_BOOT;
1657 pl->pl_src_name = stage2;
1658 pl->pl_type = IB_BBLK_STAGE2;
1659 pl->pl_cb.compare = compare_einfo_cb;
1660 pl->pl_cb.install = install_stage2_cb;
1661 pl->pl_cb.read = read_stage2_cb;
1662 pl->pl_cb.read_bbl = read_stage2_file_cb;
1663 pl->pl_cb.print = print_einfo_cb;
1664 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1665
1666 return (true);
1667 }
1668
1669 static bool
probe_device(ib_data_t * data,const char * dev)1670 probe_device(ib_data_t *data, const char *dev)
1671 {
1672 struct partlist *pl;
1673 struct stat sb;
1674 const char *ptr;
1675 char *p0;
1676 int fd, len;
1677
1678 if (dev == NULL)
1679 return (NULL);
1680
1681 len = strlen(dev);
1682
1683 if ((pl = partlist_alloc()) == NULL)
1684 return (false);
1685
1686 if (stat(dev, &sb) == -1) {
1687 perror("stat");
1688 partlist_free(pl);
1689 return (false);
1690 }
1691
1692 /* We have regular file, register it and we are done. */
1693 if (S_ISREG(sb.st_mode) != 0) {
1694 pl->pl_devname = (char *)dev;
1695
1696 pl->pl_type = IB_BBLK_FILE;
1697 pl->pl_cb.read = read_einfo_file_cb;
1698 pl->pl_cb.print = print_einfo_cb;
1699 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1700 return (true);
1701 }
1702
1703 /*
1704 * This is block device.
1705 * We do not allow to specify whole disk device (cXtYdZp0 or cXtYdZ).
1706 */
1707 if ((ptr = strrchr(dev, '/')) == NULL)
1708 ptr = dev;
1709 if ((strrchr(ptr, 'p') == NULL && strrchr(ptr, 's') == NULL) ||
1710 (dev[len - 2] == 'p' && dev[len - 1] == '0')) {
1711 (void) fprintf(stderr,
1712 gettext("whole disk device is not supported\n"));
1713 partlist_free(pl);
1714 return (false);
1715 }
1716
1717 data->target.path = (char *)dev;
1718 if (!probe_fstyp(data)) {
1719 partlist_free(pl);
1720 return (false);
1721 }
1722
1723 /* We start from identifying the whole disk. */
1724 if ((p0 = strdup(dev)) == NULL) {
1725 perror("calloc");
1726 partlist_free(pl);
1727 return (false);
1728 }
1729
1730 pl->pl_devname = p0;
1731 /* Change device name to p0 */
1732 if ((ptr = strrchr(p0, 'p')) == NULL)
1733 ptr = strrchr(p0, 's');
1734 p0 = (char *)ptr;
1735 p0[0] = 'p';
1736 p0[1] = '0';
1737 p0[2] = '\0';
1738
1739 if ((fd = open_device(pl->pl_devname)) == -1) {
1740 partlist_free(pl);
1741 return (false);
1742 }
1743
1744 sector_size = get_media_info(fd);
1745 (void) close(fd);
1746
1747 pl->pl_src_name = stage1;
1748 pl->pl_type = IB_BBLK_MBR;
1749 pl->pl_cb.compare = compare_mbr_cb;
1750 pl->pl_cb.install = install_stage1_cb;
1751 pl->pl_cb.read = read_stage1_cb;
1752 pl->pl_cb.read_bbl = read_stage1_bbl_cb;
1753 pl->pl_cb.print = print_stage1_cb;
1754 STAILQ_INSERT_TAIL(data->plist, pl, pl_next);
1755
1756 if (probe_gpt(data))
1757 return (true);
1758
1759 /*
1760 * We only do support sector size 512 with MBR and VTOC.
1761 * The 4kn sector size with actual hardware is currently
1762 * available with large disks and MBR/VTOC are not usable
1763 * with such devices.
1764 */
1765 if (sector_size != SECTOR_SIZE)
1766 return (false);
1767
1768 if (data->device.devtype == IB_DEV_UNKNOWN)
1769 if (probe_vtoc(data))
1770 return (true);
1771
1772 if (data->device.devtype == IB_DEV_UNKNOWN)
1773 return (probe_mbr(data));
1774
1775 return (false);
1776 }
1777
1778 static int
read_bootblock_from_file(const char * file,ib_bootblock_t * bblock)1779 read_bootblock_from_file(const char *file, ib_bootblock_t *bblock)
1780 {
1781 struct stat sb;
1782 uint32_t buf_size;
1783 uint32_t mboot_off;
1784 int fd = -1;
1785 int retval = BC_ERROR;
1786
1787 assert(bblock != NULL);
1788 assert(file != NULL);
1789
1790 fd = open(file, O_RDONLY);
1791 if (fd == -1) {
1792 BOOT_DEBUG("Error opening %s\n", file);
1793 goto out;
1794 }
1795
1796 if (fstat(fd, &sb) == -1) {
1797 BOOT_DEBUG("Error getting information (stat) about %s", file);
1798 perror("stat");
1799 goto outfd;
1800 }
1801
1802 /* loader bootblock has version built in */
1803 buf_size = sb.st_size;
1804 if (buf_size == 0)
1805 goto outfd;
1806
1807 /* Round up to sector size for raw disk write */
1808 bblock->buf_size = P2ROUNDUP(buf_size, sector_size);
1809 BOOT_DEBUG("bootblock in-memory buffer size is %d\n",
1810 bblock->buf_size);
1811
1812 bblock->buf = malloc(bblock->buf_size);
1813 if (bblock->buf == NULL) {
1814 perror(gettext("Memory allocation failure"));
1815 goto outbuf;
1816 }
1817 bblock->file = bblock->buf;
1818
1819 if (read(fd, bblock->file, buf_size) != buf_size) {
1820 BOOT_DEBUG("Read from %s failed\n", file);
1821 perror("read");
1822 goto outfd;
1823 }
1824
1825 buf_size = MIN(buf_size, MBOOT_SCAN_SIZE);
1826 if (find_multiboot(bblock->file, buf_size, &mboot_off)
1827 != BC_SUCCESS) {
1828 (void) fprintf(stderr,
1829 gettext("Unable to find multiboot header\n"));
1830 goto outfd;
1831 }
1832
1833 bblock->mboot = (multiboot_header_t *)(bblock->file + mboot_off);
1834 bblock->mboot_off = mboot_off;
1835
1836 bblock->file_size =
1837 bblock->mboot->load_end_addr - bblock->mboot->load_addr;
1838 BOOT_DEBUG("bootblock file size is %d\n", bblock->file_size);
1839
1840 bblock->extra = bblock->buf + P2ROUNDUP(bblock->file_size, 8);
1841 bblock->extra_size = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8);
1842
1843 BOOT_DEBUG("mboot at %p offset %d, extra at %p size %d, buf=%p "
1844 "(size=%d)\n", bblock->mboot, bblock->mboot_off, bblock->extra,
1845 bblock->extra_size, bblock->buf, bblock->buf_size);
1846
1847 (void) close(fd);
1848 return (BC_SUCCESS);
1849
1850 outbuf:
1851 (void) free(bblock->buf);
1852 bblock->buf = NULL;
1853 outfd:
1854 (void) close(fd);
1855 out:
1856 if (retval == BC_ERROR) {
1857 (void) fprintf(stderr,
1858 gettext("Error reading bootblock from %s\n"),
1859 file);
1860 }
1861
1862 if (retval == BC_NOEXTRA) {
1863 BOOT_DEBUG("No multiboot header found on %s, unable to "
1864 "locate extra information area (old/non versioned "
1865 "bootblock?) \n", file);
1866 (void) fprintf(stderr, gettext("No extended information"
1867 " found\n"));
1868 }
1869 return (retval);
1870 }
1871
1872 static void
add_bootblock_einfo(ib_bootblock_t * bblock,char * updt_str)1873 add_bootblock_einfo(ib_bootblock_t *bblock, char *updt_str)
1874 {
1875 bblk_hs_t hs;
1876 uint32_t avail_space;
1877
1878 assert(bblock != NULL);
1879
1880 if (updt_str == NULL) {
1881 BOOT_DEBUG("WARNING: no update string passed to "
1882 "add_bootblock_einfo()\n");
1883 return;
1884 }
1885
1886 /* Fill bootblock hashing source information. */
1887 hs.src_buf = (unsigned char *)bblock->file;
1888 hs.src_size = bblock->file_size;
1889 /* How much space for the extended information structure? */
1890 avail_space = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8);
1891 /* Place the extended information structure. */
1892 add_einfo(bblock->extra, updt_str, &hs, avail_space);
1893 }
1894
1895 /*
1896 * set up data for case stage1 is installed as MBR
1897 * set up location and size of bootblock
1898 * set disk guid to provide unique information for biosdev command
1899 */
1900 static void
prepare_stage1(struct partlist * stage1,struct partlist * stage2,uuid_t uuid)1901 prepare_stage1(struct partlist *stage1, struct partlist *stage2, uuid_t uuid)
1902 {
1903 char *src, *dest;
1904 ib_bootblock_t *bblk;
1905 ib_device_t *device;
1906 uint16_t size;
1907 struct mboot *mbr;
1908
1909 src = stage1->pl_stage;
1910 dest = stage1->pl_src_data;
1911 device = stage2->pl_device;
1912
1913 /* Only copy from valid source. */
1914 mbr = stage1->pl_stage;
1915 if (mbr->signature == MBB_MAGIC) {
1916 /* copy BPB */
1917 bcopy(src + STAGE1_BPB_OFFSET, dest + STAGE1_BPB_OFFSET,
1918 STAGE1_BPB_SIZE);
1919
1920 /* copy MBR, note STAGE1_SIG == BOOTSZ */
1921 bcopy(src + STAGE1_SIG, dest + STAGE1_SIG,
1922 SECTOR_SIZE - STAGE1_SIG);
1923 }
1924
1925 bcopy(uuid, dest + STAGE1_STAGE2_UUID, UUID_LEN);
1926
1927 /* store bytes per sector */
1928 *((uint16_t *)(dest + STAGE1_BPB_BPS)) = sector_size;
1929 /* set stage2 size */
1930 bblk = stage2->pl_src_data;
1931 size = bblk->buf_size / sector_size;
1932 *((uint16_t *)(dest + STAGE1_STAGE2_SIZE)) = size;
1933
1934 /* set stage2 LBA */
1935 *((uint64_t *)(dest + STAGE1_STAGE2_LBA)) =
1936 device->stage.start + device->stage.offset;
1937
1938 /* Copy prepared data to stage1 block read from the disk. */
1939 bcopy(dest, src, SECTOR_SIZE);
1940 }
1941
1942 static void
prepare_bootblock(ib_data_t * data,struct partlist * pl,char * updt_str)1943 prepare_bootblock(ib_data_t *data, struct partlist *pl, char *updt_str)
1944 {
1945 ib_bootblock_t *bblock;
1946 uint64_t *ptr;
1947
1948 assert(pl != NULL);
1949
1950 bblock = pl->pl_src_data;
1951 if (bblock == NULL)
1952 return;
1953
1954 ptr = (uint64_t *)(&bblock->mboot->bss_end_addr);
1955 *ptr = data->target.start;
1956
1957 /*
1958 * the loader bootblock has built in version, if custom
1959 * version was provided, update it.
1960 */
1961 if (do_version)
1962 add_bootblock_einfo(bblock, updt_str);
1963 }
1964
1965 static int
open_device(const char * path)1966 open_device(const char *path)
1967 {
1968 struct stat statbuf = {0};
1969 int fd = -1;
1970
1971 if (nowrite)
1972 fd = open(path, O_RDONLY);
1973 else
1974 fd = open(path, O_RDWR);
1975
1976 if (fd == -1) {
1977 BOOT_DEBUG("Unable to open %s\n", path);
1978 perror("open");
1979 return (-1);
1980 }
1981
1982 if (fstat(fd, &statbuf) != 0) {
1983 BOOT_DEBUG("Unable to stat %s\n", path);
1984 perror("stat");
1985 (void) close(fd);
1986 return (-1);
1987 }
1988
1989 if (S_ISCHR(statbuf.st_mode) == 0) {
1990 (void) fprintf(stderr, gettext("%s: Not a character device\n"),
1991 path);
1992 (void) close(fd);
1993 return (-1);
1994 }
1995
1996 return (fd);
1997 }
1998
1999 /*
2000 * We need to record stage2 location and size into pmbr/vbr.
2001 * We need to record target partiton LBA to stage2.
2002 */
2003 static void
prepare_bblocks(ib_data_t * data)2004 prepare_bblocks(ib_data_t *data)
2005 {
2006 struct partlist *pl;
2007 struct partlist *mbr, *stage1, *stage2;
2008 uuid_t uuid;
2009
2010 /*
2011 * Create disk uuid. We only need reasonable amount of uniqueness
2012 * to allow biosdev to identify disk based on mbr differences.
2013 */
2014 uuid_generate(uuid);
2015
2016 mbr = stage1 = stage2 = NULL;
2017
2018 /* First find stage 2. */
2019 STAILQ_FOREACH(pl, data->plist, pl_next) {
2020 if (pl->pl_type == IB_BBLK_STAGE2) {
2021 stage2 = pl;
2022
2023 /*
2024 * When stage2 needs update, make sure we also
2025 * update stage1.
2026 */
2027 if (pl->pl_cb.compare != NULL &&
2028 pl->pl_cb.compare(pl))
2029 write_vbr = true;
2030 break;
2031 }
2032 }
2033 /*
2034 * Walk list and pick up BIOS boot blocks. EFI boot programs
2035 * can be set in place.
2036 */
2037 STAILQ_FOREACH(pl, data->plist, pl_next) {
2038 switch (pl->pl_type) {
2039 case IB_BBLK_MBR:
2040 mbr = pl;
2041 break;
2042 case IB_BBLK_STAGE1:
2043 stage1 = pl;
2044 if (stage2 != NULL)
2045 prepare_stage1(stage1, stage2, uuid);
2046 break;
2047 case IB_BBLK_STAGE2:
2048 case IB_BBLK_EFI:
2049 prepare_bootblock(data, pl, update_str);
2050 break;
2051 default:
2052 break;
2053 }
2054 }
2055
2056 /* If stage2 is missing, we are done. */
2057 if (stage2 == NULL)
2058 return;
2059
2060 if (mbr != NULL) {
2061 prepare_stage1(mbr, stage2, uuid);
2062
2063 /*
2064 * If we have stage1, we point MBR to read stage 1.
2065 */
2066 if (stage1 != NULL) {
2067 char *dest = mbr->pl_stage;
2068
2069 *((uint16_t *)(dest + STAGE1_STAGE2_SIZE)) = 1;
2070 *((uint64_t *)(dest + STAGE1_STAGE2_LBA)) =
2071 stage1->pl_device->stage.start;
2072 }
2073 }
2074 }
2075
2076 /*
2077 * Install a new bootblock on the given device. handle_install() expects argv
2078 * to contain 3 parameters (the target device path and the path to the
2079 * bootblock.
2080 *
2081 * Returns: BC_SUCCESS - if the installation is successful
2082 * BC_ERROR - if the installation failed
2083 * BC_NOUPDT - if no installation was performed because the
2084 * version currently installed is more recent than the
2085 * supplied one.
2086 *
2087 */
2088 static int
handle_install(char * progname,int argc,char ** argv)2089 handle_install(char *progname, int argc, char **argv)
2090 {
2091 struct partlist *pl;
2092 ib_data_t data = { 0 };
2093 char *device_path = NULL;
2094 int ret = BC_ERROR;
2095
2096 switch (argc) {
2097 case 1:
2098 if ((device_path = strdup(argv[0])) == NULL) {
2099 perror(gettext("Memory Allocation Failure"));
2100 goto done;
2101 }
2102 if (asprintf(&stage1, "%s/%s", boot_dir, STAGE1) < 0) {
2103 perror(gettext("Memory Allocation Failure"));
2104 goto done;
2105 }
2106 if (asprintf(&stage2, "%s/%s", boot_dir, STAGE2) < 0) {
2107 perror(gettext("Memory Allocation Failure"));
2108 goto done;
2109 }
2110 if (asprintf(&efi32, "%s/%s", boot_dir, LOADER32) < 0) {
2111 perror(gettext("Memory Allocation Failure"));
2112 goto done;
2113 }
2114 if (asprintf(&efi64, "%s/%s", boot_dir, LOADER64) < 0) {
2115 perror(gettext("Memory Allocation Failure"));
2116 goto done;
2117 }
2118 break;
2119 case 3:
2120 if ((stage1 = strdup(argv[0])) == NULL) {
2121 perror(gettext("Memory Allocation Failure"));
2122 goto done;
2123 }
2124 if ((stage2 = strdup(argv[1])) == NULL) {
2125 perror(gettext("Memory Allocation Failure"));
2126 goto done;
2127 }
2128 if ((device_path = strdup(argv[2])) == NULL) {
2129 perror(gettext("Memory Allocation Failure"));
2130 goto done;
2131 }
2132 if (asprintf(&efi32, "%s/%s", boot_dir, LOADER32) < 0) {
2133 perror(gettext("Memory Allocation Failure"));
2134 goto done;
2135 }
2136 if (asprintf(&efi64, "%s/%s", boot_dir, LOADER64) < 0) {
2137 perror(gettext("Memory Allocation Failure"));
2138 goto done;
2139 }
2140 break;
2141 default:
2142 usage(progname, ret);
2143 }
2144
2145 data.plist = malloc(sizeof (*data.plist));
2146 if (data.plist == NULL) {
2147 perror(gettext("Memory Allocation Failure"));
2148 goto done;
2149 }
2150 STAILQ_INIT(data.plist);
2151
2152 BOOT_DEBUG("device path: %s, stage1 path: %s bootblock path: %s\n",
2153 device_path, stage1, stage2);
2154
2155 if (probe_device(&data, device_path)) {
2156 /* Read all data. */
2157 STAILQ_FOREACH(pl, data.plist, pl_next) {
2158 if (!pl->pl_cb.read(pl)) {
2159 printf("\n");
2160 }
2161 if (!pl->pl_cb.read_bbl(pl)) {
2162 /*
2163 * We will ignore ESP updates in case of
2164 * older system where we are missing
2165 * loader64.efi and loader32.efi.
2166 */
2167 if (pl->pl_type != IB_BBLK_EFI)
2168 goto cleanup;
2169 }
2170 }
2171
2172 /* Prepare data. */
2173 prepare_bblocks(&data);
2174
2175 /* Commit data to disk. */
2176 while ((pl = STAILQ_LAST(data.plist, partlist, pl_next)) !=
2177 NULL) {
2178 if (pl->pl_cb.compare != NULL &&
2179 pl->pl_cb.compare(pl)) {
2180 if (pl->pl_cb.install != NULL)
2181 pl->pl_cb.install(&data, pl);
2182 }
2183 STAILQ_REMOVE(data.plist, pl, partlist, pl_next);
2184 partlist_free(pl);
2185 }
2186 }
2187 ret = BC_SUCCESS;
2188
2189 cleanup:
2190 while ((pl = STAILQ_LAST(data.plist, partlist, pl_next)) != NULL) {
2191 STAILQ_REMOVE(data.plist, pl, partlist, pl_next);
2192 partlist_free(pl);
2193 }
2194 free(data.plist);
2195 done:
2196 free(stage1);
2197 free(stage2);
2198 free(efi32);
2199 free(efi64);
2200 free(device_path);
2201 return (ret);
2202 }
2203
2204 /*
2205 * Retrieves from a device the extended information (einfo) associated to the
2206 * file or installed stage2.
2207 * Expects one parameter, the device path, in the form: /dev/rdsk/c?[t?]d?s0
2208 * or file name.
2209 * Returns:
2210 * - BC_SUCCESS (and prints out einfo contents depending on 'flags')
2211 * - BC_ERROR (on error)
2212 * - BC_NOEINFO (no extended information available)
2213 */
2214 static int
handle_getinfo(char * progname,int argc,char ** argv)2215 handle_getinfo(char *progname, int argc, char **argv)
2216 {
2217 struct partlist *pl;
2218 ib_data_t data = { 0 };
2219 char *device_path;
2220
2221 if (argc != 1) {
2222 (void) fprintf(stderr, gettext("Missing parameter"));
2223 usage(progname, BC_ERROR);
2224 }
2225
2226 if ((device_path = strdup(argv[0])) == NULL) {
2227 perror(gettext("Memory Allocation Failure"));
2228 return (BC_ERROR);
2229 }
2230
2231 data.plist = malloc(sizeof (*data.plist));
2232 if (data.plist == NULL) {
2233 perror("malloc");
2234 free(device_path);
2235 return (BC_ERROR);
2236 }
2237 STAILQ_INIT(data.plist);
2238
2239 if (probe_device(&data, device_path)) {
2240 STAILQ_FOREACH(pl, data.plist, pl_next) {
2241 if (pl->pl_cb.read(pl))
2242 pl->pl_cb.print(pl);
2243 else
2244 printf("\n");
2245 }
2246 }
2247
2248 while ((pl = STAILQ_LAST(data.plist, partlist, pl_next)) != NULL) {
2249 STAILQ_REMOVE(data.plist, pl, partlist, pl_next);
2250 partlist_free(pl);
2251 }
2252 free(data.plist);
2253
2254 return (BC_SUCCESS);
2255 }
2256
2257 /*
2258 * Attempt to mirror (propagate) the current bootblock over the attaching disk.
2259 *
2260 * Returns:
2261 * - BC_SUCCESS (a successful propagation happened)
2262 * - BC_ERROR (an error occurred)
2263 * - BC_NOEXTRA (it is not possible to dump the current bootblock since
2264 * there is no multiboot information)
2265 */
2266 static int
handle_mirror(char * progname,int argc,char ** argv)2267 handle_mirror(char *progname, int argc, char **argv)
2268 {
2269 ib_data_t src = { 0 };
2270 ib_data_t dest = { 0 };
2271 struct partlist *pl_src, *pl_dest;
2272 char *curr_device_path = NULL;
2273 char *attach_device_path = NULL;
2274 int retval = BC_ERROR;
2275
2276 if (argc == 2) {
2277 curr_device_path = strdup(argv[0]);
2278 attach_device_path = strdup(argv[1]);
2279 }
2280
2281 if (!curr_device_path || !attach_device_path) {
2282 free(curr_device_path);
2283 free(attach_device_path);
2284 (void) fprintf(stderr, gettext("Missing parameter"));
2285 usage(progname, BC_ERROR);
2286 }
2287 BOOT_DEBUG("Current device path is: %s, attaching device path is: "
2288 " %s\n", curr_device_path, attach_device_path);
2289
2290 src.plist = malloc(sizeof (*src.plist));
2291 if (src.plist == NULL) {
2292 perror("malloc");
2293 return (BC_ERROR);
2294 }
2295 STAILQ_INIT(src.plist);
2296
2297 dest.plist = malloc(sizeof (*dest.plist));
2298 if (dest.plist == NULL) {
2299 perror("malloc");
2300 goto out;
2301 }
2302 STAILQ_INIT(dest.plist);
2303
2304 if (!probe_device(&src, curr_device_path)) {
2305 (void) fprintf(stderr, gettext("Unable to gather device "
2306 "information from %s (current device)\n"),
2307 curr_device_path);
2308 goto out;
2309 }
2310
2311 if (!probe_device(&dest, attach_device_path) != BC_SUCCESS) {
2312 (void) fprintf(stderr, gettext("Unable to gather device "
2313 "information from %s (attaching device)\n"),
2314 attach_device_path);
2315 goto cleanup_src;
2316 }
2317
2318 write_vbr = true;
2319 write_mbr = true;
2320 force_mbr = true;
2321
2322 pl_dest = STAILQ_FIRST(dest.plist);
2323 STAILQ_FOREACH(pl_src, src.plist, pl_next) {
2324 if (pl_dest == NULL) {
2325 (void) fprintf(stderr,
2326 gettext("Destination disk layout is different "
2327 "from source, can not mirror.\n"));
2328 goto cleanup;
2329 }
2330 if (!pl_src->pl_cb.read(pl_src)) {
2331 (void) fprintf(stderr, gettext("Failed to read "
2332 "boot block from %s\n"), pl_src->pl_devname);
2333 goto cleanup;
2334 }
2335 if (!pl_dest->pl_cb.read(pl_dest)) {
2336 (void) fprintf(stderr, gettext("Failed to read "
2337 "boot block from %s\n"), pl_dest->pl_devname);
2338 }
2339
2340 /* Set source pl_stage to destination source data */
2341 pl_dest->pl_src_data = pl_src->pl_stage;
2342 pl_src->pl_stage = NULL;
2343
2344 pl_dest = STAILQ_NEXT(pl_dest, pl_next);
2345 }
2346
2347 /* Prepare data. */
2348 prepare_bblocks(&dest);
2349
2350 /* Commit data to disk. */
2351 while ((pl_dest = STAILQ_LAST(dest.plist, partlist, pl_next)) != NULL) {
2352 pl_dest->pl_cb.install(&dest, pl_dest);
2353 STAILQ_REMOVE(dest.plist, pl_dest, partlist, pl_next);
2354 partlist_free(pl_dest);
2355
2356 /* Free source list */
2357 pl_src = STAILQ_LAST(src.plist, partlist, pl_next);
2358 if (pl_src != NULL) {
2359 STAILQ_REMOVE(src.plist, pl_src, partlist, pl_next);
2360 partlist_free(pl_src);
2361 }
2362 }
2363 retval = BC_SUCCESS;
2364
2365 cleanup:
2366 while ((pl_dest = STAILQ_LAST(dest.plist, partlist, pl_next)) != NULL) {
2367 STAILQ_REMOVE(dest.plist, pl_dest, partlist, pl_next);
2368 partlist_free(pl_dest);
2369 }
2370 free(dest.plist);
2371 cleanup_src:
2372 while ((pl_src = STAILQ_LAST(src.plist, partlist, pl_next)) != NULL) {
2373 STAILQ_REMOVE(src.plist, pl_src, partlist, pl_next);
2374 partlist_free(pl_src);
2375 }
2376 free(src.plist);
2377 out:
2378 free(curr_device_path);
2379 free(attach_device_path);
2380 return (retval);
2381 }
2382
2383 #define USAGE_STRING \
2384 "Usage:\t%s [-fFmn] [-b boot_dir] [-u verstr]\n" \
2385 "\t\t[stage1 stage2] raw-device\n" \
2386 "\t%s -M [-n] raw-device attach-raw-device\n" \
2387 "\t%s [-e|-V] -i raw-device | file\n"
2388
2389 #define CANON_USAGE_STR gettext(USAGE_STRING)
2390
2391 static void
usage(char * progname,int rc)2392 usage(char *progname, int rc)
2393 {
2394 (void) fprintf(stdout, CANON_USAGE_STR, progname, progname, progname);
2395 fini_yes();
2396 exit(rc);
2397 }
2398
2399 int
main(int argc,char ** argv)2400 main(int argc, char **argv)
2401 {
2402 int opt;
2403 int ret;
2404 char *progname;
2405 struct stat sb;
2406
2407 (void) setlocale(LC_ALL, "");
2408 (void) textdomain(TEXT_DOMAIN);
2409 if (init_yes() < 0)
2410 errx(BC_ERROR, gettext(ERR_MSG_INIT_YES), strerror(errno));
2411
2412 /* Needed for mount pcfs. */
2413 tzset();
2414
2415 /* Determine our name */
2416 progname = basename(argv[0]);
2417
2418 while ((opt = getopt(argc, argv, "b:deFfhiMmnu:V")) != EOF) {
2419 switch (opt) {
2420 case 'b':
2421 boot_dir = strdup(optarg);
2422 if (boot_dir == NULL) {
2423 err(BC_ERROR,
2424 gettext("Memory allocation failure"));
2425 }
2426 if (lstat(boot_dir, &sb) != 0) {
2427 err(BC_ERROR, boot_dir);
2428 }
2429 if (!S_ISDIR(sb.st_mode)) {
2430 errx(BC_ERROR, gettext("%s: not a directory"),
2431 boot_dir);
2432 }
2433 break;
2434 case 'd':
2435 boot_debug = true;
2436 break;
2437 case 'e':
2438 strip = true;
2439 break;
2440 case 'F':
2441 force_update = true;
2442 break;
2443 case 'f':
2444 force_mbr = true;
2445 break;
2446 case 'h':
2447 usage(progname, BC_SUCCESS);
2448 break;
2449 case 'i':
2450 do_getinfo = true;
2451 break;
2452 case 'M':
2453 do_mirror_bblk = true;
2454 break;
2455 case 'm':
2456 write_mbr = true;
2457 break;
2458 case 'n':
2459 nowrite = true;
2460 break;
2461 case 'u':
2462 do_version = true;
2463
2464 update_str = strdup(optarg);
2465 if (update_str == NULL) {
2466 perror(gettext("Memory allocation failure"));
2467 exit(BC_ERROR);
2468 }
2469 break;
2470 case 'V':
2471 verbose_dump = true;
2472 break;
2473 default:
2474 /* fall through to process non-optional args */
2475 break;
2476 }
2477 }
2478
2479 /* check arguments */
2480 check_options(progname);
2481
2482 if (nowrite)
2483 (void) fprintf(stdout, gettext("Dry run requested. Nothing will"
2484 " be written to disk.\n"));
2485
2486 if (do_getinfo) {
2487 ret = handle_getinfo(progname, argc - optind, argv + optind);
2488 } else if (do_mirror_bblk) {
2489 ret = handle_mirror(progname, argc - optind, argv + optind);
2490 } else {
2491 ret = handle_install(progname, argc - optind, argv + optind);
2492 }
2493 fini_yes();
2494 return (ret);
2495 }
2496
2497 #define MEANINGLESS_OPT gettext("%s specified but meaningless, ignoring\n")
2498 static void
check_options(char * progname)2499 check_options(char *progname)
2500 {
2501 if (do_getinfo && do_mirror_bblk) {
2502 (void) fprintf(stderr, gettext("Only one of -M and -i can be "
2503 "specified at the same time\n"));
2504 usage(progname, BC_ERROR);
2505 }
2506
2507 if (do_mirror_bblk) {
2508 /*
2509 * -u and -F may actually reflect a user intent that is not
2510 * correct with this command (mirror can be interpreted
2511 * "similar" to install. Emit a message and continue.
2512 * -e and -V have no meaning, be quiet here and only report the
2513 * incongruence if a debug output is requested.
2514 */
2515 if (do_version) {
2516 (void) fprintf(stderr, MEANINGLESS_OPT, "-u");
2517 do_version = false;
2518 }
2519 if (force_update) {
2520 (void) fprintf(stderr, MEANINGLESS_OPT, "-F");
2521 force_update = false;
2522 }
2523 if (strip || verbose_dump) {
2524 BOOT_DEBUG(MEANINGLESS_OPT, "-e|-V");
2525 strip = false;
2526 verbose_dump = false;
2527 }
2528 }
2529
2530 if ((strip || verbose_dump) && !do_getinfo)
2531 usage(progname, BC_ERROR);
2532
2533 if (do_getinfo) {
2534 if (write_mbr || force_mbr || do_version || force_update) {
2535 BOOT_DEBUG(MEANINGLESS_OPT, "-m|-f|-u|-F");
2536 write_mbr = force_mbr = do_version = false;
2537 force_update = false;
2538 }
2539 }
2540 }
2541