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