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