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