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