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