10c946d80SToomas Soome /*
20c946d80SToomas Soome  * CDDL HEADER START
30c946d80SToomas Soome  *
40c946d80SToomas Soome  * The contents of this file are subject to the terms of the
50c946d80SToomas Soome  * Common Development and Distribution License (the "License").
60c946d80SToomas Soome  * You may not use this file except in compliance with the License.
70c946d80SToomas Soome  *
80c946d80SToomas Soome  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90c946d80SToomas Soome  * or http://www.opensolaris.org/os/licensing.
100c946d80SToomas Soome  * See the License for the specific language governing permissions
110c946d80SToomas Soome  * and limitations under the License.
120c946d80SToomas Soome  *
130c946d80SToomas Soome  * When distributing Covered Code, include this CDDL HEADER in each
140c946d80SToomas Soome  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150c946d80SToomas Soome  * If applicable, add the following below this CDDL HEADER, with the
160c946d80SToomas Soome  * fields enclosed by brackets "[]" replaced with your own identifying
170c946d80SToomas Soome  * information: Portions Copyright [yyyy] [name of copyright owner]
180c946d80SToomas Soome  *
190c946d80SToomas Soome  * CDDL HEADER END
200c946d80SToomas Soome  */
210c946d80SToomas Soome /*
220c946d80SToomas Soome  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
230c946d80SToomas Soome  * Copyright 2012 Nexenta Systems, Inc. All rights reserved.
24d7802caeSToomas Soome  * Copyright 2019 Toomas Soome <tsoome@me.com>
250c946d80SToomas Soome  */
260c946d80SToomas Soome 
270c946d80SToomas Soome #include <stdio.h>
28d7802caeSToomas Soome #include <stdbool.h>
290c946d80SToomas Soome #include <errno.h>
300c946d80SToomas Soome #include <unistd.h>
310c946d80SToomas Soome #include <fcntl.h>
320c946d80SToomas Soome #include <assert.h>
330c946d80SToomas Soome #include <locale.h>
340c946d80SToomas Soome #include <strings.h>
350c946d80SToomas Soome #include <libfdisk.h>
36bdecfb1eSToomas Soome #include <err.h>
37d7802caeSToomas Soome #include <time.h>
38d7802caeSToomas Soome #include <spawn.h>
390c946d80SToomas Soome 
400c946d80SToomas Soome #include <sys/dktp/fdisk.h>
410c946d80SToomas Soome #include <sys/dkio.h>
420c946d80SToomas Soome #include <sys/vtoc.h>
430c946d80SToomas Soome #include <sys/multiboot.h>
440c946d80SToomas Soome #include <sys/types.h>
450c946d80SToomas Soome #include <sys/stat.h>
460c946d80SToomas Soome #include <sys/sysmacros.h>
470c946d80SToomas Soome #include <sys/efi_partition.h>
48d7802caeSToomas Soome #include <sys/queue.h>
49d7802caeSToomas Soome #include <sys/mount.h>
50d7802caeSToomas Soome #include <sys/mntent.h>
51d7802caeSToomas Soome #include <sys/mnttab.h>
52d7802caeSToomas Soome #include <sys/wait.h>
530c946d80SToomas Soome #include <libfstyp.h>
54bdecfb1eSToomas Soome #include <libgen.h>
550c946d80SToomas Soome #include <uuid/uuid.h>
560c946d80SToomas Soome 
570c946d80SToomas Soome #include "installboot.h"
58bdecfb1eSToomas Soome #include "bblk_einfo.h"
59bdecfb1eSToomas Soome #include "boot_utils.h"
60bdecfb1eSToomas Soome #include "mboot_extra.h"
610c946d80SToomas Soome #include "getresponse.h"
620c946d80SToomas Soome 
630c946d80SToomas Soome #ifndef	TEXT_DOMAIN
640c946d80SToomas Soome #define	TEXT_DOMAIN	"SUNW_OST_OSCMD"
650c946d80SToomas Soome #endif
660c946d80SToomas Soome 
670c946d80SToomas Soome /*
680c946d80SToomas Soome  * BIOS bootblock installation:
690c946d80SToomas Soome  *
700c946d80SToomas Soome  * 1. MBR is first sector of the disk. If the file system on target is
710c946d80SToomas Soome  *    ufs or zfs, the same MBR code is installed on first sector of the
720c946d80SToomas Soome  *    partition as well; this will allow to have real MBR sector to be
730c946d80SToomas Soome  *    replaced by some other boot loader and have illumos chainloaded.
740c946d80SToomas Soome  *
750c946d80SToomas Soome  * installboot will record the start LBA and size of stage2 code in MBR code.
760c946d80SToomas Soome  * On boot, the MBR code will read the stage2 code and executes it.
770c946d80SToomas Soome  *
780c946d80SToomas Soome  * 2. Stage2 location depends on file system type;
790c946d80SToomas Soome  *    In case of zfs, installboot will store stage2 to zfs bootblk area,
800c946d80SToomas Soome  *    which is 512k bytes from partition start and size is 3.5MB.
810c946d80SToomas Soome  *
820c946d80SToomas Soome  *    In case of ufs, the stage2 location is 50 512B sectors from
830c946d80SToomas Soome  *    Solaris2 MBR partition start, within boot slice, boot slice size is
840c946d80SToomas Soome  *    one cylinder.
850c946d80SToomas Soome  *
860c946d80SToomas Soome  *    In case of pcfs, the stage2 location is 50 512B sectors from beginning
870c946d80SToomas Soome  *    of the disk, filling the space between MBR and first partition.
880c946d80SToomas Soome  *    This location assumes no other bootloader and the space is one cylinder,
890c946d80SToomas Soome  *    as first partition is starting from cylinder 1.
900c946d80SToomas Soome  *
910c946d80SToomas Soome  *    In case of GPT partitioning and if file system is not zfs, the boot
920c946d80SToomas Soome  *    support is only possible with dedicated boot partition. For GPT,
930c946d80SToomas Soome  *    the current implementation is using BOOT partition, which must exist.
940c946d80SToomas Soome  *    BOOT partition does only contain raw boot blocks, without any file system.
950c946d80SToomas Soome  *
960c946d80SToomas Soome  * Loader stage2 is created with embedded version, by using fake multiboot (MB)
970c946d80SToomas Soome  * header within first 32k and EINFO block is at the end of the actual
980c946d80SToomas Soome  * boot block. MB header load_addr is set to 0 and load_end_addr is set to
990c946d80SToomas Soome  * actual block end, so the EINFO size is (file size - load_end_addr).
1000c946d80SToomas Soome  * installboot does also store the illumos boot partition LBA to MB space,
1010c946d80SToomas Soome  * starting from bss_end_addr structure member location; stage2 will
1020c946d80SToomas Soome  * detect the partition and file system based on this value.
1030c946d80SToomas Soome  *
1040c946d80SToomas Soome  * Stored location values in MBR/stage2 also mean the bootblocks must be
1050c946d80SToomas Soome  * reinstalled in case the partition content is relocated.
1060c946d80SToomas Soome  */
1070c946d80SToomas Soome 
108d7802caeSToomas Soome static bool	write_mbr = false;
1099937ff19SToomas Soome static bool	write_vbr = false;
110d7802caeSToomas Soome static bool	force_mbr = false;
111d7802caeSToomas Soome static bool	force_update = false;
112d7802caeSToomas Soome static bool	do_getinfo = false;
113d7802caeSToomas Soome static bool	do_version = false;
114d7802caeSToomas Soome static bool	do_mirror_bblk = false;
115d7802caeSToomas Soome static bool	strip = false;
116d7802caeSToomas Soome static bool	verbose_dump = false;
117d7802caeSToomas Soome static size_t	sector_size = SECTOR_SIZE;
1180c946d80SToomas Soome 
1190c946d80SToomas Soome /* Versioning string, if present. */
1200c946d80SToomas Soome static char		*update_str;
1210c946d80SToomas Soome 
122d7802caeSToomas Soome /* Default location of boot programs. */
123d7802caeSToomas Soome static char		*boot_dir = "/boot";
124d7802caeSToomas Soome 
125d7802caeSToomas Soome /* Our boot programs */
126d7802caeSToomas Soome #define	STAGE1		"pmbr"
127d7802caeSToomas Soome #define	STAGE2		"gptzfsboot"
128d7802caeSToomas Soome #define	BOOTIA32	"bootia32.efi"
129d7802caeSToomas Soome #define	BOOTX64		"bootx64.efi"
130d7802caeSToomas Soome #define	LOADER32	"loader32.efi"
131d7802caeSToomas Soome #define	LOADER64	"loader64.efi"
132d7802caeSToomas Soome 
133d7802caeSToomas Soome static char *stage1;
134d7802caeSToomas Soome static char *stage2;
135d7802caeSToomas Soome static char *efi32;
136d7802caeSToomas Soome static char *efi64;
137d7802caeSToomas Soome 
138d7802caeSToomas Soome #define	GRUB_VERSION_OFF (0x3e)
139d7802caeSToomas Soome #define	GRUB_COMPAT_VERSION_MAJOR 3
140d7802caeSToomas Soome #define	GRUB_COMPAT_VERSION_MINOR 2
141d7802caeSToomas Soome #define	GRUB_VERSION (2 << 8 | 3) /* 3.2 */
142d7802caeSToomas Soome 
143d7802caeSToomas Soome #define	LOADER_VERSION (1)
144d7802caeSToomas Soome #define	LOADER_JOYENT_VERSION (2)
145d7802caeSToomas Soome 
146d7802caeSToomas Soome typedef enum {
147d7802caeSToomas Soome 	MBR_TYPE_UNKNOWN,
148d7802caeSToomas Soome 	MBR_TYPE_GRUB1,
149d7802caeSToomas Soome 	MBR_TYPE_LOADER,
150d7802caeSToomas Soome 	MBR_TYPE_LOADER_JOYENT,
151d7802caeSToomas Soome } mbr_type_t;
152d7802caeSToomas Soome 
1530c946d80SToomas Soome /*
1540c946d80SToomas Soome  * Temporary buffer to store the first 32K of data looking for a multiboot
1550c946d80SToomas Soome  * signature.
1560c946d80SToomas Soome  */
1570c946d80SToomas Soome char			mboot_scan[MBOOT_SCAN_SIZE];
1580c946d80SToomas Soome 
1590c946d80SToomas Soome /* Function prototypes. */
1600c946d80SToomas Soome static void check_options(char *);
161d7802caeSToomas Soome static int open_device(const char *);
162d7802caeSToomas Soome static char *make_blkdev(const char *);
1630c946d80SToomas Soome 
164d7802caeSToomas Soome static int read_bootblock_from_file(const char *, ib_bootblock_t *);
1650c946d80SToomas Soome static void add_bootblock_einfo(ib_bootblock_t *, char *);
166d7802caeSToomas Soome static void prepare_bootblock(ib_data_t *, struct partlist *, char *);
167d7802caeSToomas Soome static int handle_install(char *, int, char **);
168d7802caeSToomas Soome static int handle_getinfo(char *, int, char **);
169d7802caeSToomas Soome static int handle_mirror(char *, int, char **);
170bdecfb1eSToomas Soome static void usage(char *, int) __NORETURN;
1710c946d80SToomas Soome 
172d7802caeSToomas Soome static char *
stagefs_mount(char * blkdev,struct partlist * plist)173d7802caeSToomas Soome stagefs_mount(char *blkdev, struct partlist *plist)
1740c946d80SToomas Soome {
175d7802caeSToomas Soome 	char *path;
176d7802caeSToomas Soome 	char optbuf[MAX_MNTOPT_STR] = { '\0', };
177d7802caeSToomas Soome 	char *template = strdup("/tmp/ibootXXXXXX");
178d7802caeSToomas Soome 	int ret;
1790c946d80SToomas Soome 
180d7802caeSToomas Soome 	if (template == NULL)
181d7802caeSToomas Soome 		return (NULL);
1820c946d80SToomas Soome 
183d7802caeSToomas Soome 	if ((path = mkdtemp(template)) == NULL) {
184d7802caeSToomas Soome 		free(template);
185d7802caeSToomas Soome 		return (NULL);
1860c946d80SToomas Soome 	}
187d7802caeSToomas Soome 
188d7802caeSToomas Soome 	(void) snprintf(optbuf, MAX_MNTOPT_STR, "timezone=%d",
189d7802caeSToomas Soome 	    timezone);
190d7802caeSToomas Soome 	ret = mount(blkdev, path, MS_OPTIONSTR,
191d7802caeSToomas Soome 	    MNTTYPE_PCFS, NULL, 0, optbuf, MAX_MNTOPT_STR);
192d7802caeSToomas Soome 	if (ret != 0) {
193d7802caeSToomas Soome 		(void) rmdir(path);
194d7802caeSToomas Soome 		free(path);
195d7802caeSToomas Soome 		path = NULL;
196d7802caeSToomas Soome 	}
197d7802caeSToomas Soome 	plist->pl_device->stage.mntpnt = path;
198d7802caeSToomas Soome 	return (path);
1990c946d80SToomas Soome }
2000c946d80SToomas Soome 
201d7802caeSToomas Soome static void
install_stage1_cb(void * data,struct partlist * plist)202d7802caeSToomas Soome install_stage1_cb(void *data, struct partlist *plist)
2030c946d80SToomas Soome {
204d7802caeSToomas Soome 	int rv, fd;
205d7802caeSToomas Soome 	ib_device_t *device = plist->pl_device;
2060c946d80SToomas Soome 
207d7802caeSToomas Soome 	if (plist->pl_type == IB_BBLK_MBR && !write_mbr)
208d7802caeSToomas Soome 		return;
2090c946d80SToomas Soome 
210d7802caeSToomas Soome 	if ((fd = open_device(plist->pl_devname)) == -1) {
211d7802caeSToomas Soome 		(void) fprintf(stdout, gettext("cannot open "
212d7802caeSToomas Soome 		    "device %s\n"), plist->pl_devname);
2130c946d80SToomas Soome 		perror("open");
214d7802caeSToomas Soome 		return;
2150c946d80SToomas Soome 	}
2160c946d80SToomas Soome 
217d7802caeSToomas Soome 	rv = write_out(fd, plist->pl_stage, sector_size, 0);
218d7802caeSToomas Soome 	if (rv != BC_SUCCESS) {
219d7802caeSToomas Soome 		(void) fprintf(stdout, gettext("cannot write "
220d7802caeSToomas Soome 		    "partition boot sector\n"));
221d7802caeSToomas Soome 		perror("write");
222d7802caeSToomas Soome 	} else {
223d7802caeSToomas Soome 		(void) fprintf(stdout, gettext("stage1 written to "
2249937ff19SToomas Soome 		    "%s %d sector 0 (abs %d)\n\n"),
225d7802caeSToomas Soome 		    device->devtype == IB_DEV_MBR? "partition" : "slice",
226d7802caeSToomas Soome 		    device->stage.id, device->stage.start);
2270c946d80SToomas Soome 	}
228d7802caeSToomas Soome }
2290c946d80SToomas Soome 
230d7802caeSToomas Soome static void
install_stage2_cb(void * data,struct partlist * plist)231d7802caeSToomas Soome install_stage2_cb(void *data, struct partlist *plist)
232d7802caeSToomas Soome {
233d7802caeSToomas Soome 	ib_bootblock_t *bblock = plist->pl_src_data;
234d7802caeSToomas Soome 	int fd, ret;
235d7802caeSToomas Soome 	off_t offset;
236d7802caeSToomas Soome 	uint64_t abs;
2370c946d80SToomas Soome 
238d7802caeSToomas Soome 	/*
239d7802caeSToomas Soome 	 * ZFS bootblock area is 3.5MB, make sure we can fit.
240d7802caeSToomas Soome 	 * buf_size is size of bootblk+EINFO.
241d7802caeSToomas Soome 	 */
242d7802caeSToomas Soome 	if (bblock->buf_size > BBLK_ZFS_BLK_SIZE) {
243d7802caeSToomas Soome 		(void) fprintf(stderr, gettext("bootblock is too large\n"));
244d7802caeSToomas Soome 		return;
245d7802caeSToomas Soome 	}
2460c946d80SToomas Soome 
247d7802caeSToomas Soome 	abs = plist->pl_device->stage.start + plist->pl_device->stage.offset;
248d7802caeSToomas Soome 
249d7802caeSToomas Soome 	if ((fd = open_device(plist->pl_devname)) == -1) {
250d7802caeSToomas Soome 		(void) fprintf(stdout, gettext("cannot open "
251d7802caeSToomas Soome 		    "device %s\n"), plist->pl_devname);
252d7802caeSToomas Soome 		perror("open");
253d7802caeSToomas Soome 		return;
254d7802caeSToomas Soome 	}
255d7802caeSToomas Soome 	offset = plist->pl_device->stage.offset * SECTOR_SIZE;
256d7802caeSToomas Soome 	ret = write_out(fd, bblock->buf, bblock->buf_size, offset);
257d7802caeSToomas Soome 	(void) close(fd);
258d7802caeSToomas Soome 	if (ret != BC_SUCCESS) {
259d7802caeSToomas Soome 		BOOT_DEBUG("Error writing the ZFS bootblock "
260d7802caeSToomas Soome 		    "to %s at offset %d\n", plist->pl_devname, offset);
261d7802caeSToomas Soome 		return;
262d7802caeSToomas Soome 	}
263d7802caeSToomas Soome 	(void) fprintf(stdout, gettext("bootblock written for %s,"
2649937ff19SToomas Soome 	    " %d sectors starting at %d (abs %lld)\n\n"), plist->pl_devname,
265d7802caeSToomas Soome 	    (bblock->buf_size / SECTOR_SIZE) + 1, offset / SECTOR_SIZE, abs);
266d7802caeSToomas Soome }
267d7802caeSToomas Soome 
268d7802caeSToomas Soome static bool
mkfs_pcfs(const char * dev)269d7802caeSToomas Soome mkfs_pcfs(const char *dev)
270d7802caeSToomas Soome {
271d7802caeSToomas Soome 	pid_t pid, w;
272d7802caeSToomas Soome 	posix_spawnattr_t attr;
273d7802caeSToomas Soome 	posix_spawn_file_actions_t file_actions;
274d7802caeSToomas Soome 	int status;
275d7802caeSToomas Soome 	char *cmd[7];
276d7802caeSToomas Soome 
277d7802caeSToomas Soome 	if (posix_spawnattr_init(&attr))
278d7802caeSToomas Soome 		return (false);
279d7802caeSToomas Soome 	if (posix_spawn_file_actions_init(&file_actions)) {
280d7802caeSToomas Soome 		(void) posix_spawnattr_destroy(&attr);
281d7802caeSToomas Soome 		return (false);
282d7802caeSToomas Soome 	}
283d7802caeSToomas Soome 
284d7802caeSToomas Soome 	if (posix_spawnattr_setflags(&attr,
286d7802caeSToomas Soome 		(void) posix_spawnattr_destroy(&attr);
287d7802caeSToomas Soome 		(void) posix_spawn_file_actions_destroy(&file_actions);
288d7802caeSToomas Soome 		return (false);
289d7802caeSToomas Soome 	}
290d7802caeSToomas Soome 	if (posix_spawn_file_actions_addopen(&file_actions, 0, "/dev/null",
291d7802caeSToomas Soome 	    O_RDONLY, 0)) {
292d7802caeSToomas Soome 		(void) posix_spawnattr_destroy(&attr);
293d7802caeSToomas Soome 		(void) posix_spawn_file_actions_destroy(&file_actions);
294d7802caeSToomas Soome 		return (false);
295d7802caeSToomas Soome 	}
296d7802caeSToomas Soome 
297d7802caeSToomas Soome 	cmd[0] = "/usr/sbin/mkfs";
298d7802caeSToomas Soome 	cmd[1] = "-F";
299d7802caeSToomas Soome 	cmd[2] = "pcfs";
300d7802caeSToomas Soome 	cmd[3] = "-o";
301d7802caeSToomas Soome 	cmd[4] = "fat=32";
302d7802caeSToomas Soome 	cmd[5] = (char *)dev;
303d7802caeSToomas Soome 	cmd[6] = NULL;
304d7802caeSToomas Soome 
305d7802caeSToomas Soome 	if (posix_spawn(&pid, cmd[0], &file_actions, &attr, cmd, NULL))
306d7802caeSToomas Soome 		return (false);
307d7802caeSToomas Soome 	(void) posix_spawnattr_destroy(&attr);
308d7802caeSToomas Soome 	(void) posix_spawn_file_actions_destroy(&file_actions);
309d7802caeSToomas Soome 
310d7802caeSToomas Soome 	do {
311d7802caeSToomas Soome 		w = waitpid(pid, &status, 0);
312d7802caeSToomas Soome 	} while (w == -1 && errno == EINTR);
313d7802caeSToomas Soome 	if (w == -1)
314d7802caeSToomas Soome 		status = -1;
315d7802caeSToomas Soome 
316d7802caeSToomas Soome 	return (status != -1);
317d7802caeSToomas Soome }
318d7802caeSToomas Soome 
319d7802caeSToomas Soome static void
install_esp_cb(void * data,struct partlist * plist)320d7802caeSToomas Soome install_esp_cb(void *data, struct partlist *plist)
321d7802caeSToomas Soome {
322d7802caeSToomas Soome 	fstyp_handle_t fhdl;
323d7802caeSToomas Soome 	const char *fident;
324d7802caeSToomas Soome 	bool pcfs;
325d7802caeSToomas Soome 	char *blkdev, *path, *file;
326d7802caeSToomas Soome 	FILE *fp;
327d7802caeSToomas Soome 	struct mnttab mp, mpref = { 0 };
328d7802caeSToomas Soome 	ib_bootblock_t *bblock = plist->pl_src_data;
329d7802caeSToomas Soome 	int fd, ret;
330d7802caeSToomas Soome 
331d7802caeSToomas Soome 	if ((fd = open_device(plist->pl_devname)) == -1)
332d7802caeSToomas Soome 		return;
333d7802caeSToomas Soome 
334d7802caeSToomas Soome 	if (fstyp_init(fd, 0, NULL, &fhdl) != 0) {
335d7802caeSToomas Soome 		(void) close(fd);
336d7802caeSToomas Soome 		return;
337d7802caeSToomas Soome 	}
338d7802caeSToomas Soome 
339d7802caeSToomas Soome 	pcfs = false;
340d7802caeSToomas Soome 	if (fstyp_ident(fhdl, NULL, &fident) == 0) {
341d7802caeSToomas Soome 		if (strcmp(fident, MNTTYPE_PCFS) == 0)
342d7802caeSToomas Soome 			pcfs = true;
343d7802caeSToomas Soome 	}
344d7802caeSToomas Soome 	fstyp_fini(fhdl);
345d7802caeSToomas Soome 	(void) close(fd);
346d7802caeSToomas Soome 
347d7802caeSToomas Soome 	if (!pcfs) {
348d7802caeSToomas Soome 		(void) printf(gettext("Creating pcfs on ESP %s\n"),
349d7802caeSToomas Soome 		    plist->pl_devname);
350d7802caeSToomas Soome 
351d7802caeSToomas Soome 		if (!mkfs_pcfs(plist->pl_devname)) {
352d7802caeSToomas Soome 			(void) fprintf(stderr, gettext("mkfs -F pcfs failed "
353d7802caeSToomas Soome 			    "on %s\n"), plist->pl_devname);
354d7802caeSToomas Soome 			return;
355d7802caeSToomas Soome 		}
356d7802caeSToomas Soome 	}
357d7802caeSToomas Soome 	blkdev = make_blkdev(plist->pl_devname);
358d7802caeSToomas Soome 	if (blkdev == NULL)
359d7802caeSToomas Soome 		return;
360d7802caeSToomas Soome 
361d7802caeSToomas Soome 	fp = fopen(MNTTAB, "r");
362d7802caeSToomas Soome 	if (fp == NULL) {
363d7802caeSToomas Soome 		perror("fopen");
364d7802caeSToomas Soome 		free(blkdev);
365d7802caeSToomas Soome 		return;
366d7802caeSToomas Soome 	}
367d7802caeSToomas Soome 
368d7802caeSToomas Soome 	mpref.mnt_special = blkdev;
369d7802caeSToomas Soome 	ret = getmntany(fp, &mp, &mpref);
370d7802caeSToomas Soome 	(void) fclose(fp);
371d7802caeSToomas Soome 	if (ret == 0)
372d7802caeSToomas Soome 		path = mp.mnt_mountp;
373d7802caeSToomas Soome 	else
374d7802caeSToomas Soome 		path = stagefs_mount(blkdev, plist);
375d7802caeSToomas Soome 
376d7802caeSToomas Soome 	free(blkdev);
377d7802caeSToomas Soome 	if (path == NULL)
378d7802caeSToomas Soome 		return;
379d7802caeSToomas Soome 
380d7802caeSToomas Soome 	if (asprintf(&file, "%s%s", path, "/EFI") < 0) {
3810c946d80SToomas Soome 		perror(gettext("Memory allocation failure"));
382d7802caeSToomas Soome 		return;
3830c946d80SToomas Soome 	}
3840c946d80SToomas Soome 
385d7802caeSToomas Soome 	ret = mkdir(file, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
386d7802caeSToomas Soome 	if (ret == 0 || errno == EEXIST) {
387d7802caeSToomas Soome 		free(file);
388d7802caeSToomas Soome 		if (asprintf(&file, "%s%s", path, "/EFI/Boot") < 0) {
389d7802caeSToomas Soome 			perror(gettext("Memory allocation failure"));
390d7802caeSToomas Soome 			return;
391d7802caeSToomas Soome 		}
392d7802caeSToomas Soome 		ret = mkdir(file,
393d7802caeSToomas Soome 		    S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
394d7802caeSToomas Soome 		if (errno == EEXIST)
395d7802caeSToomas Soome 			ret = 0;
396d7802caeSToomas Soome 	}
397d7802caeSToomas Soome 	free(file);
398d7802caeSToomas Soome 	if (ret < 0) {
399d7802caeSToomas Soome 		perror("mkdir");
400d7802caeSToomas Soome 		return;
4010c946d80SToomas Soome 	}
4020c946d80SToomas Soome 
403d7802caeSToomas Soome 	if (asprintf(&file, "%s%s", path, plist->pl_device->stage.path) < 0) {
404d7802caeSToomas Soome 		perror(gettext("Memory allocation failure"));
405d7802caeSToomas Soome 		return;
406d7802caeSToomas Soome 	}
407d7802caeSToomas Soome 
408d7802caeSToomas Soome 	/* Write stage file. Should create temp file and rename. */
409d7802caeSToomas Soome 	(void) chmod(file, S_IRUSR | S_IWUSR);
410d7802caeSToomas Soome 	fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
411d7802caeSToomas Soome 	if (fd != -1) {
412d7802caeSToomas Soome 		ret = write_out(fd, bblock->buf, bblock->buf_size, 0);
413d7802caeSToomas Soome 		if (ret == BC_SUCCESS) {
414d7802caeSToomas Soome 			(void) fprintf(stdout,
4159937ff19SToomas Soome 			    gettext("bootblock written to %s\n\n"), file);
416d7802caeSToomas Soome 		} else {
417d7802caeSToomas Soome 			(void) fprintf(stdout,
418d7802caeSToomas Soome 			    gettext("error while writing %s\n"), file);
419d7802caeSToomas Soome 		}
420d7802caeSToomas Soome 		(void) fchmod(fd, S_IRUSR | S_IRGRP | S_IROTH);
421d7802caeSToomas Soome 		(void) close(fd);
422d7802caeSToomas Soome 	}
423d7802caeSToomas Soome 	free(file);
424d7802caeSToomas Soome }
425d7802caeSToomas Soome 
426d7802caeSToomas Soome /*
427d7802caeSToomas Soome  * MBR setup only depends on write_mbr toggle.
428d7802caeSToomas Soome  */
429d7802caeSToomas Soome static bool
compare_mbr_cb(struct partlist * plist)430d7802caeSToomas Soome compare_mbr_cb(struct partlist *plist)
431d7802caeSToomas Soome {
432d7802caeSToomas Soome 	/* get confirmation for -m */
433d7802caeSToomas Soome 	if (write_mbr && !force_mbr) {
434d7802caeSToomas Soome 		(void) fprintf(stdout, gettext("Updating master boot sector "
435d7802caeSToomas Soome 		    "destroys existing boot managers (if any).\n"
436d7802caeSToomas Soome 		    "continue (y/n)? "));
437d7802caeSToomas Soome 		if (!yes()) {
438d7802caeSToomas Soome 			write_mbr = false;
439d7802caeSToomas Soome 			(void) fprintf(stdout, gettext("master boot sector "
440d7802caeSToomas Soome 			    "not updated\n"));
441d7802caeSToomas Soome 		}
442d7802caeSToomas Soome 	}
443d7802caeSToomas Soome 	if (write_mbr)
444d7802caeSToomas Soome 		(void) printf("%s is newer than one in %s\n",
445d7802caeSToomas Soome 		    plist->pl_src_name, plist->pl_devname);
446d7802caeSToomas Soome 	return (write_mbr);
447d7802caeSToomas Soome }
448d7802caeSToomas Soome 
449d7802caeSToomas Soome /*
4509937ff19SToomas Soome  * VBR setup is done in pair with stage2.
451d7802caeSToomas Soome  */
452d7802caeSToomas Soome static bool
compare_stage1_cb(struct partlist * plist)453d7802caeSToomas Soome compare_stage1_cb(struct partlist *plist)
454d7802caeSToomas Soome {
4559937ff19SToomas Soome 	if (write_vbr) {
456*6b02bf31SToomas Soome 		(void) printf("%s is newer than one in %s\n",
457*6b02bf31SToomas Soome 		    plist->pl_src_name, plist->pl_devname);
4589937ff19SToomas Soome 	}
4599937ff19SToomas Soome 	return (write_vbr);
460d7802caeSToomas Soome }
461d7802caeSToomas Soome 
462d7802caeSToomas Soome /*
463d7802caeSToomas Soome  * Return true if we can update, false if not.
464d7802caeSToomas Soome  */
465d7802caeSToomas Soome static bool
compare_einfo_cb(struct partlist * plist)466d7802caeSToomas Soome compare_einfo_cb(struct partlist *plist)
467d7802caeSToomas Soome {
468d7802caeSToomas Soome 	ib_bootblock_t *bblock, *bblock_file;
469d7802caeSToomas Soome 	bblk_einfo_t *einfo, *einfo_file;
470d7802caeSToomas Soome 	bblk_hs_t bblock_hs;
471d7802caeSToomas Soome 	bool rv;
472d7802caeSToomas Soome 
47346d70dceSToomas Soome 	bblock_file = plist->pl_src_data;
47446d70dceSToomas Soome 	if (bblock_file == NULL)
47546d70dceSToomas Soome 		return (false);	/* source is missing, cannot update */
47646d70dceSToomas Soome 
477d7802caeSToomas Soome 	bblock = plist->pl_stage;
4789937ff19SToomas Soome 	if (bblock == NULL ||
4799937ff19SToomas Soome 	    bblock->extra == NULL ||
4809937ff19SToomas Soome 	    bblock->extra_size == 0) {
4819937ff19SToomas Soome 		if (plist->pl_type == IB_BBLK_STAGE2)
4829937ff19SToomas Soome 			write_vbr = true;
483d7802caeSToomas Soome 		return (true);
4849937ff19SToomas Soome 	}
485d7802caeSToomas Soome 
486d7802caeSToomas Soome 	einfo = find_einfo(bblock->extra, bblock->extra_size);
487d7802caeSToomas Soome 	if (einfo == NULL) {
488d7802caeSToomas Soome 		BOOT_DEBUG("No extended information available on disk\n");
4899937ff19SToomas Soome 		if (plist->pl_type == IB_BBLK_STAGE2)
4909937ff19SToomas Soome 			write_vbr = true;
491d7802caeSToomas Soome 		return (true);
492d7802caeSToomas Soome 	}
493d7802caeSToomas Soome 
494d7802caeSToomas Soome 	einfo_file = find_einfo(bblock_file->extra, bblock_file->extra_size);
495d7802caeSToomas Soome 	if (einfo_file == NULL) {
496d7802caeSToomas Soome 		/*
497d7802caeSToomas Soome 		 * loader bootblock is versioned. missing version means
498d7802caeSToomas Soome 		 * probably incompatible block. installboot can not install
499d7802caeSToomas Soome 		 * grub, for example.
500d7802caeSToomas Soome 		 */
5010c946d80SToomas Soome 		(void) fprintf(stderr,
502d7802caeSToomas Soome 		    gettext("ERROR: non versioned bootblock in file\n"));
503d7802caeSToomas Soome 		return (false);
504d7802caeSToomas Soome 	} else {
505d7802caeSToomas Soome 		if (update_str == NULL) {
506d7802caeSToomas Soome 			update_str = einfo_get_string(einfo_file);
507d7802caeSToomas Soome 			do_version = true;
508d7802caeSToomas Soome 		}
5090c946d80SToomas Soome 	}
5100c946d80SToomas Soome 
511d7802caeSToomas Soome 	if (!do_version || update_str == NULL) {
512d7802caeSToomas Soome 		(void) fprintf(stderr,
513d7802caeSToomas Soome 		    gettext("WARNING: target device %s has a "
514d7802caeSToomas Soome 		    "versioned bootblock that is going to be overwritten by a "
515d7802caeSToomas Soome 		    "non versioned one\n"), plist->pl_devname);
5169937ff19SToomas Soome 		if (plist->pl_type == IB_BBLK_STAGE2)
5179937ff19SToomas Soome 			write_vbr = true;
518d7802caeSToomas Soome 		return (true);
519d7802caeSToomas Soome 	}
5200c946d80SToomas Soome 
521d7802caeSToomas Soome 	if (force_update) {
522d7802caeSToomas Soome 		BOOT_DEBUG("Forcing update of %s bootblock\n",
523d7802caeSToomas Soome 		    plist->pl_devname);
5249937ff19SToomas Soome 		if (plist->pl_type == IB_BBLK_STAGE2)
5259937ff19SToomas Soome 			write_vbr = true;
526d7802caeSToomas Soome 		return (true);
527d7802caeSToomas Soome 	}
5280c946d80SToomas Soome 
529d7802caeSToomas Soome 	BOOT_DEBUG("Ready to check installed version vs %s\n", update_str);
5300c946d80SToomas Soome 
531d7802caeSToomas Soome 	bblock_hs.src_buf = (unsigned char *)bblock_file->file;
532d7802caeSToomas Soome 	bblock_hs.src_size = bblock_file->file_size;
533d7802caeSToomas Soome 
534d7802caeSToomas Soome 	rv = einfo_should_update(einfo, &bblock_hs, update_str);
535d7802caeSToomas Soome 	if (rv == false) {
5369937ff19SToomas Soome 		(void) fprintf(stderr, gettext("Bootblock version installed "
537d7802caeSToomas Soome 		    "on %s is more recent or identical to\n%s\n"
5389937ff19SToomas Soome 		    "Use -F to override or install without the -u option.\n\n"),
539d7802caeSToomas Soome 		    plist->pl_devname, plist->pl_src_name);
540d7802caeSToomas Soome 	} else {
541d7802caeSToomas Soome 		(void) printf("%s is newer than one in %s\n",
542d7802caeSToomas Soome 		    plist->pl_src_name, plist->pl_devname);
5439937ff19SToomas Soome 		if (plist->pl_type == IB_BBLK_STAGE2)
5449937ff19SToomas Soome 			write_vbr = true;
545d7802caeSToomas Soome 	}
546d7802caeSToomas Soome 	return (rv);
547d7802caeSToomas Soome }
548d7802caeSToomas Soome 
549d7802caeSToomas Soome static bool
read_stage1_cb(struct partlist * plist)550d7802caeSToomas Soome read_stage1_cb(struct partlist *plist)
551d7802caeSToomas Soome {
552d7802caeSToomas Soome 	int fd;
553d7802caeSToomas Soome 	bool rv = false;
554d7802caeSToomas Soome 
555d7802caeSToomas Soome 	if ((fd = open_device(plist->pl_devname)) == -1)
556d7802caeSToomas Soome 		return (rv);
557d7802caeSToomas Soome 
558d7802caeSToomas Soome 	if (plist->pl_stage == NULL)
559d7802caeSToomas Soome 		plist->pl_stage = calloc(1, sector_size);
560d7802caeSToomas Soome 
561d7802caeSToomas Soome 	if (plist->pl_stage == NULL) {
562d7802caeSToomas Soome 		perror("calloc");
563d7802caeSToomas Soome 		goto done;
564d7802caeSToomas Soome 	}
5650c946d80SToomas Soome 
566d7802caeSToomas Soome 	if (pread(fd, plist->pl_stage, sector_size, 0) == -1) {
567d7802caeSToomas Soome 		perror("pread");
568d7802caeSToomas Soome 		goto done;
569d7802caeSToomas Soome 	}
570d7802caeSToomas Soome 	rv = true;
571d7802caeSToomas Soome done:
5720c946d80SToomas Soome 	(void) close(fd);
573d7802caeSToomas Soome 	return (rv);
574d7802caeSToomas Soome }
5750c946d80SToomas Soome 
576d7802caeSToomas Soome static bool
read_stage1_bbl_cb(struct partlist * plist)577d7802caeSToomas Soome read_stage1_bbl_cb(struct partlist *plist)
578d7802caeSToomas Soome {
579d7802caeSToomas Soome 	int fd;
580d7802caeSToomas Soome 	void *data;
581d7802caeSToomas Soome 	bool rv = false;
582d7802caeSToomas Soome 
583d7802caeSToomas Soome 	data = malloc(SECTOR_SIZE);
584d7802caeSToomas Soome 	if (data == NULL)
585d7802caeSToomas Soome 		return (rv);
586d7802caeSToomas Soome 
587d7802caeSToomas Soome 	/* read the stage1 file from filesystem */
588d7802caeSToomas Soome 	fd = open(plist->pl_src_name, O_RDONLY);
589d7802caeSToomas Soome 	if (fd == -1 ||
590d7802caeSToomas Soome 	    read(fd, data, SECTOR_SIZE) != SECTOR_SIZE) {
591d7802caeSToomas Soome 		(void) fprintf(stderr, gettext("cannot read stage1 file %s\n"),
592d7802caeSToomas Soome 		    plist->pl_src_name);
593d7802caeSToomas Soome 		free(data);
594d7802caeSToomas Soome 		if (fd != -1)
595d7802caeSToomas Soome 			(void) close(fd);
596d7802caeSToomas Soome 		return (rv);
597d7802caeSToomas Soome 	}
598d7802caeSToomas Soome 
599d7802caeSToomas Soome 	plist->pl_src_data = data;
6000c946d80SToomas Soome 	(void) close(fd);
601d7802caeSToomas Soome 	return (true);
6020c946d80SToomas Soome }
6030c946d80SToomas Soome 
604d7802caeSToomas Soome static bool
read_stage2_cb(struct partlist * plist)605d7802caeSToomas Soome read_stage2_cb(struct partlist *plist)
6060c946d80SToomas Soome {
607d7802caeSToomas Soome 	ib_device_t		*device;
608d7802caeSToomas Soome 	ib_bootblock_t		*bblock;
609d7802caeSToomas Soome 	int			fd;
6100c946d80SToomas Soome 	uint32_t		size, offset;
6110c946d80SToomas Soome 	uint32_t		buf_size;
6120c946d80SToomas Soome 	uint32_t		mboot_off;
6130c946d80SToomas Soome 	multiboot_header_t	*mboot;
614b97b1727SToomas Soome 	size_t			scan_size;
6150c946d80SToomas Soome 
616d7802caeSToomas Soome 	bblock = calloc(1, sizeof (ib_bootblock_t));
617d7802caeSToomas Soome 	if (bblock == NULL)
618d7802caeSToomas Soome 		return (false);
6190c946d80SToomas Soome 
620d7802caeSToomas Soome 	if ((fd = open_device(plist->pl_devname)) == -1) {
621d7802caeSToomas Soome 		free(bblock);
622d7802caeSToomas Soome 		return (false);
6230c946d80SToomas Soome 	}
6240c946d80SToomas Soome 
625d7802caeSToomas Soome 	device = plist->pl_device;
626d7802caeSToomas Soome 	plist->pl_stage = bblock;
627d7802caeSToomas Soome 	offset = device->stage.offset * SECTOR_SIZE;
628b97b1727SToomas Soome 	scan_size = MIN(sizeof (mboot_scan),
629b97b1727SToomas Soome 	    (device->stage.size - device->stage.offset) * sector_size);
630d7802caeSToomas Soome 
631b97b1727SToomas Soome 	if (read_in(fd, mboot_scan, scan_size, offset)
6320c946d80SToomas Soome 	    != BC_SUCCESS) {
6330c946d80SToomas Soome 		BOOT_DEBUG("Error reading bootblock area\n");
6340c946d80SToomas Soome 		perror("read");
635d7802caeSToomas Soome 		(void) close(fd);
636d7802caeSToomas Soome 		return (false);
6370c946d80SToomas Soome 	}
6380c946d80SToomas Soome 
6390c946d80SToomas Soome 	/* No multiboot means no chance of knowing bootblock size */
640b97b1727SToomas Soome 	if (find_multiboot(mboot_scan, scan_size, &mboot_off)
6410c946d80SToomas Soome 	    != BC_SUCCESS) {
6420c946d80SToomas Soome 		BOOT_DEBUG("Unable to find multiboot header\n");
643d7802caeSToomas Soome 		(void) close(fd);
644d7802caeSToomas Soome 		return (false);
6450c946d80SToomas Soome 	}
6460c946d80SToomas Soome 	mboot = (multiboot_header_t *)(mboot_scan + mboot_off);
6470c946d80SToomas Soome 
6480c946d80SToomas Soome 	/*
6490c946d80SToomas Soome 	 * make sure mboot has sane values
6500c946d80SToomas Soome 	 */
6510c946d80SToomas Soome 	if (mboot->load_end_addr == 0 ||
652d7802caeSToomas Soome 	    mboot->load_end_addr < mboot->load_addr) {
653d7802caeSToomas Soome 		(void) close(fd);
654d7802caeSToomas Soome 		return (false);
655d7802caeSToomas Soome 	}
6560c946d80SToomas Soome 
6570c946d80SToomas Soome 	/*
6580c946d80SToomas Soome 	 * Currently, the amount of space reserved for extra information
6590c946d80SToomas Soome 	 * is "fixed". We may have to scan for the terminating extra payload
6600c946d80SToomas Soome 	 * in the future.
6610c946d80SToomas Soome 	 */
6620c946d80SToomas Soome 	size = mboot->load_end_addr - mboot->load_addr;
6630c946d80SToomas Soome 	buf_size = P2ROUNDUP(size + SECTOR_SIZE, SECTOR_SIZE);
6640c946d80SToomas Soome 	bblock->file_size = size;
6650c946d80SToomas Soome 
6660c946d80SToomas Soome 	bblock->buf = malloc(buf_size);
6670c946d80SToomas Soome 	if (bblock->buf == NULL) {
6680c946d80SToomas Soome 		BOOT_DEBUG("Unable to allocate enough memory to read"
6690c946d80SToomas Soome 		    " the extra bootblock from the disk\n");
6700c946d80SToomas Soome 		perror(gettext("Memory allocation failure"));
671d7802caeSToomas Soome 		(void) close(fd);
672d7802caeSToomas Soome 		return (false);
6730c946d80SToomas Soome 	}
6740c946d80SToomas Soome 	bblock->buf_size = buf_size;
6750c946d80SToomas Soome 
676d7802caeSToomas Soome 	if (read_in(fd, bblock->buf, buf_size, offset) != BC_SUCCESS) {
6770c946d80SToomas Soome 		BOOT_DEBUG("Error reading the bootblock\n");
6780c946d80SToomas Soome 		(void) free(bblock->buf);
6790c946d80SToomas Soome 		bblock->buf = NULL;
680d7802caeSToomas Soome 		(void) close(fd);
681d7802caeSToomas Soome 		return (false);
6820c946d80SToomas Soome 	}
6830c946d80SToomas Soome 
6840c946d80SToomas Soome 	/* Update pointers. */
6850c946d80SToomas Soome 	bblock->file = bblock->buf;
6860c946d80SToomas Soome 	bblock->mboot_off = mboot_off;
6870c946d80SToomas Soome 	bblock->mboot = (multiboot_header_t *)(bblock->buf + bblock->mboot_off);
6880c946d80SToomas Soome 	bblock->extra = bblock->buf + P2ROUNDUP(bblock->file_size, 8);
6890c946d80SToomas Soome 	bblock->extra_size = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8);
6900c946d80SToomas Soome 
6910c946d80SToomas Soome 	BOOT_DEBUG("mboot at %p offset %d, extra at %p size %d, buf=%p "
6920c946d80SToomas Soome 	    "(size=%d)\n", bblock->mboot, bblock->mboot_off, bblock->extra,
6930c946d80SToomas Soome 	    bblock->extra_size, bblock->buf, bblock->buf_size);
6940c946d80SToomas Soome 
695d7802caeSToomas Soome 	return (true);
6960c946d80SToomas Soome }
6970c946d80SToomas Soome 
698d7802caeSToomas Soome static bool
read_einfo_file_cb(struct partlist * plist)699d7802caeSToomas Soome read_einfo_file_cb(struct partlist *plist)
7000c946d80SToomas Soome {
70146d70dceSToomas Soome 	int rc;
70246d70dceSToomas Soome 	void *stage;
70346d70dceSToomas Soome 
70446d70dceSToomas Soome 	stage = calloc(1, sizeof (ib_bootblock_t));
70546d70dceSToomas Soome 	if (stage == NULL)
706d7802caeSToomas Soome 		return (false);
7070c946d80SToomas Soome 
70846d70dceSToomas Soome 	rc =  read_bootblock_from_file(plist->pl_devname, stage);
70946d70dceSToomas Soome 	if (rc != BC_SUCCESS) {
71046d70dceSToomas Soome 		free(stage);
71146d70dceSToomas Soome 		stage = NULL;
71246d70dceSToomas Soome 	}
71346d70dceSToomas Soome 	plist->pl_stage = stage;
71446d70dceSToomas Soome 	return (rc == BC_SUCCESS);
715d7802caeSToomas Soome }
7160c946d80SToomas Soome 
717d7802caeSToomas Soome static bool
read_stage2_file_cb(struct partlist * plist)718d7802caeSToomas Soome read_stage2_file_cb(struct partlist *plist)
719d7802caeSToomas Soome {
72046d70dceSToomas Soome 	int rc;
72146d70dceSToomas Soome 	void *data;
72246d70dceSToomas Soome 
72346d70dceSToomas Soome 	data = calloc(1, sizeof (ib_bootblock_t));
72446d70dceSToomas Soome 	if (data == NULL)
725d7802caeSToomas Soome 		return (false);
7260c946d80SToomas Soome 
72746d70dceSToomas Soome 	rc = read_bootblock_from_file(plist->pl_src_name, data);
72846d70dceSToomas Soome 	if (rc != BC_SUCCESS) {
72946d70dceSToomas Soome 		free(data);
73046d70dceSToomas Soome 		data = NULL;
73146d70dceSToomas Soome 	}
73246d70dceSToomas Soome 	plist->pl_src_data = data;
73346d70dceSToomas Soome 	return (rc == BC_SUCCESS);
734d7802caeSToomas Soome }
7350c946d80SToomas Soome 
736d7802caeSToomas Soome /*
737d7802caeSToomas Soome  * convert /dev/rdsk/... to /dev/dsk/...
738d7802caeSToomas Soome  */
739d7802caeSToomas Soome static char *
make_blkdev(const char * path)740d7802caeSToomas Soome make_blkdev(const char *path)
741d7802caeSToomas Soome {
742d7802caeSToomas Soome 	char *tmp;
743d7802caeSToomas Soome 	char *ptr = strdup(path);
7440c946d80SToomas Soome 
745d7802caeSToomas Soome 	if (ptr == NULL)
746d7802caeSToomas Soome 		return (ptr);
7470c946d80SToomas Soome 
748d7802caeSToomas Soome 	tmp = strstr(ptr, "rdsk");
749d7802caeSToomas Soome 	if (tmp == NULL) {
750d7802caeSToomas Soome 		free(ptr);
751d7802caeSToomas Soome 		return (NULL); /* Something is very wrong */
7520c946d80SToomas Soome 	}
753d7802caeSToomas Soome 	/* This is safe because we do shorten the string */
754d7802caeSToomas Soome 	(void) memmove(tmp, tmp + 1, strlen(tmp));
755d7802caeSToomas Soome 	return (ptr);
756d7802caeSToomas Soome }
7570c946d80SToomas Soome 
758d7802caeSToomas Soome /*
759d7802caeSToomas Soome  * Try to mount ESP and read boot program.
760d7802caeSToomas Soome  */
761d7802caeSToomas Soome static bool
read_einfo_esp_cb(struct partlist * plist)762d7802caeSToomas Soome read_einfo_esp_cb(struct partlist *plist)
763d7802caeSToomas Soome {
764d7802caeSToomas Soome 	fstyp_handle_t fhdl;
765d7802caeSToomas Soome 	const char *fident;
766d7802caeSToomas Soome 	char *blkdev, *path, *file;
767d7802caeSToomas Soome 	bool rv = false;
768d7802caeSToomas Soome 	FILE *fp;
769d7802caeSToomas Soome 	struct mnttab mp, mpref = { 0 };
770d7802caeSToomas Soome 	int fd, ret;
7710c946d80SToomas Soome 
772d7802caeSToomas Soome 	if ((fd = open_device(plist->pl_devname)) == -1)
773d7802caeSToomas Soome 		return (rv);
7740c946d80SToomas Soome 
775d7802caeSToomas Soome 	if (fstyp_init(fd, 0, NULL, &fhdl) != 0) {
776d7802caeSToomas Soome 		(void) close(fd);
777d7802caeSToomas Soome 		return (rv);
778d7802caeSToomas Soome 	}
7790c946d80SToomas Soome 
780d7802caeSToomas Soome 	if (fstyp_ident(fhdl, NULL, &fident) != 0) {
781d7802caeSToomas Soome 		fstyp_fini(fhdl);
782d7802caeSToomas Soome 		(void) close(fd);
783d7802caeSToomas Soome 		(void) fprintf(stderr, gettext("Failed to detect file "
784d7802caeSToomas Soome 		    "system type\n"));
785d7802caeSToomas Soome 		return (rv);
786d7802caeSToomas Soome 	}
7870c946d80SToomas Soome 
788d7802caeSToomas Soome 	/* We only do expect pcfs. */
789d7802caeSToomas Soome 	if (strcmp(fident, MNTTYPE_PCFS) != 0) {
790d7802caeSToomas Soome 		(void) fprintf(stderr,
791d7802caeSToomas Soome 		    gettext("File system %s is not supported.\n"), fident);
792d7802caeSToomas Soome 		fstyp_fini(fhdl);
793d7802caeSToomas Soome 		(void) close(fd);
794d7802caeSToomas Soome 		return (rv);
795d7802caeSToomas Soome 	}
796d7802caeSToomas Soome 	fstyp_fini(fhdl);
797d7802caeSToomas Soome 	(void) close(fd);
798d7802caeSToomas Soome 
799d7802caeSToomas Soome 	blkdev = make_blkdev(plist->pl_devname);
800d7802caeSToomas Soome 	if (blkdev == NULL)
801d7802caeSToomas Soome 		return (rv);
802d7802caeSToomas Soome 
803d7802caeSToomas Soome 	/* mount ESP if needed, read boot program(s) and unmount. */
804d7802caeSToomas Soome 	fp = fopen(MNTTAB, "r");
805d7802caeSToomas Soome 	if (fp == NULL) {
806d7802caeSToomas Soome 		perror("fopen");
807d7802caeSToomas Soome 		free(blkdev);
808d7802caeSToomas Soome 		return (rv);
8090c946d80SToomas Soome 	}
8100c946d80SToomas Soome 
811d7802caeSToomas Soome 	mpref.mnt_special = blkdev;
812d7802caeSToomas Soome 	ret = getmntany(fp, &mp, &mpref);
813d7802caeSToomas Soome 	(void) fclose(fp);
814d7802caeSToomas Soome 	if (ret == 0)
815d7802caeSToomas Soome 		path = mp.mnt_mountp;
816d7802caeSToomas Soome 	else
817d7802caeSToomas Soome 		path = stagefs_mount(blkdev, plist);
818d7802caeSToomas Soome 
819d7802caeSToomas Soome 	free(blkdev);
820d7802caeSToomas Soome 	if (path == NULL)
821d7802caeSToomas Soome 		return (rv);
822d7802caeSToomas Soome 
823d7802caeSToomas Soome 	if (asprintf(&file, "%s%s", path, plist->pl_device->stage.path) < 0) {
824d7802caeSToomas Soome 		return (rv);
825d7802caeSToomas Soome 	}
826d7802caeSToomas Soome 
827d7802caeSToomas Soome 	plist->pl_stage = calloc(1, sizeof (ib_bootblock_t));
828d7802caeSToomas Soome 	if (plist->pl_stage == NULL) {
829d7802caeSToomas Soome 		free(file);
830d7802caeSToomas Soome 		return (rv);
831d7802caeSToomas Soome 	}
832d7802caeSToomas Soome 	if (read_bootblock_from_file(file, plist->pl_stage) != BC_SUCCESS) {
833d7802caeSToomas Soome 		free(plist->pl_stage);
834d7802caeSToomas Soome 		plist->pl_stage = NULL;
835d7802caeSToomas Soome 	} else {
836d7802caeSToomas Soome 		rv = true;
837d7802caeSToomas Soome 	}
838d7802caeSToomas Soome 
839d7802caeSToomas Soome 	free(file);
840d7802caeSToomas Soome 	return (rv);