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; 109d7802caeSToomas Soome static bool force_mbr = false; 110d7802caeSToomas Soome static bool force_update = false; 111d7802caeSToomas Soome static bool do_getinfo = false; 112d7802caeSToomas Soome static bool do_version = false; 113d7802caeSToomas Soome static bool do_mirror_bblk = false; 114d7802caeSToomas Soome static bool strip = false; 115d7802caeSToomas Soome static bool verbose_dump = false; 116d7802caeSToomas Soome static size_t sector_size = SECTOR_SIZE; 1170c946d80SToomas Soome 1180c946d80SToomas Soome /* Versioning string, if present. */ 1190c946d80SToomas Soome static char *update_str; 1200c946d80SToomas Soome 121d7802caeSToomas Soome /* Default location of boot programs. */ 122d7802caeSToomas Soome static char *boot_dir = "/boot"; 123d7802caeSToomas Soome 124d7802caeSToomas Soome /* Our boot programs */ 125d7802caeSToomas Soome #define STAGE1 "pmbr" 126d7802caeSToomas Soome #define STAGE2 "gptzfsboot" 127d7802caeSToomas Soome #define BOOTIA32 "bootia32.efi" 128d7802caeSToomas Soome #define BOOTX64 "bootx64.efi" 129d7802caeSToomas Soome #define LOADER32 "loader32.efi" 130d7802caeSToomas Soome #define LOADER64 "loader64.efi" 131d7802caeSToomas Soome 132d7802caeSToomas Soome static char *stage1; 133d7802caeSToomas Soome static char *stage2; 134d7802caeSToomas Soome static char *efi32; 135d7802caeSToomas Soome static char *efi64; 136d7802caeSToomas Soome 137d7802caeSToomas Soome #define GRUB_VERSION_OFF (0x3e) 138d7802caeSToomas Soome #define GRUB_COMPAT_VERSION_MAJOR 3 139d7802caeSToomas Soome #define GRUB_COMPAT_VERSION_MINOR 2 140d7802caeSToomas Soome #define GRUB_VERSION (2 << 8 | 3) /* 3.2 */ 141d7802caeSToomas Soome 142d7802caeSToomas Soome #define LOADER_VERSION (1) 143d7802caeSToomas Soome #define LOADER_JOYENT_VERSION (2) 144d7802caeSToomas Soome 145d7802caeSToomas Soome typedef enum { 146d7802caeSToomas Soome MBR_TYPE_UNKNOWN, 147d7802caeSToomas Soome MBR_TYPE_GRUB1, 148d7802caeSToomas Soome MBR_TYPE_LOADER, 149d7802caeSToomas Soome MBR_TYPE_LOADER_JOYENT, 150d7802caeSToomas Soome } mbr_type_t; 151d7802caeSToomas Soome 1520c946d80SToomas Soome /* 1530c946d80SToomas Soome * Temporary buffer to store the first 32K of data looking for a multiboot 1540c946d80SToomas Soome * signature. 1550c946d80SToomas Soome */ 1560c946d80SToomas Soome char mboot_scan[MBOOT_SCAN_SIZE]; 1570c946d80SToomas Soome 1580c946d80SToomas Soome /* Function prototypes. */ 1590c946d80SToomas Soome static void check_options(char *); 160d7802caeSToomas Soome static int open_device(const char *); 161d7802caeSToomas Soome static char *make_blkdev(const char *); 1620c946d80SToomas Soome 163d7802caeSToomas Soome static int read_bootblock_from_file(const char *, ib_bootblock_t *); 1640c946d80SToomas Soome static void add_bootblock_einfo(ib_bootblock_t *, char *); 165d7802caeSToomas Soome static void prepare_bootblock(ib_data_t *, struct partlist *, char *); 166d7802caeSToomas Soome static int handle_install(char *, int, char **); 167d7802caeSToomas Soome static int handle_getinfo(char *, int, char **); 168d7802caeSToomas Soome static int handle_mirror(char *, int, char **); 169bdecfb1eSToomas Soome static void usage(char *, int) __NORETURN; 1700c946d80SToomas Soome 171d7802caeSToomas Soome static char * 172d7802caeSToomas Soome stagefs_mount(char *blkdev, struct partlist *plist) 1730c946d80SToomas Soome { 174d7802caeSToomas Soome char *path; 175d7802caeSToomas Soome char optbuf[MAX_MNTOPT_STR] = { '\0', }; 176d7802caeSToomas Soome char *template = strdup("/tmp/ibootXXXXXX"); 177d7802caeSToomas Soome int ret; 1780c946d80SToomas Soome 179d7802caeSToomas Soome if (template == NULL) 180d7802caeSToomas Soome return (NULL); 1810c946d80SToomas Soome 182d7802caeSToomas Soome if ((path = mkdtemp(template)) == NULL) { 183d7802caeSToomas Soome free(template); 184d7802caeSToomas Soome return (NULL); 1850c946d80SToomas Soome } 186d7802caeSToomas Soome 187d7802caeSToomas Soome (void) snprintf(optbuf, MAX_MNTOPT_STR, "timezone=%d", 188d7802caeSToomas Soome timezone); 189d7802caeSToomas Soome ret = mount(blkdev, path, MS_OPTIONSTR, 190d7802caeSToomas Soome MNTTYPE_PCFS, NULL, 0, optbuf, MAX_MNTOPT_STR); 191d7802caeSToomas Soome if (ret != 0) { 192d7802caeSToomas Soome (void) rmdir(path); 193d7802caeSToomas Soome free(path); 194d7802caeSToomas Soome path = NULL; 195d7802caeSToomas Soome } 196d7802caeSToomas Soome plist->pl_device->stage.mntpnt = path; 197d7802caeSToomas Soome return (path); 1980c946d80SToomas Soome } 1990c946d80SToomas Soome 200d7802caeSToomas Soome static void 201d7802caeSToomas Soome install_stage1_cb(void *data, struct partlist *plist) 2020c946d80SToomas Soome { 203d7802caeSToomas Soome int rv, fd; 204d7802caeSToomas Soome ib_device_t *device = plist->pl_device; 2050c946d80SToomas Soome 206d7802caeSToomas Soome if (plist->pl_type == IB_BBLK_MBR && !write_mbr) 207d7802caeSToomas Soome return; 2080c946d80SToomas Soome 209d7802caeSToomas Soome if ((fd = open_device(plist->pl_devname)) == -1) { 210d7802caeSToomas Soome (void) fprintf(stdout, gettext("cannot open " 211d7802caeSToomas Soome "device %s\n"), plist->pl_devname); 2120c946d80SToomas Soome perror("open"); 213d7802caeSToomas Soome return; 2140c946d80SToomas Soome } 2150c946d80SToomas Soome 216d7802caeSToomas Soome rv = write_out(fd, plist->pl_stage, sector_size, 0); 217d7802caeSToomas Soome if (rv != BC_SUCCESS) { 218d7802caeSToomas Soome (void) fprintf(stdout, gettext("cannot write " 219d7802caeSToomas Soome "partition boot sector\n")); 220d7802caeSToomas Soome perror("write"); 221d7802caeSToomas Soome } else { 222d7802caeSToomas Soome (void) fprintf(stdout, gettext("stage1 written to " 223d7802caeSToomas Soome "%s %d sector 0 (abs %d)\n"), 224d7802caeSToomas Soome device->devtype == IB_DEV_MBR? "partition" : "slice", 225d7802caeSToomas Soome device->stage.id, device->stage.start); 2260c946d80SToomas Soome } 227d7802caeSToomas Soome } 2280c946d80SToomas Soome 229d7802caeSToomas Soome static void 230d7802caeSToomas Soome install_stage2_cb(void *data, struct partlist *plist) 231d7802caeSToomas Soome { 232d7802caeSToomas Soome ib_bootblock_t *bblock = plist->pl_src_data; 233d7802caeSToomas Soome int fd, ret; 234d7802caeSToomas Soome off_t offset; 235d7802caeSToomas Soome uint64_t abs; 2360c946d80SToomas Soome 237d7802caeSToomas Soome /* 238d7802caeSToomas Soome * ZFS bootblock area is 3.5MB, make sure we can fit. 239d7802caeSToomas Soome * buf_size is size of bootblk+EINFO. 240d7802caeSToomas Soome */ 241d7802caeSToomas Soome if (bblock->buf_size > BBLK_ZFS_BLK_SIZE) { 242d7802caeSToomas Soome (void) fprintf(stderr, gettext("bootblock is too large\n")); 243d7802caeSToomas Soome return; 244d7802caeSToomas Soome } 2450c946d80SToomas Soome 246d7802caeSToomas Soome abs = plist->pl_device->stage.start + plist->pl_device->stage.offset; 247d7802caeSToomas Soome 248d7802caeSToomas Soome if ((fd = open_device(plist->pl_devname)) == -1) { 249d7802caeSToomas Soome (void) fprintf(stdout, gettext("cannot open " 250d7802caeSToomas Soome "device %s\n"), plist->pl_devname); 251d7802caeSToomas Soome perror("open"); 252d7802caeSToomas Soome return; 253d7802caeSToomas Soome } 254d7802caeSToomas Soome offset = plist->pl_device->stage.offset * SECTOR_SIZE; 255d7802caeSToomas Soome ret = write_out(fd, bblock->buf, bblock->buf_size, offset); 256d7802caeSToomas Soome (void) close(fd); 257d7802caeSToomas Soome if (ret != BC_SUCCESS) { 258d7802caeSToomas Soome BOOT_DEBUG("Error writing the ZFS bootblock " 259d7802caeSToomas Soome "to %s at offset %d\n", plist->pl_devname, offset); 260d7802caeSToomas Soome return; 261d7802caeSToomas Soome } 262d7802caeSToomas Soome (void) fprintf(stdout, gettext("bootblock written for %s," 263d7802caeSToomas Soome " %d sectors starting at %d (abs %lld)\n"), plist->pl_devname, 264d7802caeSToomas Soome (bblock->buf_size / SECTOR_SIZE) + 1, offset / SECTOR_SIZE, abs); 265d7802caeSToomas Soome } 266d7802caeSToomas Soome 267d7802caeSToomas Soome static bool 268d7802caeSToomas Soome mkfs_pcfs(const char *dev) 269d7802caeSToomas Soome { 270d7802caeSToomas Soome pid_t pid, w; 271d7802caeSToomas Soome posix_spawnattr_t attr; 272d7802caeSToomas Soome posix_spawn_file_actions_t file_actions; 273d7802caeSToomas Soome int status; 274d7802caeSToomas Soome char *cmd[7]; 275d7802caeSToomas Soome 276d7802caeSToomas Soome if (posix_spawnattr_init(&attr)) 277d7802caeSToomas Soome return (false); 278d7802caeSToomas Soome if (posix_spawn_file_actions_init(&file_actions)) { 279d7802caeSToomas Soome (void) posix_spawnattr_destroy(&attr); 280d7802caeSToomas Soome return (false); 281d7802caeSToomas Soome } 282d7802caeSToomas Soome 283d7802caeSToomas Soome if (posix_spawnattr_setflags(&attr, 284d7802caeSToomas Soome POSIX_SPAWN_NOSIGCHLD_NP | POSIX_SPAWN_WAITPID_NP)) { 285d7802caeSToomas Soome (void) posix_spawnattr_destroy(&attr); 286d7802caeSToomas Soome (void) posix_spawn_file_actions_destroy(&file_actions); 287d7802caeSToomas Soome return (false); 288d7802caeSToomas Soome } 289d7802caeSToomas Soome if (posix_spawn_file_actions_addopen(&file_actions, 0, "/dev/null", 290d7802caeSToomas Soome O_RDONLY, 0)) { 291d7802caeSToomas Soome (void) posix_spawnattr_destroy(&attr); 292d7802caeSToomas Soome (void) posix_spawn_file_actions_destroy(&file_actions); 293d7802caeSToomas Soome return (false); 294d7802caeSToomas Soome } 295d7802caeSToomas Soome 296d7802caeSToomas Soome cmd[0] = "/usr/sbin/mkfs"; 297d7802caeSToomas Soome cmd[1] = "-F"; 298d7802caeSToomas Soome cmd[2] = "pcfs"; 299d7802caeSToomas Soome cmd[3] = "-o"; 300d7802caeSToomas Soome cmd[4] = "fat=32"; 301d7802caeSToomas Soome cmd[5] = (char *)dev; 302d7802caeSToomas Soome cmd[6] = NULL; 303d7802caeSToomas Soome 304d7802caeSToomas Soome if (posix_spawn(&pid, cmd[0], &file_actions, &attr, cmd, NULL)) 305d7802caeSToomas Soome return (false); 306d7802caeSToomas Soome (void) posix_spawnattr_destroy(&attr); 307d7802caeSToomas Soome (void) posix_spawn_file_actions_destroy(&file_actions); 308d7802caeSToomas Soome 309d7802caeSToomas Soome do { 310d7802caeSToomas Soome w = waitpid(pid, &status, 0); 311d7802caeSToomas Soome } while (w == -1 && errno == EINTR); 312d7802caeSToomas Soome if (w == -1) 313d7802caeSToomas Soome status = -1; 314d7802caeSToomas Soome 315d7802caeSToomas Soome return (status != -1); 316d7802caeSToomas Soome } 317d7802caeSToomas Soome 318d7802caeSToomas Soome static void 319d7802caeSToomas Soome install_esp_cb(void *data, struct partlist *plist) 320d7802caeSToomas Soome { 321d7802caeSToomas Soome fstyp_handle_t fhdl; 322d7802caeSToomas Soome const char *fident; 323d7802caeSToomas Soome bool pcfs; 324d7802caeSToomas Soome char *blkdev, *path, *file; 325d7802caeSToomas Soome FILE *fp; 326d7802caeSToomas Soome struct mnttab mp, mpref = { 0 }; 327d7802caeSToomas Soome ib_bootblock_t *bblock = plist->pl_src_data; 328d7802caeSToomas Soome int fd, ret; 329d7802caeSToomas Soome 330d7802caeSToomas Soome if ((fd = open_device(plist->pl_devname)) == -1) 331d7802caeSToomas Soome return; 332d7802caeSToomas Soome 333d7802caeSToomas Soome if (fstyp_init(fd, 0, NULL, &fhdl) != 0) { 334d7802caeSToomas Soome (void) close(fd); 335d7802caeSToomas Soome return; 336d7802caeSToomas Soome } 337d7802caeSToomas Soome 338d7802caeSToomas Soome pcfs = false; 339d7802caeSToomas Soome if (fstyp_ident(fhdl, NULL, &fident) == 0) { 340d7802caeSToomas Soome if (strcmp(fident, MNTTYPE_PCFS) == 0) 341d7802caeSToomas Soome pcfs = true; 342d7802caeSToomas Soome } 343d7802caeSToomas Soome fstyp_fini(fhdl); 344d7802caeSToomas Soome (void) close(fd); 345d7802caeSToomas Soome 346d7802caeSToomas Soome if (!pcfs) { 347d7802caeSToomas Soome (void) printf(gettext("Creating pcfs on ESP %s\n"), 348d7802caeSToomas Soome plist->pl_devname); 349d7802caeSToomas Soome 350d7802caeSToomas Soome if (!mkfs_pcfs(plist->pl_devname)) { 351d7802caeSToomas Soome (void) fprintf(stderr, gettext("mkfs -F pcfs failed " 352d7802caeSToomas Soome "on %s\n"), plist->pl_devname); 353d7802caeSToomas Soome return; 354d7802caeSToomas Soome } 355d7802caeSToomas Soome } 356d7802caeSToomas Soome blkdev = make_blkdev(plist->pl_devname); 357d7802caeSToomas Soome if (blkdev == NULL) 358d7802caeSToomas Soome return; 359d7802caeSToomas Soome 360d7802caeSToomas Soome fp = fopen(MNTTAB, "r"); 361d7802caeSToomas Soome if (fp == NULL) { 362d7802caeSToomas Soome perror("fopen"); 363d7802caeSToomas Soome free(blkdev); 364d7802caeSToomas Soome return; 365d7802caeSToomas Soome } 366d7802caeSToomas Soome 367d7802caeSToomas Soome mpref.mnt_special = blkdev; 368d7802caeSToomas Soome ret = getmntany(fp, &mp, &mpref); 369d7802caeSToomas Soome (void) fclose(fp); 370d7802caeSToomas Soome if (ret == 0) 371d7802caeSToomas Soome path = mp.mnt_mountp; 372d7802caeSToomas Soome else 373d7802caeSToomas Soome path = stagefs_mount(blkdev, plist); 374d7802caeSToomas Soome 375d7802caeSToomas Soome free(blkdev); 376d7802caeSToomas Soome if (path == NULL) 377d7802caeSToomas Soome return; 378d7802caeSToomas Soome 379d7802caeSToomas Soome if (asprintf(&file, "%s%s", path, "/EFI") < 0) { 3800c946d80SToomas Soome perror(gettext("Memory allocation failure")); 381d7802caeSToomas Soome return; 3820c946d80SToomas Soome } 3830c946d80SToomas Soome 384d7802caeSToomas Soome ret = mkdir(file, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); 385d7802caeSToomas Soome if (ret == 0 || errno == EEXIST) { 386d7802caeSToomas Soome free(file); 387d7802caeSToomas Soome if (asprintf(&file, "%s%s", path, "/EFI/Boot") < 0) { 388d7802caeSToomas Soome perror(gettext("Memory allocation failure")); 389d7802caeSToomas Soome return; 390d7802caeSToomas Soome } 391d7802caeSToomas Soome ret = mkdir(file, 392d7802caeSToomas Soome S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); 393d7802caeSToomas Soome if (errno == EEXIST) 394d7802caeSToomas Soome ret = 0; 395d7802caeSToomas Soome } 396d7802caeSToomas Soome free(file); 397d7802caeSToomas Soome if (ret < 0) { 398d7802caeSToomas Soome perror("mkdir"); 399d7802caeSToomas Soome return; 4000c946d80SToomas Soome } 4010c946d80SToomas Soome 402d7802caeSToomas Soome if (asprintf(&file, "%s%s", path, plist->pl_device->stage.path) < 0) { 403d7802caeSToomas Soome perror(gettext("Memory allocation failure")); 404d7802caeSToomas Soome return; 405d7802caeSToomas Soome } 406d7802caeSToomas Soome 407d7802caeSToomas Soome /* Write stage file. Should create temp file and rename. */ 408d7802caeSToomas Soome (void) chmod(file, S_IRUSR | S_IWUSR); 409d7802caeSToomas Soome fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); 410d7802caeSToomas Soome if (fd != -1) { 411d7802caeSToomas Soome ret = write_out(fd, bblock->buf, bblock->buf_size, 0); 412d7802caeSToomas Soome if (ret == BC_SUCCESS) { 413d7802caeSToomas Soome (void) fprintf(stdout, 414d7802caeSToomas Soome gettext("bootblock written to %s\n"), file); 415d7802caeSToomas Soome } else { 416d7802caeSToomas Soome (void) fprintf(stdout, 417d7802caeSToomas Soome gettext("error while writing %s\n"), file); 418d7802caeSToomas Soome } 419d7802caeSToomas Soome (void) fchmod(fd, S_IRUSR | S_IRGRP | S_IROTH); 420d7802caeSToomas Soome (void) close(fd); 421d7802caeSToomas Soome } 422d7802caeSToomas Soome free(file); 423d7802caeSToomas Soome } 424d7802caeSToomas Soome 425d7802caeSToomas Soome /* 426d7802caeSToomas Soome * MBR setup only depends on write_mbr toggle. 427d7802caeSToomas Soome */ 428d7802caeSToomas Soome static bool 429d7802caeSToomas Soome compare_mbr_cb(struct partlist *plist) 430d7802caeSToomas Soome { 431d7802caeSToomas Soome /* get confirmation for -m */ 432d7802caeSToomas Soome if (write_mbr && !force_mbr) { 433d7802caeSToomas Soome (void) fprintf(stdout, gettext("Updating master boot sector " 434d7802caeSToomas Soome "destroys existing boot managers (if any).\n" 435d7802caeSToomas Soome "continue (y/n)? ")); 436d7802caeSToomas Soome if (!yes()) { 437d7802caeSToomas Soome write_mbr = false; 438d7802caeSToomas Soome (void) fprintf(stdout, gettext("master boot sector " 439d7802caeSToomas Soome "not updated\n")); 440d7802caeSToomas Soome } 441d7802caeSToomas Soome } 442d7802caeSToomas Soome if (write_mbr) 443d7802caeSToomas Soome (void) printf("%s is newer than one in %s\n", 444d7802caeSToomas Soome plist->pl_src_name, plist->pl_devname); 445d7802caeSToomas Soome return (write_mbr); 446d7802caeSToomas Soome } 447d7802caeSToomas Soome 448d7802caeSToomas Soome /* 449d7802caeSToomas Soome * VBR setup is always done. 450d7802caeSToomas Soome */ 451d7802caeSToomas Soome static bool 452d7802caeSToomas Soome compare_stage1_cb(struct partlist *plist) 453d7802caeSToomas Soome { 454d7802caeSToomas Soome (void) printf("%s will be written to %s\n", plist->pl_src_name, 455d7802caeSToomas Soome plist->pl_devname); 456d7802caeSToomas Soome return (true); 457d7802caeSToomas Soome } 458d7802caeSToomas Soome 459d7802caeSToomas Soome /* 460d7802caeSToomas Soome * Return true if we can update, false if not. 461d7802caeSToomas Soome */ 462d7802caeSToomas Soome static bool 463d7802caeSToomas Soome compare_einfo_cb(struct partlist *plist) 464d7802caeSToomas Soome { 465d7802caeSToomas Soome ib_bootblock_t *bblock, *bblock_file; 466d7802caeSToomas Soome bblk_einfo_t *einfo, *einfo_file; 467d7802caeSToomas Soome bblk_hs_t bblock_hs; 468d7802caeSToomas Soome bool rv; 469d7802caeSToomas Soome 470*46d70dceSToomas Soome bblock_file = plist->pl_src_data; 471*46d70dceSToomas Soome if (bblock_file == NULL) 472*46d70dceSToomas Soome return (false); /* source is missing, cannot update */ 473*46d70dceSToomas Soome 474d7802caeSToomas Soome bblock = plist->pl_stage; 475d7802caeSToomas Soome if (bblock == NULL || bblock->extra == NULL || bblock->extra_size == 0) 476d7802caeSToomas Soome return (true); 477d7802caeSToomas Soome 478d7802caeSToomas Soome einfo = find_einfo(bblock->extra, bblock->extra_size); 479d7802caeSToomas Soome if (einfo == NULL) { 480d7802caeSToomas Soome BOOT_DEBUG("No extended information available on disk\n"); 481d7802caeSToomas Soome return (true); 482d7802caeSToomas Soome } 483d7802caeSToomas Soome 484d7802caeSToomas Soome einfo_file = find_einfo(bblock_file->extra, bblock_file->extra_size); 485d7802caeSToomas Soome if (einfo_file == NULL) { 486d7802caeSToomas Soome /* 487d7802caeSToomas Soome * loader bootblock is versioned. missing version means 488d7802caeSToomas Soome * probably incompatible block. installboot can not install 489d7802caeSToomas Soome * grub, for example. 490d7802caeSToomas Soome */ 4910c946d80SToomas Soome (void) fprintf(stderr, 492d7802caeSToomas Soome gettext("ERROR: non versioned bootblock in file\n")); 493d7802caeSToomas Soome return (false); 494d7802caeSToomas Soome } else { 495d7802caeSToomas Soome if (update_str == NULL) { 496d7802caeSToomas Soome update_str = einfo_get_string(einfo_file); 497d7802caeSToomas Soome do_version = true; 498d7802caeSToomas Soome } 4990c946d80SToomas Soome } 5000c946d80SToomas Soome 501d7802caeSToomas Soome if (!do_version || update_str == NULL) { 502d7802caeSToomas Soome (void) fprintf(stderr, 503d7802caeSToomas Soome gettext("WARNING: target device %s has a " 504d7802caeSToomas Soome "versioned bootblock that is going to be overwritten by a " 505d7802caeSToomas Soome "non versioned one\n"), plist->pl_devname); 506d7802caeSToomas Soome return (true); 507d7802caeSToomas Soome } 5080c946d80SToomas Soome 509d7802caeSToomas Soome if (force_update) { 510d7802caeSToomas Soome BOOT_DEBUG("Forcing update of %s bootblock\n", 511d7802caeSToomas Soome plist->pl_devname); 512d7802caeSToomas Soome return (true); 513d7802caeSToomas Soome } 5140c946d80SToomas Soome 515d7802caeSToomas Soome BOOT_DEBUG("Ready to check installed version vs %s\n", update_str); 5160c946d80SToomas Soome 517d7802caeSToomas Soome bblock_hs.src_buf = (unsigned char *)bblock_file->file; 518d7802caeSToomas Soome bblock_hs.src_size = bblock_file->file_size; 519d7802caeSToomas Soome 520d7802caeSToomas Soome rv = einfo_should_update(einfo, &bblock_hs, update_str); 521d7802caeSToomas Soome if (rv == false) { 522d7802caeSToomas Soome (void) fprintf(stderr, gettext("\nBootblock version installed " 523d7802caeSToomas Soome "on %s is more recent or identical to\n%s\n" 524d7802caeSToomas Soome "Use -F to override or install without the -u option.\n"), 525d7802caeSToomas Soome plist->pl_devname, plist->pl_src_name); 526d7802caeSToomas Soome } else { 527d7802caeSToomas Soome (void) printf("%s is newer than one in %s\n", 528d7802caeSToomas Soome plist->pl_src_name, plist->pl_devname); 529d7802caeSToomas Soome } 530d7802caeSToomas Soome return (rv); 531d7802caeSToomas Soome } 532d7802caeSToomas Soome 533d7802caeSToomas Soome static bool 534d7802caeSToomas Soome read_stage1_cb(struct partlist *plist) 535d7802caeSToomas Soome { 536d7802caeSToomas Soome int fd; 537d7802caeSToomas Soome bool rv = false; 538d7802caeSToomas Soome 539d7802caeSToomas Soome if ((fd = open_device(plist->pl_devname)) == -1) 540d7802caeSToomas Soome return (rv); 541d7802caeSToomas Soome 542d7802caeSToomas Soome if (plist->pl_stage == NULL) 543d7802caeSToomas Soome plist->pl_stage = calloc(1, sector_size); 544d7802caeSToomas Soome 545d7802caeSToomas Soome if (plist->pl_stage == NULL) { 546d7802caeSToomas Soome perror("calloc"); 547d7802caeSToomas Soome goto done; 548d7802caeSToomas Soome } 5490c946d80SToomas Soome 550d7802caeSToomas Soome if (pread(fd, plist->pl_stage, sector_size, 0) == -1) { 551d7802caeSToomas Soome perror("pread"); 552d7802caeSToomas Soome goto done; 553d7802caeSToomas Soome } 554d7802caeSToomas Soome rv = true; 555d7802caeSToomas Soome done: 5560c946d80SToomas Soome (void) close(fd); 557d7802caeSToomas Soome return (rv); 558d7802caeSToomas Soome } 5590c946d80SToomas Soome 560d7802caeSToomas Soome static bool 561d7802caeSToomas Soome read_stage1_bbl_cb(struct partlist *plist) 562d7802caeSToomas Soome { 563d7802caeSToomas Soome int fd; 564d7802caeSToomas Soome void *data; 565d7802caeSToomas Soome bool rv = false; 566d7802caeSToomas Soome 567d7802caeSToomas Soome data = malloc(SECTOR_SIZE); 568d7802caeSToomas Soome if (data == NULL) 569d7802caeSToomas Soome return (rv); 570d7802caeSToomas Soome 571d7802caeSToomas Soome /* read the stage1 file from filesystem */ 572d7802caeSToomas Soome fd = open(plist->pl_src_name, O_RDONLY); 573d7802caeSToomas Soome if (fd == -1 || 574d7802caeSToomas Soome read(fd, data, SECTOR_SIZE) != SECTOR_SIZE) { 575d7802caeSToomas Soome (void) fprintf(stderr, gettext("cannot read stage1 file %s\n"), 576d7802caeSToomas Soome plist->pl_src_name); 577d7802caeSToomas Soome free(data); 578d7802caeSToomas Soome if (fd != -1) 579d7802caeSToomas Soome (void) close(fd); 580d7802caeSToomas Soome return (rv); 581d7802caeSToomas Soome } 582d7802caeSToomas Soome 583d7802caeSToomas Soome plist->pl_src_data = data; 5840c946d80SToomas Soome (void) close(fd); 585d7802caeSToomas Soome return (true); 5860c946d80SToomas Soome } 5870c946d80SToomas Soome 588d7802caeSToomas Soome static bool 589d7802caeSToomas Soome read_stage2_cb(struct partlist *plist) 5900c946d80SToomas Soome { 591d7802caeSToomas Soome ib_device_t *device; 592d7802caeSToomas Soome ib_bootblock_t *bblock; 593d7802caeSToomas Soome int fd; 5940c946d80SToomas Soome uint32_t size, offset; 5950c946d80SToomas Soome uint32_t buf_size; 5960c946d80SToomas Soome uint32_t mboot_off; 5970c946d80SToomas Soome multiboot_header_t *mboot; 5980c946d80SToomas Soome 599d7802caeSToomas Soome bblock = calloc(1, sizeof (ib_bootblock_t)); 600d7802caeSToomas Soome if (bblock == NULL) 601d7802caeSToomas Soome return (false); 6020c946d80SToomas Soome 603d7802caeSToomas Soome if ((fd = open_device(plist->pl_devname)) == -1) { 604d7802caeSToomas Soome free(bblock); 605d7802caeSToomas Soome return (false); 6060c946d80SToomas Soome } 6070c946d80SToomas Soome 608d7802caeSToomas Soome device = plist->pl_device; 609d7802caeSToomas Soome plist->pl_stage = bblock; 610d7802caeSToomas Soome offset = device->stage.offset * SECTOR_SIZE; 611d7802caeSToomas Soome 612d7802caeSToomas Soome if (read_in(fd, mboot_scan, sizeof (mboot_scan), offset) 6130c946d80SToomas Soome != BC_SUCCESS) { 6140c946d80SToomas Soome BOOT_DEBUG("Error reading bootblock area\n"); 6150c946d80SToomas Soome perror("read"); 616d7802caeSToomas Soome (void) close(fd); 617d7802caeSToomas Soome return (false); 6180c946d80SToomas Soome } 6190c946d80SToomas Soome 6200c946d80SToomas Soome /* No multiboot means no chance of knowing bootblock size */ 6210c946d80SToomas Soome if (find_multiboot(mboot_scan, sizeof (mboot_scan), &mboot_off) 6220c946d80SToomas Soome != BC_SUCCESS) { 6230c946d80SToomas Soome BOOT_DEBUG("Unable to find multiboot header\n"); 624d7802caeSToomas Soome (void) close(fd); 625d7802caeSToomas Soome return (false); 6260c946d80SToomas Soome } 6270c946d80SToomas Soome mboot = (multiboot_header_t *)(mboot_scan + mboot_off); 6280c946d80SToomas Soome 6290c946d80SToomas Soome /* 6300c946d80SToomas Soome * make sure mboot has sane values 6310c946d80SToomas Soome */ 6320c946d80SToomas Soome if (mboot->load_end_addr == 0 || 633d7802caeSToomas Soome mboot->load_end_addr < mboot->load_addr) { 634d7802caeSToomas Soome (void) close(fd); 635d7802caeSToomas Soome return (false); 636d7802caeSToomas Soome } 6370c946d80SToomas Soome 6380c946d80SToomas Soome /* 6390c946d80SToomas Soome * Currently, the amount of space reserved for extra information 6400c946d80SToomas Soome * is "fixed". We may have to scan for the terminating extra payload 6410c946d80SToomas Soome * in the future. 6420c946d80SToomas Soome */ 6430c946d80SToomas Soome size = mboot->load_end_addr - mboot->load_addr; 6440c946d80SToomas Soome buf_size = P2ROUNDUP(size + SECTOR_SIZE, SECTOR_SIZE); 6450c946d80SToomas Soome bblock->file_size = size; 6460c946d80SToomas Soome 6470c946d80SToomas Soome bblock->buf = malloc(buf_size); 6480c946d80SToomas Soome if (bblock->buf == NULL) { 6490c946d80SToomas Soome BOOT_DEBUG("Unable to allocate enough memory to read" 6500c946d80SToomas Soome " the extra bootblock from the disk\n"); 6510c946d80SToomas Soome perror(gettext("Memory allocation failure")); 652d7802caeSToomas Soome (void) close(fd); 653d7802caeSToomas Soome return (false); 6540c946d80SToomas Soome } 6550c946d80SToomas Soome bblock->buf_size = buf_size; 6560c946d80SToomas Soome 657d7802caeSToomas Soome if (read_in(fd, bblock->buf, buf_size, offset) != BC_SUCCESS) { 6580c946d80SToomas Soome BOOT_DEBUG("Error reading the bootblock\n"); 6590c946d80SToomas Soome (void) free(bblock->buf); 6600c946d80SToomas Soome bblock->buf = NULL; 661d7802caeSToomas Soome (void) close(fd); 662d7802caeSToomas Soome return (false); 6630c946d80SToomas Soome } 6640c946d80SToomas Soome 6650c946d80SToomas Soome /* Update pointers. */ 6660c946d80SToomas Soome bblock->file = bblock->buf; 6670c946d80SToomas Soome bblock->mboot_off = mboot_off; 6680c946d80SToomas Soome bblock->mboot = (multiboot_header_t *)(bblock->buf + bblock->mboot_off); 6690c946d80SToomas Soome bblock->extra = bblock->buf + P2ROUNDUP(bblock->file_size, 8); 6700c946d80SToomas Soome bblock->extra_size = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8); 6710c946d80SToomas Soome 6720c946d80SToomas Soome BOOT_DEBUG("mboot at %p offset %d, extra at %p size %d, buf=%p " 6730c946d80SToomas Soome "(size=%d)\n", bblock->mboot, bblock->mboot_off, bblock->extra, 6740c946d80SToomas Soome bblock->extra_size, bblock->buf, bblock->buf_size); 6750c946d80SToomas Soome 676d7802caeSToomas Soome return (true); 6770c946d80SToomas Soome } 6780c946d80SToomas Soome 679d7802caeSToomas Soome static bool 680d7802caeSToomas Soome read_einfo_file_cb(struct partlist *plist) 6810c946d80SToomas Soome { 682*46d70dceSToomas Soome int rc; 683*46d70dceSToomas Soome void *stage; 684*46d70dceSToomas Soome 685*46d70dceSToomas Soome stage = calloc(1, sizeof (ib_bootblock_t)); 686*46d70dceSToomas Soome if (stage == NULL) 687d7802caeSToomas Soome return (false); 6880c946d80SToomas Soome 689*46d70dceSToomas Soome rc = read_bootblock_from_file(plist->pl_devname, stage); 690*46d70dceSToomas Soome if (rc != BC_SUCCESS) { 691*46d70dceSToomas Soome free(stage); 692*46d70dceSToomas Soome stage = NULL; 693*46d70dceSToomas Soome } 694*46d70dceSToomas Soome plist->pl_stage = stage; 695*46d70dceSToomas Soome return (rc == BC_SUCCESS); 696d7802caeSToomas Soome } 6970c946d80SToomas Soome 698d7802caeSToomas Soome static bool 699d7802caeSToomas Soome read_stage2_file_cb(struct partlist *plist) 700d7802caeSToomas Soome { 701*46d70dceSToomas Soome int rc; 702*46d70dceSToomas Soome void *data; 703*46d70dceSToomas Soome 704*46d70dceSToomas Soome data = calloc(1, sizeof (ib_bootblock_t)); 705*46d70dceSToomas Soome if (data == NULL) 706d7802caeSToomas Soome return (false); 7070c946d80SToomas Soome 708*46d70dceSToomas Soome rc = read_bootblock_from_file(plist->pl_src_name, data); 709*46d70dceSToomas Soome if (rc != BC_SUCCESS) { 710*46d70dceSToomas Soome free(data); 711*46d70dceSToomas Soome data = NULL; 712*46d70dceSToomas Soome } 713*46d70dceSToomas Soome plist->pl_src_data = data; 714*46d70dceSToomas Soome return (rc == BC_SUCCESS); 715d7802caeSToomas Soome } 7160c946d80SToomas Soome 717d7802caeSToomas Soome /* 718d7802caeSToomas Soome * convert /dev/rdsk/... to /dev/dsk/... 719d7802caeSToomas Soome */ 720d7802caeSToomas Soome static char * 721d7802caeSToomas Soome make_blkdev(const char *path) 722d7802caeSToomas Soome { 723d7802caeSToomas Soome char *tmp; 724d7802caeSToomas Soome char *ptr = strdup(path); 7250c946d80SToomas Soome 726d7802caeSToomas Soome if (ptr == NULL) 727d7802caeSToomas Soome return (ptr); 7280c946d80SToomas Soome 729d7802caeSToomas Soome tmp = strstr(ptr, "rdsk"); 730d7802caeSToomas Soome if (tmp == NULL) { 731d7802caeSToomas Soome free(ptr); 732d7802caeSToomas Soome return (NULL); /* Something is very wrong */ 7330c946d80SToomas Soome } 734d7802caeSToomas Soome /* This is safe because we do shorten the string */ 735d7802caeSToomas Soome (void) memmove(tmp, tmp + 1, strlen(tmp)); 736d7802caeSToomas Soome return (ptr); 737d7802caeSToomas Soome } 7380c946d80SToomas Soome 739d7802caeSToomas Soome /* 740d7802caeSToomas Soome * Try to mount ESP and read boot program. 741d7802caeSToomas Soome */ 742d7802caeSToomas Soome static bool 743d7802caeSToomas Soome read_einfo_esp_cb(struct partlist *plist) 744d7802caeSToomas Soome { 745d7802caeSToomas Soome fstyp_handle_t fhdl; 746d7802caeSToomas Soome const char *fident; 747d7802caeSToomas Soome char *blkdev, *path, *file; 748d7802caeSToomas Soome bool rv = false; 749d7802caeSToomas Soome FILE *fp; 750d7802caeSToomas Soome struct mnttab mp, mpref = { 0 }; 751d7802caeSToomas Soome int fd, ret; 7520c946d80SToomas Soome 753d7802caeSToomas Soome if ((fd = open_device(plist->pl_devname)) == -1) 754d7802caeSToomas Soome return (rv); 7550c946d80SToomas Soome 756d7802caeSToomas Soome if (fstyp_init(fd, 0, NULL, &fhdl) != 0) { 757d7802caeSToomas Soome (void) close(fd); 758d7802caeSToomas Soome return (rv); 759d7802caeSToomas Soome } 7600c946d80SToomas Soome 761d7802caeSToomas Soome if (fstyp_ident(fhdl, NULL, &fident) != 0) { 762d7802caeSToomas Soome fstyp_fini(fhdl); 763d7802caeSToomas Soome (void) close(fd); 764d7802caeSToomas Soome (void) fprintf(stderr, gettext("Failed to detect file " 765d7802caeSToomas Soome "system type\n")); 766d7802caeSToomas Soome return (rv); 767d7802caeSToomas Soome } 7680c946d80SToomas Soome 769d7802caeSToomas Soome /* We only do expect pcfs. */ 770d7802caeSToomas Soome if (strcmp(fident, MNTTYPE_PCFS) != 0) { 771d7802caeSToomas Soome (void) fprintf(stderr, 772d7802caeSToomas Soome gettext("File system %s is not supported.\n"), fident); 773d7802caeSToomas Soome fstyp_fini(fhdl); 774d7802caeSToomas Soome (void) close(fd); 775d7802caeSToomas Soome return (rv); 776d7802caeSToomas Soome } 777d7802caeSToomas Soome fstyp_fini(fhdl); 778d7802caeSToomas Soome (void) close(fd); 779d7802caeSToomas Soome 780d7802caeSToomas Soome blkdev = make_blkdev(plist->pl_devname); 781d7802caeSToomas Soome if (blkdev == NULL) 782d7802caeSToomas Soome return (rv); 783d7802caeSToomas Soome 784d7802caeSToomas Soome /* mount ESP if needed, read boot program(s) and unmount. */ 785d7802caeSToomas Soome fp = fopen(MNTTAB, "r"); 786d7802caeSToomas Soome if (fp == NULL) { 787d7802caeSToomas Soome perror("fopen"); 788d7802caeSToomas Soome free(blkdev); 789d7802caeSToomas Soome return (rv); 7900c946d80SToomas Soome } 7910c946d80SToomas Soome 792d7802caeSToomas Soome mpref.mnt_special = blkdev; 793d7802caeSToomas Soome ret = getmntany(fp, &mp, &mpref); 794d7802caeSToomas Soome (void) fclose(fp); 795d7802caeSToomas Soome if (ret == 0) 796d7802caeSToomas Soome path = mp.mnt_mountp; 797d7802caeSToomas Soome else 798d7802caeSToomas Soome path = stagefs_mount(blkdev, plist); 799d7802caeSToomas Soome 800d7802caeSToomas Soome free(blkdev); 801d7802caeSToomas Soome if (path == NULL) 802d7802caeSToomas Soome return (rv); 803d7802caeSToomas Soome 804d7802caeSToomas Soome if (asprintf(&file, "%s%s", path, plist->pl_device->stage.path) < 0) { 805d7802caeSToomas Soome return (rv); 806d7802caeSToomas Soome } 807d7802caeSToomas Soome 808d7802caeSToomas Soome plist->pl_stage = calloc(1, sizeof (ib_bootblock_t)); 809d7802caeSToomas Soome if (plist->pl_stage == NULL) { 810d7802caeSToomas Soome free(file); 811d7802caeSToomas Soome return (rv); 812d7802caeSToomas Soome } 813d7802caeSToomas Soome if (read_bootblock_from_file(file, plist->pl_stage) != BC_SUCCESS) { 814d7802caeSToomas Soome free(plist->pl_stage); 815d7802caeSToomas Soome plist->pl_stage = NULL; 816d7802caeSToomas Soome } else { 817d7802caeSToomas Soome rv = true; 818d7802caeSToomas Soome } 819d7802caeSToomas Soome 820d7802caeSToomas Soome free(file); 821d7802caeSToomas Soome return (rv); 8220c946d80SToomas Soome } 8230c946d80SToomas Soome 824d7802caeSToomas Soome static void 825d7802caeSToomas Soome print_stage1_cb(struct partlist *plist) 8260c946d80SToomas Soome { 827d7802caeSToomas Soome struct mboot *mbr; 828d7802caeSToomas Soome struct ipart *part; 829d7802caeSToomas Soome mbr_type_t type = MBR_TYPE_UNKNOWN; 830d7802caeSToomas Soome bool pmbr = false; 831d7802caeSToomas Soome char *label; 8320c946d80SToomas Soome 833d7802caeSToomas Soome mbr = plist->pl_stage; 8340c946d80SToomas Soome 835d7802caeSToomas Soome if (*((uint16_t *)&mbr->bootinst[GRUB_VERSION_OFF]) == GRUB_VERSION) { 836d7802caeSToomas Soome type = MBR_TYPE_GRUB1; 837d7802caeSToomas Soome } else if (mbr->bootinst[STAGE1_MBR_VERSION] == LOADER_VERSION) { 838d7802caeSToomas Soome type = MBR_TYPE_LOADER; 839d7802caeSToomas Soome } else if (mbr->bootinst[STAGE1_MBR_VERSION] == LOADER_JOYENT_VERSION) { 840d7802caeSToomas Soome type = MBR_TYPE_LOADER_JOYENT; 841d7802caeSToomas Soome } 8420c946d80SToomas Soome 843d7802caeSToomas Soome part = (struct ipart *)mbr->parts; 844d7802caeSToomas Soome for (int i = 0; i < FD_NUMPART; i++) { 845d7802caeSToomas Soome if (part[i].systid == EFI_PMBR) 846d7802caeSToomas Soome pmbr = true; 847d7802caeSToomas Soome } 8480c946d80SToomas Soome 849d7802caeSToomas Soome if (plist->pl_type == IB_BBLK_MBR) 850d7802caeSToomas Soome label = pmbr ? "PMBR" : "MBR"; 851d7802caeSToomas Soome else 852d7802caeSToomas Soome label = "VBR"; 8530c946d80SToomas Soome 854d7802caeSToomas Soome printf("%s block from %s:\n", label, plist->pl_devname); 8550c946d80SToomas Soome 856d7802caeSToomas Soome switch (type) { 857d7802caeSToomas Soome case MBR_TYPE_UNKNOWN: 858d7802caeSToomas Soome printf("Format: unknown\n"); 859d7802caeSToomas Soome break; 860d7802caeSToomas Soome case MBR_TYPE_GRUB1: 861d7802caeSToomas Soome printf("Format: grub1\n"); 862d7802caeSToomas Soome break; 863d7802caeSToomas Soome case MBR_TYPE_LOADER: 864d7802caeSToomas Soome printf("Format: loader (illumos)\n"); 865d7802caeSToomas Soome break; 866d7802caeSToomas Soome case MBR_TYPE_LOADER_JOYENT: 867d7802caeSToomas Soome printf("Format: loader (joyent)\n"); 868d7802caeSToomas Soome break; 8690c946d80SToomas Soome } 8700c946d80SToomas Soome 871d7802caeSToomas Soome printf("Signature: 0x%hx (%s)\n", mbr->signature, 872d7802caeSToomas Soome mbr->signature == MBB_MAGIC ? "valid" : "invalid"); 8730c946d80SToomas Soome 874d7802caeSToomas Soome printf("UniqueMBRDiskSignature: %#lx\n", 875d7802caeSToomas Soome *(uint32_t *)&mbr->bootinst[STAGE1_SIG]); 876d7802caeSToomas Soome 877d7802caeSToomas Soome if (type == MBR_TYPE_LOADER || type == MBR_TYPE_LOADER_JOYENT) { 878d7802caeSToomas Soome char uuid[UUID_PRINTABLE_STRING_LENGTH]; 879d7802caeSToomas Soome 880d7802caeSToomas Soome printf("Loader STAGE1_STAGE2_LBA: %llu\n", 881d7802caeSToomas Soome *(uint64_t *)&mbr->bootinst[STAGE1_STAGE2_LBA]); 882d7802caeSToomas Soome 883d7802caeSToomas Soome printf("Loader STAGE1_STAGE2_SIZE: %hu\n", 884d7802caeSToomas Soome *(uint16_t *)&mbr->bootinst[STAGE1_STAGE2_SIZE]); 885d7802caeSToomas Soome 886d7802caeSToomas Soome uuid_unparse((uchar_t *)&mbr->bootinst[STAGE1_STAGE2_UUID], 887d7802caeSToomas Soome uuid); 888d7802caeSToomas Soome 889d7802caeSToomas Soome printf("Loader STAGE1_STAGE2_UUID: %s\n", uuid); 890d7802caeSToomas Soome } 891d7802caeSToomas Soome printf("\n"); 8920c946d80SToomas Soome } 8930c946d80SToomas Soome 894d7802caeSToomas Soome static void 895d7802caeSToomas Soome print_einfo_cb(struct partlist *plist) 8960c946d80SToomas Soome { 897d7802caeSToomas Soome uint8_t flags = 0; 898d7802caeSToomas Soome ib_bootblock_t *bblock; 899d7802caeSToomas Soome bblk_einfo_t *einfo = NULL; 900d7802caeSToomas Soome const char *filepath; 901d7802caeSToomas Soome 902d7802caeSToomas Soome /* No stage, get out. */ 903d7802caeSToomas Soome bblock = plist->pl_stage; 904d7802caeSToomas Soome if (bblock == NULL) 905d7802caeSToomas Soome return; 9060c946d80SToomas Soome 907d7802caeSToomas Soome if (plist->pl_device->stage.path == NULL) 908d7802caeSToomas Soome filepath = ""; 909d7802caeSToomas Soome else 910d7802caeSToomas Soome filepath = plist->pl_device->stage.path; 9110c946d80SToomas Soome 912d7802caeSToomas Soome printf("Boot block from %s:%s\n", plist->pl_devname, filepath); 9130c946d80SToomas Soome 914d7802caeSToomas Soome if (bblock->extra != NULL) 915d7802caeSToomas Soome einfo = find_einfo(bblock->extra, bblock->extra_size); 9160c946d80SToomas Soome 917d7802caeSToomas Soome if (einfo == NULL) { 918d7802caeSToomas Soome (void) fprintf(stderr, 919d7802caeSToomas Soome gettext("No extended information found.\n\n")); 920d7802caeSToomas Soome return; 921d7802caeSToomas Soome } 9220c946d80SToomas Soome 923d7802caeSToomas Soome /* Print the extended information. */ 924d7802caeSToomas Soome if (strip) 925d7802caeSToomas Soome flags |= EINFO_EASY_PARSE; 926d7802caeSToomas Soome if (verbose_dump) 927d7802caeSToomas Soome flags |= EINFO_PRINT_HEADER; 928d7802caeSToomas Soome 929d7802caeSToomas Soome print_einfo(flags, einfo, bblock->extra_size); 930d7802caeSToomas Soome printf("\n"); 9310c946d80SToomas Soome } 9320c946d80SToomas Soome 933d7802caeSToomas Soome static size_t 934d7802caeSToomas Soome get_media_info(int fd) 9350c946d80SToomas Soome { 936d7802caeSToomas Soome struct dk_minfo disk_info; 9370c946d80SToomas Soome 938d7802caeSToomas Soome if ((ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info)) == -1) 939d7802caeSToomas Soome return (SECTOR_SIZE); 9400c946d80SToomas Soome 941d7802caeSToomas Soome return (disk_info.dki_lbsize); 942d7802caeSToomas Soome } 943d7802caeSToomas Soome 944d7802caeSToomas Soome static struct partlist * 945d7802caeSToomas Soome partlist_alloc(void) 946d7802caeSToomas Soome { 947d7802caeSToomas Soome struct partlist *pl; 948d7802caeSToomas Soome 949d7802caeSToomas Soome if ((pl = calloc(1, sizeof (*pl))) == NULL) { 950d7802caeSToomas Soome perror("calloc"); 951d7802caeSToomas Soome return (NULL); 9520c946d80SToomas Soome } 9530c946d80SToomas Soome 954d7802caeSToomas Soome pl->pl_device = calloc(1, sizeof (*pl->pl_device)); 955d7802caeSToomas Soome if (pl->pl_device == NULL) { 956d7802caeSToomas Soome perror("calloc"); 957d7802caeSToomas Soome free(pl); 958d7802caeSToomas Soome return (NULL); 959d7802caeSToomas Soome } 960d7802caeSToomas Soome 961d7802caeSToomas Soome return (pl); 962d7802caeSToomas Soome } 963d7802caeSToomas Soome 964d7802caeSToomas Soome static void 965d7802caeSToomas Soome partlist_free(struct partlist *pl) 966d7802caeSToomas Soome { 967d7802caeSToomas Soome ib_bootblock_t *bblock; 968d7802caeSToomas Soome ib_device_t *device; 969d7802caeSToomas Soome 970d7802caeSToomas Soome switch (pl->pl_type) { 971d7802caeSToomas Soome case IB_BBLK_MBR: 972d7802caeSToomas Soome case IB_BBLK_STAGE1: 973d7802caeSToomas Soome free(pl->pl_stage); 974d7802caeSToomas Soome break; 975d7802caeSToomas Soome default: 976d7802caeSToomas Soome if (pl->pl_stage != NULL) { 977d7802caeSToomas Soome bblock = pl->pl_stage; 978d7802caeSToomas Soome free(bblock->buf); 979d7802caeSToomas Soome free(bblock); 9800c946d80SToomas Soome } 9810c946d80SToomas Soome } 982d7802caeSToomas Soome 983d7802caeSToomas Soome /* umount the stage fs. */ 984d7802caeSToomas Soome if (pl->pl_device->stage.mntpnt != NULL) { 985d7802caeSToomas Soome if (umount(pl->pl_device->stage.mntpnt) == 0) 986d7802caeSToomas Soome (void) rmdir(pl->pl_device->stage.mntpnt); 987d7802caeSToomas Soome free(pl->pl_device->stage.mntpnt); 9880c946d80SToomas Soome } 989d7802caeSToomas Soome device = pl->pl_device; 990d7802caeSToomas Soome free(device->target.path); 991d7802caeSToomas Soome free(pl->pl_device); 9920c946d80SToomas Soome 993d7802caeSToomas Soome free(pl->pl_src_data); 994d7802caeSToomas Soome free(pl->pl_devname); 995d7802caeSToomas Soome free(pl); 996d7802caeSToomas Soome } 9970c946d80SToomas Soome 998d7802caeSToomas Soome static bool 999d7802caeSToomas Soome probe_fstyp(ib_data_t *data) 1000d7802caeSToomas Soome { 1001d7802caeSToomas Soome fstyp_handle_t fhdl; 1002d7802caeSToomas Soome const char *fident; 1003d7802caeSToomas Soome char *ptr; 1004d7802caeSToomas Soome int fd; 1005d7802caeSToomas Soome bool rv = false; 1006d7802caeSToomas Soome 1007d7802caeSToomas Soome /* Record partition id */ 1008d7802caeSToomas Soome ptr = strrchr(data->target.path, 'p'); 1009d7802caeSToomas Soome if (ptr == NULL) 1010d7802caeSToomas Soome ptr = strrchr(data->target.path, 's'); 1011d7802caeSToomas Soome data->target.id = atoi(++ptr); 1012d7802caeSToomas Soome if ((fd = open_device(data->target.path)) == -1) 1013d7802caeSToomas Soome return (rv); 1014d7802caeSToomas Soome 1015d7802caeSToomas Soome if (fstyp_init(fd, 0, NULL, &fhdl) != 0) { 1016d7802caeSToomas Soome (void) close(fd); 1017d7802caeSToomas Soome return (rv); 1018d7802caeSToomas Soome } 1019d7802caeSToomas Soome 1020d7802caeSToomas Soome if (fstyp_ident(fhdl, NULL, &fident) != 0) { 1021d7802caeSToomas Soome fstyp_fini(fhdl); 1022d7802caeSToomas Soome (void) fprintf(stderr, gettext("Failed to detect file " 1023d7802caeSToomas Soome "system type\n")); 1024d7802caeSToomas Soome (void) close(fd); 1025d7802caeSToomas Soome return (rv); 1026d7802caeSToomas Soome } 1027d7802caeSToomas Soome 1028d7802caeSToomas Soome rv = true; 1029d7802caeSToomas Soome if (strcmp(fident, MNTTYPE_ZFS) == 0) 1030d7802caeSToomas Soome data->target.fstype = IB_FS_ZFS; 1031d7802caeSToomas Soome else if (strcmp(fident, MNTTYPE_UFS) == 0) { 1032d7802caeSToomas Soome data->target.fstype = IB_FS_UFS; 1033d7802caeSToomas Soome } else if (strcmp(fident, MNTTYPE_PCFS) == 0) { 1034d7802caeSToomas Soome data->target.fstype = IB_FS_PCFS; 1035d7802caeSToomas Soome } else { 1036d7802caeSToomas Soome (void) fprintf(stderr, gettext("File system %s is not " 1037d7802caeSToomas Soome "supported by loader\n"), fident); 1038d7802caeSToomas Soome rv = false; 1039d7802caeSToomas Soome } 1040d7802caeSToomas Soome fstyp_fini(fhdl); 1041d7802caeSToomas Soome (void) close(fd); 1042d7802caeSToomas Soome return (rv); 10430c946d80SToomas Soome } 10440c946d80SToomas Soome 1045d7802caeSToomas Soome static bool 1046d7802caeSToomas Soome get_slice(ib_data_t *data, struct partlist *pl, struct dk_gpt *vtoc, 1047d7802caeSToomas Soome uint16_t tag) 10480c946d80SToomas Soome { 1049d7802caeSToomas Soome uint_t i; 1050d7802caeSToomas Soome ib_device_t *device = pl->pl_device; 1051d7802caeSToomas Soome char *path, *ptr; 10520c946d80SToomas Soome 1053d7802caeSToomas Soome if (tag != V_BOOT && tag != V_SYSTEM) 1054d7802caeSToomas Soome return (false); 10550c946d80SToomas Soome 1056d7802caeSToomas Soome for (i = 0; i < vtoc->efi_nparts; i++) { 1057d7802caeSToomas Soome if (vtoc->efi_parts[i].p_tag == tag) { 1058d7802caeSToomas Soome if ((path = strdup(data->target.path)) == NULL) { 1059d7802caeSToomas Soome perror(gettext("Memory allocation failure")); 1060d7802caeSToomas Soome return (false); 1061d7802caeSToomas Soome } 1062d7802caeSToomas Soome ptr = strrchr(path, 's'); 1063d7802caeSToomas Soome ptr++; 1064d7802caeSToomas Soome *ptr = '\0'; 1065d7802caeSToomas Soome (void) asprintf(&ptr, "%s%d", path, i); 1066d7802caeSToomas Soome free(path); 1067d7802caeSToomas Soome if (ptr == NULL) { 1068d7802caeSToomas Soome perror(gettext("Memory allocation failure")); 1069d7802caeSToomas Soome return (false); 1070d7802caeSToomas Soome } 1071d7802caeSToomas Soome pl->pl_devname = ptr; 1072d7802caeSToomas Soome device->stage.id = i; 1073d7802caeSToomas Soome device->stage.devtype = IB_DEV_EFI; 1074d7802caeSToomas Soome switch (vtoc->efi_parts[i].p_tag) { 1075d7802caeSToomas Soome case V_BOOT: 1076d7802caeSToomas Soome device->stage.fstype = IB_FS_NONE; 1077d7802caeSToomas Soome /* leave sector 0 for VBR */ 1078d7802caeSToomas Soome device->stage.offset = 1; 1079d7802caeSToomas Soome break; 1080d7802caeSToomas Soome case V_SYSTEM: 1081d7802caeSToomas Soome device->stage.fstype = IB_FS_PCFS; 1082d7802caeSToomas Soome break; 1083d7802caeSToomas Soome } 1084d7802caeSToomas Soome device->stage.tag = vtoc->efi_parts[i].p_tag; 1085d7802caeSToomas Soome device->stage.start = vtoc->efi_parts[i].p_start; 1086d7802caeSToomas Soome device->stage.size = vtoc->efi_parts[i].p_size; 1087d7802caeSToomas Soome break; 10880c946d80SToomas Soome } 10890c946d80SToomas Soome } 1090d7802caeSToomas Soome return (true); 1091d7802caeSToomas Soome } 10920c946d80SToomas Soome 1093d7802caeSToomas Soome static bool 1094d7802caeSToomas Soome allocate_slice(ib_data_t *data, struct dk_gpt *vtoc, uint16_t tag, 1095d7802caeSToomas Soome struct partlist **plp) 1096d7802caeSToomas Soome { 1097d7802caeSToomas Soome struct partlist *pl; 10980c946d80SToomas Soome 1099d7802caeSToomas Soome *plp = NULL; 1100d7802caeSToomas Soome if ((pl = partlist_alloc()) == NULL) 1101d7802caeSToomas Soome return (false); 11020c946d80SToomas Soome 1103d7802caeSToomas Soome pl->pl_device = calloc(1, sizeof (*pl->pl_device)); 1104d7802caeSToomas Soome if (pl->pl_device == NULL) { 1105d7802caeSToomas Soome perror("calloc"); 1106d7802caeSToomas Soome partlist_free(pl); 1107d7802caeSToomas Soome return (false); 1108d7802caeSToomas Soome } 1109d7802caeSToomas Soome if (!get_slice(data, pl, vtoc, tag)) { 1110d7802caeSToomas Soome partlist_free(pl); 1111d7802caeSToomas Soome return (false); 11120c946d80SToomas Soome } 11130c946d80SToomas Soome 1114d7802caeSToomas Soome /* tag was not found */ 1115d7802caeSToomas Soome if (pl->pl_devname == NULL) 1116d7802caeSToomas Soome partlist_free(pl); 1117d7802caeSToomas Soome else 1118d7802caeSToomas Soome *plp = pl; 1119d7802caeSToomas Soome 1120d7802caeSToomas Soome return (true); 11210c946d80SToomas Soome } 11220c946d80SToomas Soome 1123d7802caeSToomas Soome static bool 1124d7802caeSToomas Soome probe_gpt(ib_data_t *data) 11250c946d80SToomas Soome { 1126d7802caeSToomas Soome struct partlist *pl; 1127d7802caeSToomas Soome struct dk_gpt *vtoc; 1128d7802caeSToomas Soome ib_device_t *device; 1129d7802caeSToomas Soome int slice, fd; 1130d7802caeSToomas Soome bool rv = false; 11310c946d80SToomas Soome 1132d7802caeSToomas Soome if ((fd = open_device(data->target.path)) < 0) 1133d7802caeSToomas Soome return (rv); 11340c946d80SToomas Soome 1135d7802caeSToomas Soome slice = efi_alloc_and_read(fd, &vtoc); 1136d7802caeSToomas Soome (void) close(fd); 1137d7802caeSToomas Soome if (slice < 0) 1138d7802caeSToomas Soome return (rv); 1139d7802caeSToomas Soome 1140d7802caeSToomas Soome data->device.devtype = IB_DEV_EFI; 1141d7802caeSToomas Soome data->target.start = vtoc->efi_parts[slice].p_start; 1142d7802caeSToomas Soome data->target.size = vtoc->efi_parts[slice].p_size; 11430c946d80SToomas Soome 1144d7802caeSToomas Soome /* Always update PMBR. */ 1145d7802caeSToomas Soome force_mbr = 1; 1146d7802caeSToomas Soome write_mbr = 1; 1147d7802caeSToomas Soome 1148d7802caeSToomas Soome /* 1149d7802caeSToomas Soome * With GPT we can have boot partition and ESP. 1150d7802caeSToomas Soome * Boot partition can have both stage 1 and stage 2. 1151d7802caeSToomas Soome */ 1152d7802caeSToomas Soome if (!allocate_slice(data, vtoc, V_BOOT, &pl)) 1153d7802caeSToomas Soome goto done; 1154d7802caeSToomas Soome if (pl != NULL) { 1155d7802caeSToomas Soome pl->pl_src_name = stage1; 1156d7802caeSToomas Soome pl->pl_type = IB_BBLK_STAGE1; 1157d7802caeSToomas Soome pl->pl_cb.compare = compare_stage1_cb; 1158d7802caeSToomas Soome pl->pl_cb.install = install_stage1_cb; 1159d7802caeSToomas Soome pl->pl_cb.read = read_stage1_cb; 1160d7802caeSToomas Soome pl->pl_cb.read_bbl = read_stage1_bbl_cb; 1161d7802caeSToomas Soome pl->pl_cb.print = print_stage1_cb; 1162d7802caeSToomas Soome STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1163d7802caeSToomas Soome } else if (data->target.fstype != IB_FS_ZFS) { 1164d7802caeSToomas Soome (void) fprintf(stderr, gettext("Booting %s from EFI " 1165d7802caeSToomas Soome "labeled disks requires the boot partition.\n"), 1166d7802caeSToomas Soome data->target.fstype == IB_FS_UFS? 1167d7802caeSToomas Soome MNTTYPE_UFS : MNTTYPE_PCFS); 1168d7802caeSToomas Soome goto done; 1169d7802caeSToomas Soome } 1170d7802caeSToomas Soome /* Add stage 2 */ 1171d7802caeSToomas Soome if (!allocate_slice(data, vtoc, V_BOOT, &pl)) 1172d7802caeSToomas Soome goto done; 1173d7802caeSToomas Soome if (pl != NULL) { 1174d7802caeSToomas Soome pl->pl_src_name = stage2; 1175d7802caeSToomas Soome pl->pl_type = IB_BBLK_STAGE2; 1176d7802caeSToomas Soome pl->pl_cb.compare = compare_einfo_cb; 1177d7802caeSToomas Soome pl->pl_cb.install = install_stage2_cb; 1178d7802caeSToomas Soome pl->pl_cb.read = read_stage2_cb; 1179d7802caeSToomas Soome pl->pl_cb.read_bbl = read_stage2_file_cb; 1180d7802caeSToomas Soome pl->pl_cb.print = print_einfo_cb; 1181d7802caeSToomas Soome STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1182d7802caeSToomas Soome } 1183d7802caeSToomas Soome 1184d7802caeSToomas Soome /* ESP can have 32- and 64-bit boot code. */ 1185d7802caeSToomas Soome if (!allocate_slice(data, vtoc, V_SYSTEM, &pl)) 1186d7802caeSToomas Soome goto done; 1187d7802caeSToomas Soome if (pl != NULL) { 1188d7802caeSToomas Soome pl->pl_device->stage.path = "/EFI/Boot/" BOOTIA32; 1189d7802caeSToomas Soome pl->pl_src_name = efi32; 1190d7802caeSToomas Soome pl->pl_type = IB_BBLK_EFI; 1191d7802caeSToomas Soome pl->pl_cb.compare = compare_einfo_cb; 1192d7802caeSToomas Soome pl->pl_cb.install = install_esp_cb; 1193d7802caeSToomas Soome pl->pl_cb.read = read_einfo_esp_cb; 1194d7802caeSToomas Soome pl->pl_cb.read_bbl = read_stage2_file_cb; 1195d7802caeSToomas Soome pl->pl_cb.print = print_einfo_cb; 1196d7802caeSToomas Soome STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1197d7802caeSToomas Soome } 1198d7802caeSToomas Soome if (!allocate_slice(data, vtoc, V_SYSTEM, &pl)) 1199d7802caeSToomas Soome goto done; 1200d7802caeSToomas Soome if (pl != NULL) { 1201d7802caeSToomas Soome pl->pl_device->stage.path = "/EFI/Boot/" BOOTX64; 1202d7802caeSToomas Soome pl->pl_src_name = efi64; 1203d7802caeSToomas Soome pl->pl_type = IB_BBLK_EFI; 1204d7802caeSToomas Soome pl->pl_cb.compare = compare_einfo_cb; 1205d7802caeSToomas Soome pl->pl_cb.install = install_esp_cb; 1206d7802caeSToomas Soome pl->pl_cb.read = read_einfo_esp_cb; 1207d7802caeSToomas Soome pl->pl_cb.read_bbl = read_stage2_file_cb; 1208d7802caeSToomas Soome pl->pl_cb.print = print_einfo_cb; 1209d7802caeSToomas Soome STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1210d7802caeSToomas Soome } 1211d7802caeSToomas Soome 1212d7802caeSToomas Soome /* add stage for our target file system slice */ 1213d7802caeSToomas Soome pl = partlist_alloc(); 1214d7802caeSToomas Soome if (pl == NULL) 1215d7802caeSToomas Soome goto done; 1216d7802caeSToomas Soome 1217d7802caeSToomas Soome device = pl->pl_device; 1218d7802caeSToomas Soome device->stage.devtype = data->device.devtype; 1219d7802caeSToomas Soome if ((pl->pl_devname = strdup(data->target.path)) == NULL) { 1220d7802caeSToomas Soome perror(gettext("Memory allocation failure")); 1221d7802caeSToomas Soome partlist_free(pl); 1222d7802caeSToomas Soome goto done; 12230c946d80SToomas Soome } 12240c946d80SToomas Soome 1225d7802caeSToomas Soome device->stage.id = slice; 1226d7802caeSToomas Soome device->stage.start = vtoc->efi_parts[slice].p_start; 1227d7802caeSToomas Soome device->stage.size = vtoc->efi_parts[slice].p_size; 12280c946d80SToomas Soome 1229d7802caeSToomas Soome /* ZFS and UFS can have stage1 in boot area. */ 1230d7802caeSToomas Soome if (data->target.fstype == IB_FS_ZFS || 1231d7802caeSToomas Soome data->target.fstype == IB_FS_UFS) { 1232d7802caeSToomas Soome pl->pl_src_name = stage1; 1233d7802caeSToomas Soome pl->pl_type = IB_BBLK_STAGE1; 1234d7802caeSToomas Soome pl->pl_cb.compare = compare_stage1_cb; 1235d7802caeSToomas Soome pl->pl_cb.install = install_stage1_cb; 1236d7802caeSToomas Soome pl->pl_cb.read = read_stage1_cb; 1237d7802caeSToomas Soome pl->pl_cb.read_bbl = read_stage1_bbl_cb; 1238d7802caeSToomas Soome pl->pl_cb.print = print_stage1_cb; 1239d7802caeSToomas Soome STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1240d7802caeSToomas Soome } 12410c946d80SToomas Soome 1242d7802caeSToomas Soome if (data->target.fstype == IB_FS_ZFS) { 1243d7802caeSToomas Soome pl = partlist_alloc(); 1244d7802caeSToomas Soome if (pl == NULL) 1245d7802caeSToomas Soome goto done; 12460c946d80SToomas Soome 1247d7802caeSToomas Soome device = pl->pl_device; 1248d7802caeSToomas Soome device->stage.devtype = data->device.devtype; 1249d7802caeSToomas Soome 1250d7802caeSToomas Soome if ((pl->pl_devname = strdup(data->target.path)) == NULL) { 1251d7802caeSToomas Soome perror(gettext("Memory allocation failure")); 1252d7802caeSToomas Soome goto done; 12530c946d80SToomas Soome } 12540c946d80SToomas Soome 1255d7802caeSToomas Soome device->stage.id = slice; 1256d7802caeSToomas Soome device->stage.start = vtoc->efi_parts[slice].p_start; 1257d7802caeSToomas Soome device->stage.size = vtoc->efi_parts[slice].p_size; 1258d7802caeSToomas Soome 1259d7802caeSToomas Soome device->stage.offset = BBLK_ZFS_BLK_OFF; 1260d7802caeSToomas Soome pl->pl_src_name = stage2; 1261d7802caeSToomas Soome pl->pl_type = IB_BBLK_STAGE2; 1262d7802caeSToomas Soome pl->pl_cb.compare = compare_einfo_cb; 1263d7802caeSToomas Soome pl->pl_cb.install = install_stage2_cb; 1264d7802caeSToomas Soome pl->pl_cb.read = read_stage2_cb; 1265d7802caeSToomas Soome pl->pl_cb.read_bbl = read_stage2_file_cb; 1266d7802caeSToomas Soome pl->pl_cb.print = print_einfo_cb; 1267d7802caeSToomas Soome STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1268d7802caeSToomas Soome } 1269d7802caeSToomas Soome rv = true; 1270d7802caeSToomas Soome done: 1271d7802caeSToomas Soome efi_free(vtoc); 1272d7802caeSToomas Soome return (rv); 1273d7802caeSToomas Soome } 12740c946d80SToomas Soome 1275d7802caeSToomas Soome static bool 1276d7802caeSToomas Soome get_start_sector(ib_data_t *data, struct extpartition *v_part, 1277d7802caeSToomas Soome diskaddr_t *start) 1278d7802caeSToomas Soome { 1279d7802caeSToomas Soome struct partlist *pl; 1280d7802caeSToomas Soome struct mboot *mbr; 1281d7802caeSToomas Soome struct ipart *part; 1282d7802caeSToomas Soome struct part_info dkpi; 1283d7802caeSToomas Soome struct extpart_info edkpi; 1284d7802caeSToomas Soome uint32_t secnum, numsec; 1285d7802caeSToomas Soome ext_part_t *epp; 1286d7802caeSToomas Soome ushort_t i; 1287d7802caeSToomas Soome int fd, rval, pno; 1288d7802caeSToomas Soome 1289d7802caeSToomas Soome if ((fd = open_device(data->target.path)) < 0) 1290d7802caeSToomas Soome return (false); 1291d7802caeSToomas Soome 1292d7802caeSToomas Soome if (ioctl(fd, DKIOCEXTPARTINFO, &edkpi) < 0) { 1293d7802caeSToomas Soome if (ioctl(fd, DKIOCPARTINFO, &dkpi) < 0) { 12940c946d80SToomas Soome (void) fprintf(stderr, gettext("cannot get the " 12950c946d80SToomas Soome "slice information of the disk\n")); 1296d7802caeSToomas Soome (void) close(fd); 1297d7802caeSToomas Soome return (false); 12980c946d80SToomas Soome } else { 12990c946d80SToomas Soome edkpi.p_start = dkpi.p_start; 13000c946d80SToomas Soome edkpi.p_length = dkpi.p_length; 13010c946d80SToomas Soome } 13020c946d80SToomas Soome } 1303d7802caeSToomas Soome (void) close(fd); 13040c946d80SToomas Soome 1305d7802caeSToomas Soome /* Set target file system start and size */ 1306d7802caeSToomas Soome data->target.start = edkpi.p_start; 1307d7802caeSToomas Soome data->target.size = edkpi.p_length; 13080c946d80SToomas Soome 1309d7802caeSToomas Soome /* This is our MBR partition start. */ 1310d7802caeSToomas Soome edkpi.p_start -= v_part->p_start; 13110c946d80SToomas Soome 1312d7802caeSToomas Soome /* Head is always MBR */ 1313d7802caeSToomas Soome pl = STAILQ_FIRST(data->plist); 1314d7802caeSToomas Soome if (!read_stage1_cb(pl)) 1315d7802caeSToomas Soome return (false); 13160c946d80SToomas Soome 1317d7802caeSToomas Soome mbr = (struct mboot *)pl->pl_stage; 1318d7802caeSToomas Soome part = (struct ipart *)mbr->parts; 13190c946d80SToomas Soome 1320d7802caeSToomas Soome for (i = 0; i < FD_NUMPART; i++) { 1321d7802caeSToomas Soome if (part[i].relsect == edkpi.p_start) { 1322d7802caeSToomas Soome *start = part[i].relsect; 1323d7802caeSToomas Soome return (true); 1324d7802caeSToomas Soome } 13250c946d80SToomas Soome } 13260c946d80SToomas Soome 1327d7802caeSToomas Soome rval = libfdisk_init(&epp, pl->pl_devname, part, FDISK_READ_DISK); 1328d7802caeSToomas Soome if (rval != FDISK_SUCCESS) { 13290c946d80SToomas Soome switch (rval) { 13300c946d80SToomas Soome /* 13310c946d80SToomas Soome * The first 3 cases are not an error per-se, just that 13320c946d80SToomas Soome * there is no Solaris logical partition 13330c946d80SToomas Soome */ 13340c946d80SToomas Soome case FDISK_EBADLOGDRIVE: 13350c946d80SToomas Soome case FDISK_ENOLOGDRIVE: 13360c946d80SToomas Soome case FDISK_EBADMAGIC: 13370c946d80SToomas Soome (void) fprintf(stderr, gettext("Solaris " 13380c946d80SToomas Soome "partition not found. " 1339d7802caeSToomas Soome "Aborting operation. %d\n"), rval); 1340d7802caeSToomas Soome return (false); 13410c946d80SToomas Soome case FDISK_ENOVGEOM: 13420c946d80SToomas Soome (void) fprintf(stderr, gettext("Could not get " 13430c946d80SToomas Soome "virtual geometry\n")); 1344d7802caeSToomas Soome return (false); 13450c946d80SToomas Soome case FDISK_ENOPGEOM: 13460c946d80SToomas Soome (void) fprintf(stderr, gettext("Could not get " 13470c946d80SToomas Soome "physical geometry\n")); 1348d7802caeSToomas Soome return (false); 13490c946d80SToomas Soome case FDISK_ENOLGEOM: 13500c946d80SToomas Soome (void) fprintf(stderr, gettext("Could not get " 13510c946d80SToomas Soome "label geometry\n")); 1352d7802caeSToomas Soome return (false); 13530c946d80SToomas Soome default: 13540c946d80SToomas Soome (void) fprintf(stderr, gettext("Failed to " 13550c946d80SToomas Soome "initialize libfdisk.\n")); 1356d7802caeSToomas Soome return (false); 13570c946d80SToomas Soome } 13580c946d80SToomas Soome } 13590c946d80SToomas Soome rval = fdisk_get_solaris_part(epp, &pno, &secnum, &numsec); 13600c946d80SToomas Soome libfdisk_fini(&epp); 13610c946d80SToomas Soome if (rval != FDISK_SUCCESS) { 13620c946d80SToomas Soome /* No solaris logical partition */ 13630c946d80SToomas Soome (void) fprintf(stderr, gettext("Solaris partition not found. " 13640c946d80SToomas Soome "Aborting operation.\n")); 1365d7802caeSToomas Soome return (false); 13660c946d80SToomas Soome } 1367d7802caeSToomas Soome *start = secnum; 1368d7802caeSToomas Soome return (true); 1369d7802caeSToomas Soome } 13700c946d80SToomas Soome 1371d7802caeSToomas Soome /* 1372d7802caeSToomas Soome * On x86 the VTOC table is inside MBR partition and to get 1373d7802caeSToomas Soome * absolute sectors, we need to add MBR partition start to VTOC slice start. 1374d7802caeSToomas Soome */ 1375d7802caeSToomas Soome static bool 1376d7802caeSToomas Soome probe_vtoc(ib_data_t *data) 1377d7802caeSToomas Soome { 1378d7802caeSToomas Soome struct partlist *pl; 1379d7802caeSToomas Soome struct extvtoc exvtoc; 1380d7802caeSToomas Soome ib_device_t *device; 1381d7802caeSToomas Soome char *path, *ptr; 1382d7802caeSToomas Soome ushort_t i; 1383d7802caeSToomas Soome int slice, fd; 1384d7802caeSToomas Soome diskaddr_t start; 1385d7802caeSToomas Soome bool rv; 13860c946d80SToomas Soome 1387d7802caeSToomas Soome rv = false; 1388d7802caeSToomas Soome 1389d7802caeSToomas Soome if ((fd = open_device(data->target.path)) < 0) 1390d7802caeSToomas Soome return (rv); 1391d7802caeSToomas Soome 1392d7802caeSToomas Soome slice = read_extvtoc(fd, &exvtoc); 1393d7802caeSToomas Soome (void) close(fd); 1394d7802caeSToomas Soome if (slice < 0) 1395d7802caeSToomas Soome return (rv); 1396d7802caeSToomas Soome data->device.devtype = IB_DEV_VTOC; 1397d7802caeSToomas Soome 1398d7802caeSToomas Soome if (!get_start_sector(data, exvtoc.v_part + slice, &start)) 1399d7802caeSToomas Soome return (rv); 1400d7802caeSToomas Soome 1401d7802caeSToomas Soome if (exvtoc.v_part[slice].p_tag == V_BACKUP) { 1402d7802caeSToomas Soome /* 1403d7802caeSToomas Soome * NOTE: we could relax there and allow zfs boot on 1404d7802caeSToomas Soome * slice 2, but lets keep traditional limits. 1405d7802caeSToomas Soome */ 1406d7802caeSToomas Soome (void) fprintf(stderr, gettext( 1407d7802caeSToomas Soome "raw device must be a root slice (not backup)\n")); 1408d7802caeSToomas Soome return (rv); 1409d7802caeSToomas Soome } 1410d7802caeSToomas Soome 1411d7802caeSToomas Soome if ((path = strdup(data->target.path)) == NULL) { 1412d7802caeSToomas Soome perror(gettext("Memory allocation failure")); 1413d7802caeSToomas Soome return (false); 1414d7802caeSToomas Soome } 1415d7802caeSToomas Soome 1416d7802caeSToomas Soome data->target.start = start + exvtoc.v_part[slice].p_start; 1417d7802caeSToomas Soome data->target.size = exvtoc.v_part[slice].p_size; 1418d7802caeSToomas Soome 1419d7802caeSToomas Soome /* Search for boot slice. */ 1420d7802caeSToomas Soome for (i = 0; i < exvtoc.v_nparts; i++) { 1421d7802caeSToomas Soome if (exvtoc.v_part[i].p_tag == V_BOOT) 1422d7802caeSToomas Soome break; 1423d7802caeSToomas Soome } 1424d7802caeSToomas Soome 1425d7802caeSToomas Soome if (i == exvtoc.v_nparts || 1426d7802caeSToomas Soome exvtoc.v_part[i].p_size == 0) { 1427d7802caeSToomas Soome /* fall back to slice V_BACKUP */ 1428d7802caeSToomas Soome for (i = 0; i < exvtoc.v_nparts; i++) { 1429d7802caeSToomas Soome if (exvtoc.v_part[i].p_tag == V_BACKUP) 1430d7802caeSToomas Soome break; 1431d7802caeSToomas Soome } 1432d7802caeSToomas Soome /* Still nothing? Error out. */ 1433d7802caeSToomas Soome if (i == exvtoc.v_nparts || 1434d7802caeSToomas Soome exvtoc.v_part[i].p_size == 0) { 1435d7802caeSToomas Soome free(path); 1436d7802caeSToomas Soome return (false); 1437d7802caeSToomas Soome } 1438d7802caeSToomas Soome } 1439d7802caeSToomas Soome 1440d7802caeSToomas Soome /* Create path. */ 1441d7802caeSToomas Soome ptr = strrchr(path, 's'); 1442d7802caeSToomas Soome ptr++; 1443d7802caeSToomas Soome *ptr = '\0'; 1444d7802caeSToomas Soome (void) asprintf(&ptr, "%s%d", path, i); 1445d7802caeSToomas Soome free(path); 1446d7802caeSToomas Soome if (ptr == NULL) { 1447d7802caeSToomas Soome perror(gettext("Memory allocation failure")); 1448d7802caeSToomas Soome return (false); 1449d7802caeSToomas Soome } 1450d7802caeSToomas Soome 1451d7802caeSToomas Soome pl = partlist_alloc(); 1452d7802caeSToomas Soome if (pl == NULL) { 1453d7802caeSToomas Soome free(ptr); 1454d7802caeSToomas Soome return (false); 1455d7802caeSToomas Soome } 1456d7802caeSToomas Soome pl->pl_devname = ptr; 1457d7802caeSToomas Soome device = pl->pl_device; 1458d7802caeSToomas Soome device->stage.devtype = data->device.devtype; 1459d7802caeSToomas Soome device->stage.id = i; 1460d7802caeSToomas Soome device->stage.tag = exvtoc.v_part[i].p_tag; 1461d7802caeSToomas Soome device->stage.start = start + exvtoc.v_part[i].p_start; 1462d7802caeSToomas Soome device->stage.size = exvtoc.v_part[i].p_size; 1463d7802caeSToomas Soome 1464d7802caeSToomas Soome /* Fix size if this slice is in fact V_BACKUP */ 1465d7802caeSToomas Soome if (exvtoc.v_part[i].p_tag == V_BACKUP) { 1466d7802caeSToomas Soome for (i = 0; i < exvtoc.v_nparts; i++) { 1467d7802caeSToomas Soome if (exvtoc.v_part[i].p_start == 0) 1468d7802caeSToomas Soome continue; 1469d7802caeSToomas Soome if (exvtoc.v_part[i].p_size == 0) 1470d7802caeSToomas Soome continue; 1471d7802caeSToomas Soome if (exvtoc.v_part[i].p_start < 1472d7802caeSToomas Soome device->stage.size) 1473d7802caeSToomas Soome device->stage.size = 1474d7802caeSToomas Soome exvtoc.v_part[i].p_start; 14750c946d80SToomas Soome } 14760c946d80SToomas Soome } 14770c946d80SToomas Soome 1478d7802caeSToomas Soome pl->pl_src_name = stage1; 1479d7802caeSToomas Soome pl->pl_type = IB_BBLK_STAGE1; 1480d7802caeSToomas Soome pl->pl_cb.compare = compare_stage1_cb; 1481d7802caeSToomas Soome pl->pl_cb.install = install_stage1_cb; 1482d7802caeSToomas Soome pl->pl_cb.read = read_stage1_cb; 1483d7802caeSToomas Soome pl->pl_cb.read_bbl = read_stage1_bbl_cb; 1484d7802caeSToomas Soome pl->pl_cb.print = print_stage1_cb; 1485d7802caeSToomas Soome STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1486d7802caeSToomas Soome 1487d7802caeSToomas Soome /* Create instance for stage 2 */ 1488d7802caeSToomas Soome pl = partlist_alloc(); 1489d7802caeSToomas Soome if (pl == NULL) { 1490d7802caeSToomas Soome free(ptr); 1491d7802caeSToomas Soome return (false); 1492d7802caeSToomas Soome } 1493d7802caeSToomas Soome pl->pl_devname = strdup(ptr); 1494d7802caeSToomas Soome if (pl->pl_devname == NULL) { 1495d7802caeSToomas Soome partlist_free(pl); 1496d7802caeSToomas Soome return (false); 1497d7802caeSToomas Soome } 1498d7802caeSToomas Soome pl->pl_device->stage.devtype = data->device.devtype; 1499d7802caeSToomas Soome pl->pl_device->stage.id = device->stage.id; 1500d7802caeSToomas Soome pl->pl_device->stage.offset = BBLK_BLKLIST_OFF; 1501d7802caeSToomas Soome pl->pl_device->stage.tag = device->stage.tag; 1502d7802caeSToomas Soome pl->pl_device->stage.start = device->stage.start; 1503d7802caeSToomas Soome pl->pl_device->stage.size = device->stage.size; 1504d7802caeSToomas Soome pl->pl_src_name = stage2; 1505d7802caeSToomas Soome pl->pl_type = IB_BBLK_STAGE2; 1506d7802caeSToomas Soome pl->pl_cb.compare = compare_einfo_cb; 1507d7802caeSToomas Soome pl->pl_cb.install = install_stage2_cb; 1508d7802caeSToomas Soome pl->pl_cb.read = read_stage2_cb; 1509d7802caeSToomas Soome pl->pl_cb.read_bbl = read_stage2_file_cb; 1510d7802caeSToomas Soome pl->pl_cb.print = print_einfo_cb; 1511d7802caeSToomas Soome STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1512d7802caeSToomas Soome 1513d7802caeSToomas Soome /* And we are done. */ 1514d7802caeSToomas Soome rv = true; 1515d7802caeSToomas Soome return (rv); 1516d7802caeSToomas Soome } 1517d7802caeSToomas Soome 1518d7802caeSToomas Soome static bool 1519d7802caeSToomas Soome probe_mbr(ib_data_t *data) 1520d7802caeSToomas Soome { 1521d7802caeSToomas Soome struct partlist *pl; 1522d7802caeSToomas Soome struct ipart *part; 1523d7802caeSToomas Soome struct mboot *mbr; 1524d7802caeSToomas Soome ib_device_t *device; 1525d7802caeSToomas Soome char *path, *ptr; 1526d7802caeSToomas Soome int i, rv; 1527d7802caeSToomas Soome 1528d7802caeSToomas Soome data->device.devtype = IB_DEV_MBR; 1529d7802caeSToomas Soome 1530d7802caeSToomas Soome /* Head is always MBR */ 1531d7802caeSToomas Soome pl = STAILQ_FIRST(data->plist); 1532d7802caeSToomas Soome if (!read_stage1_cb(pl)) 1533d7802caeSToomas Soome return (false); 1534d7802caeSToomas Soome 1535d7802caeSToomas Soome mbr = (struct mboot *)pl->pl_stage; 1536d7802caeSToomas Soome part = (struct ipart *)mbr->parts; 1537d7802caeSToomas Soome 1538d7802caeSToomas Soome /* Set target file system start and size */ 1539d7802caeSToomas Soome data->target.start = part[data->target.id - 1].relsect; 1540d7802caeSToomas Soome data->target.size = part[data->target.id - 1].numsect; 1541d7802caeSToomas Soome 1542d7802caeSToomas Soome /* Use X86BOOT partition if we have one. */ 1543d7802caeSToomas Soome for (i = 0; i < FD_NUMPART; i++) { 1544d7802caeSToomas Soome if (part[i].systid == X86BOOT) 1545d7802caeSToomas Soome break; 1546d7802caeSToomas Soome } 1547d7802caeSToomas Soome 1548d7802caeSToomas Soome /* Keep device name of whole disk device. */ 1549d7802caeSToomas Soome path = (char *)pl->pl_devname; 1550d7802caeSToomas Soome if ((pl = partlist_alloc()) == NULL) 1551d7802caeSToomas Soome return (false); 1552d7802caeSToomas Soome device = pl->pl_device; 1553d7802caeSToomas Soome 15540c946d80SToomas Soome /* 1555d7802caeSToomas Soome * No X86BOOT, try to use space between MBR and first 1556d7802caeSToomas Soome * partition. 15570c946d80SToomas Soome */ 1558d7802caeSToomas Soome if (i == FD_NUMPART) { 1559d7802caeSToomas Soome /* with pcfs we always write MBR */ 1560d7802caeSToomas Soome if (data->target.fstype == IB_FS_PCFS) { 1561d7802caeSToomas Soome force_mbr = true; 1562d7802caeSToomas Soome write_mbr = true; 15630c946d80SToomas Soome } 1564d7802caeSToomas Soome 1565d7802caeSToomas Soome pl->pl_devname = strdup(path); 1566d7802caeSToomas Soome if (pl->pl_devname == NULL) { 1567d7802caeSToomas Soome perror(gettext("Memory allocation failure")); 1568d7802caeSToomas Soome partlist_free(pl); 1569d7802caeSToomas Soome return (false); 1570d7802caeSToomas Soome } 1571d7802caeSToomas Soome device->stage.id = 0; 1572d7802caeSToomas Soome device->stage.devtype = IB_DEV_MBR; 1573d7802caeSToomas Soome device->stage.fstype = IB_FS_NONE; 1574d7802caeSToomas Soome device->stage.start = 0; 1575d7802caeSToomas Soome device->stage.size = part[0].relsect; 1576d7802caeSToomas Soome device->stage.offset = BBLK_BLKLIST_OFF; 1577d7802caeSToomas Soome pl->pl_src_name = stage2; 1578d7802caeSToomas Soome pl->pl_type = IB_BBLK_STAGE2; 1579d7802caeSToomas Soome pl->pl_cb.compare = compare_einfo_cb; 1580d7802caeSToomas Soome pl->pl_cb.install = install_stage2_cb; 1581d7802caeSToomas Soome pl->pl_cb.read = read_stage2_cb; 1582d7802caeSToomas Soome pl->pl_cb.read_bbl = read_stage2_file_cb; 1583d7802caeSToomas Soome pl->pl_cb.print = print_einfo_cb; 1584d7802caeSToomas Soome STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1585d7802caeSToomas Soome 1586d7802caeSToomas Soome /* We have MBR for stage1 and gap for stage2, we are done. */ 1587d7802caeSToomas Soome return (true); 15880c946d80SToomas Soome } 15890c946d80SToomas Soome 1590d7802caeSToomas Soome if ((path = strdup(path)) == NULL) { 1591d7802caeSToomas Soome perror(gettext("Memory allocation failure")); 1592d7802caeSToomas Soome partlist_free(pl); 1593d7802caeSToomas Soome return (false); 1594d7802caeSToomas Soome } 1595d7802caeSToomas Soome ptr = strrchr(path, 'p'); 1596d7802caeSToomas Soome ptr++; 1597d7802caeSToomas Soome *ptr = '\0'; 1598d7802caeSToomas Soome /* partitions are p1..p4 */ 1599d7802caeSToomas Soome rv = asprintf(&ptr, "%s%d", path, i + 1); 1600d7802caeSToomas Soome free(path); 1601d7802caeSToomas Soome if (rv < 0) { 1602d7802caeSToomas Soome perror(gettext("Memory allocation failure")); 1603d7802caeSToomas Soome partlist_free(pl); 1604d7802caeSToomas Soome return (false); 1605d7802caeSToomas Soome } 1606d7802caeSToomas Soome pl->pl_devname = ptr; 1607d7802caeSToomas Soome device->stage.id = i + 1; 1608d7802caeSToomas Soome device->stage.devtype = IB_DEV_MBR; 1609d7802caeSToomas Soome device->stage.fstype = IB_FS_NONE; 1610d7802caeSToomas Soome device->stage.start = part[i].relsect; 1611d7802caeSToomas Soome device->stage.size = part[i].numsect; 1612d7802caeSToomas Soome pl->pl_src_name = stage1; 1613d7802caeSToomas Soome pl->pl_type = IB_BBLK_STAGE1; 1614d7802caeSToomas Soome pl->pl_cb.compare = compare_stage1_cb; 1615d7802caeSToomas Soome pl->pl_cb.install = install_stage1_cb; 1616d7802caeSToomas Soome pl->pl_cb.read = read_stage1_cb; 1617d7802caeSToomas Soome pl->pl_cb.read_bbl = read_stage1_bbl_cb; 1618d7802caeSToomas Soome pl->pl_cb.print = print_stage1_cb; 1619d7802caeSToomas Soome STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1620d7802caeSToomas Soome 1621d7802caeSToomas Soome pl = partlist_alloc(); 1622d7802caeSToomas Soome if (pl == NULL) 1623d7802caeSToomas Soome return (false); 1624d7802caeSToomas Soome device = pl->pl_device; 1625d7802caeSToomas Soome pl->pl_devname = strdup(ptr); 1626d7802caeSToomas Soome if (pl->pl_devname == NULL) { 1627d7802caeSToomas Soome perror(gettext("Memory allocation failure")); 1628d7802caeSToomas Soome partlist_free(pl); 1629d7802caeSToomas Soome return (false); 1630d7802caeSToomas Soome } 1631d7802caeSToomas Soome device->stage.id = i + 1; 1632d7802caeSToomas Soome device->stage.devtype = IB_DEV_MBR; 1633d7802caeSToomas Soome device->stage.fstype = IB_FS_NONE; 1634d7802caeSToomas Soome device->stage.start = part[i].relsect; 1635d7802caeSToomas Soome device->stage.size = part[i].numsect; 1636d7802caeSToomas Soome device->stage.offset = 1; 1637d7802caeSToomas Soome /* This is boot partition */ 1638d7802caeSToomas Soome device->stage.tag = V_BOOT; 1639d7802caeSToomas Soome pl->pl_src_name = stage2; 1640d7802caeSToomas Soome pl->pl_type = IB_BBLK_STAGE2; 1641d7802caeSToomas Soome pl->pl_cb.compare = compare_einfo_cb; 1642d7802caeSToomas Soome pl->pl_cb.install = install_stage2_cb; 1643d7802caeSToomas Soome pl->pl_cb.read = read_stage2_cb; 1644d7802caeSToomas Soome pl->pl_cb.read_bbl = read_stage2_file_cb; 1645d7802caeSToomas Soome pl->pl_cb.print = print_einfo_cb; 1646d7802caeSToomas Soome STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1647d7802caeSToomas Soome 1648d7802caeSToomas Soome return (true); 1649d7802caeSToomas Soome } 1650d7802caeSToomas Soome 1651d7802caeSToomas Soome static bool 1652d7802caeSToomas Soome probe_device(ib_data_t *data, const char *dev) 1653d7802caeSToomas Soome { 1654d7802caeSToomas Soome struct partlist *pl; 1655d7802caeSToomas Soome struct stat sb; 1656d7802caeSToomas Soome const char *ptr; 1657d7802caeSToomas Soome char *p0; 1658d7802caeSToomas Soome int fd, len; 1659d7802caeSToomas Soome 1660d7802caeSToomas Soome if (dev == NULL) 1661d7802caeSToomas Soome return (NULL); 1662d7802caeSToomas Soome 1663d7802caeSToomas Soome len = strlen(dev); 1664d7802caeSToomas Soome 1665d7802caeSToomas Soome if ((pl = partlist_alloc()) == NULL) 1666d7802caeSToomas Soome return (false); 1667d7802caeSToomas Soome 1668d7802caeSToomas Soome if (stat(dev, &sb) == -1) { 1669d7802caeSToomas Soome perror("stat"); 1670d7802caeSToomas Soome partlist_free(pl); 1671d7802caeSToomas Soome return (false); 1672d7802caeSToomas Soome } 1673d7802caeSToomas Soome 1674d7802caeSToomas Soome /* We have regular file, register it and we are done. */ 1675d7802caeSToomas Soome if (S_ISREG(sb.st_mode) != 0) { 1676d7802caeSToomas Soome pl->pl_devname = (char *)dev; 1677d7802caeSToomas Soome 1678d7802caeSToomas Soome pl->pl_type = IB_BBLK_FILE; 1679d7802caeSToomas Soome pl->pl_cb.read = read_einfo_file_cb; 1680d7802caeSToomas Soome pl->pl_cb.print = print_einfo_cb; 1681d7802caeSToomas Soome STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1682d7802caeSToomas Soome return (true); 1683d7802caeSToomas Soome } 1684d7802caeSToomas Soome 1685d7802caeSToomas Soome /* 1686d7802caeSToomas Soome * This is block device. 1687d7802caeSToomas Soome * We do not allow to specify whole disk device (cXtYdZp0 or cXtYdZ). 1688d7802caeSToomas Soome */ 1689d7802caeSToomas Soome if ((ptr = strrchr(dev, '/')) == NULL) 1690d7802caeSToomas Soome ptr = dev; 1691d7802caeSToomas Soome if ((strrchr(ptr, 'p') == NULL && strrchr(ptr, 's') == NULL) || 1692d7802caeSToomas Soome (dev[len - 2] == 'p' && dev[len - 1] == '0')) { 1693d7802caeSToomas Soome (void) fprintf(stderr, 1694d7802caeSToomas Soome gettext("whole disk device is not supported\n")); 1695d7802caeSToomas Soome partlist_free(pl); 1696d7802caeSToomas Soome return (false); 1697d7802caeSToomas Soome } 1698d7802caeSToomas Soome 1699d7802caeSToomas Soome data->target.path = (char *)dev; 1700d7802caeSToomas Soome if (!probe_fstyp(data)) { 1701d7802caeSToomas Soome partlist_free(pl); 1702d7802caeSToomas Soome return (false); 1703d7802caeSToomas Soome } 1704d7802caeSToomas Soome 1705d7802caeSToomas Soome /* We start from identifying the whole disk. */ 1706d7802caeSToomas Soome if ((p0 = strdup(dev)) == NULL) { 1707d7802caeSToomas Soome perror("calloc"); 1708d7802caeSToomas Soome partlist_free(pl); 1709d7802caeSToomas Soome return (false); 1710d7802caeSToomas Soome } 1711d7802caeSToomas Soome 1712d7802caeSToomas Soome pl->pl_devname = p0; 1713d7802caeSToomas Soome /* Change device name to p0 */ 1714d7802caeSToomas Soome if ((ptr = strrchr(p0, 'p')) == NULL) 1715d7802caeSToomas Soome ptr = strrchr(p0, 's'); 1716d7802caeSToomas Soome p0 = (char *)ptr; 1717d7802caeSToomas Soome p0[0] = 'p'; 1718d7802caeSToomas Soome p0[1] = '0'; 1719d7802caeSToomas Soome p0[2] = '\0'; 1720d7802caeSToomas Soome 1721d7802caeSToomas Soome if ((fd = open_device(pl->pl_devname)) == -1) { 1722d7802caeSToomas Soome partlist_free(pl); 1723d7802caeSToomas Soome return (false); 1724d7802caeSToomas Soome } 1725d7802caeSToomas Soome 1726d7802caeSToomas Soome sector_size = get_media_info(fd); 1727d7802caeSToomas Soome (void) close(fd); 1728d7802caeSToomas Soome 1729d7802caeSToomas Soome pl->pl_src_name = stage1; 1730d7802caeSToomas Soome pl->pl_type = IB_BBLK_MBR; 1731d7802caeSToomas Soome pl->pl_cb.compare = compare_mbr_cb; 1732d7802caeSToomas Soome pl->pl_cb.install = install_stage1_cb; 1733d7802caeSToomas Soome pl->pl_cb.read = read_stage1_cb; 1734d7802caeSToomas Soome pl->pl_cb.read_bbl = read_stage1_bbl_cb; 1735d7802caeSToomas Soome pl->pl_cb.print = print_stage1_cb; 1736d7802caeSToomas Soome STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1737d7802caeSToomas Soome 1738d7802caeSToomas Soome if (probe_gpt(data)) 1739d7802caeSToomas Soome return (true); 1740d7802caeSToomas Soome 1741d7802caeSToomas Soome if (data->device.devtype == IB_DEV_UNKNOWN) 1742d7802caeSToomas Soome if (probe_vtoc(data)) 1743d7802caeSToomas Soome return (true); 1744d7802caeSToomas Soome 1745d7802caeSToomas Soome if (data->device.devtype == IB_DEV_UNKNOWN) 1746d7802caeSToomas Soome return (probe_mbr(data)); 1747d7802caeSToomas Soome 1748d7802caeSToomas Soome return (false); 1749d7802caeSToomas Soome } 1750d7802caeSToomas Soome 1751d7802caeSToomas Soome static int 1752d7802caeSToomas Soome read_bootblock_from_file(const char *file, ib_bootblock_t *bblock) 1753d7802caeSToomas Soome { 1754d7802caeSToomas Soome struct stat sb; 1755d7802caeSToomas Soome uint32_t buf_size; 1756d7802caeSToomas Soome uint32_t mboot_off; 1757d7802caeSToomas Soome int fd = -1; 1758d7802caeSToomas Soome int retval = BC_ERROR; 1759d7802caeSToomas Soome 1760d7802caeSToomas Soome assert(bblock != NULL); 1761d7802caeSToomas Soome assert(file != NULL); 1762d7802caeSToomas Soome 1763d7802caeSToomas Soome fd = open(file, O_RDONLY); 1764d7802caeSToomas Soome if (fd == -1) { 1765d7802caeSToomas Soome BOOT_DEBUG("Error opening %s\n", file); 1766d7802caeSToomas Soome goto out; 1767d7802caeSToomas Soome } 1768d7802caeSToomas Soome 1769d7802caeSToomas Soome if (fstat(fd, &sb) == -1) { 1770d7802caeSToomas Soome BOOT_DEBUG("Error getting information (stat) about %s", file); 1771d7802caeSToomas Soome perror("stat"); 1772d7802caeSToomas Soome goto outfd; 1773d7802caeSToomas Soome } 1774d7802caeSToomas Soome 1775d7802caeSToomas Soome /* loader bootblock has version built in */ 1776d7802caeSToomas Soome buf_size = sb.st_size; 1777*46d70dceSToomas Soome if (buf_size == 0) 1778*46d70dceSToomas Soome goto outfd; 1779d7802caeSToomas Soome 1780d7802caeSToomas Soome bblock->buf_size = buf_size; 1781d7802caeSToomas Soome BOOT_DEBUG("bootblock in-memory buffer size is %d\n", 1782d7802caeSToomas Soome bblock->buf_size); 1783d7802caeSToomas Soome 1784d7802caeSToomas Soome bblock->buf = malloc(buf_size); 1785d7802caeSToomas Soome if (bblock->buf == NULL) { 1786d7802caeSToomas Soome perror(gettext("Memory allocation failure")); 1787d7802caeSToomas Soome goto outbuf; 1788d7802caeSToomas Soome } 1789d7802caeSToomas Soome bblock->file = bblock->buf; 1790d7802caeSToomas Soome 1791d7802caeSToomas Soome if (read(fd, bblock->file, bblock->buf_size) != bblock->buf_size) { 1792d7802caeSToomas Soome BOOT_DEBUG("Read from %s failed\n", file); 1793d7802caeSToomas Soome perror("read"); 1794d7802caeSToomas Soome goto outfd; 1795d7802caeSToomas Soome } 1796d7802caeSToomas Soome 1797d7802caeSToomas Soome buf_size = MIN(buf_size, MBOOT_SCAN_SIZE); 1798d7802caeSToomas Soome if (find_multiboot(bblock->file, buf_size, &mboot_off) 1799d7802caeSToomas Soome != BC_SUCCESS) { 1800d7802caeSToomas Soome (void) fprintf(stderr, 1801d7802caeSToomas Soome gettext("Unable to find multiboot header\n")); 1802d7802caeSToomas Soome goto outfd; 1803d7802caeSToomas Soome } 1804d7802caeSToomas Soome 1805d7802caeSToomas Soome bblock->mboot = (multiboot_header_t *)(bblock->file + mboot_off); 1806d7802caeSToomas Soome bblock->mboot_off = mboot_off; 1807d7802caeSToomas Soome 1808d7802caeSToomas Soome bblock->file_size = 1809d7802caeSToomas Soome bblock->mboot->load_end_addr - bblock->mboot->load_addr; 1810d7802caeSToomas Soome BOOT_DEBUG("bootblock file size is %d\n", bblock->file_size); 1811d7802caeSToomas Soome 1812d7802caeSToomas Soome bblock->extra = bblock->buf + P2ROUNDUP(bblock->file_size, 8); 1813d7802caeSToomas Soome bblock->extra_size = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8); 1814d7802caeSToomas Soome 1815d7802caeSToomas Soome BOOT_DEBUG("mboot at %p offset %d, extra at %p size %d, buf=%p " 1816d7802caeSToomas Soome "(size=%d)\n", bblock->mboot, bblock->mboot_off, bblock->extra, 1817d7802caeSToomas Soome bblock->extra_size, bblock->buf, bblock->buf_size); 1818d7802caeSToomas Soome 1819d7802caeSToomas Soome (void) close(fd); 18200c946d80SToomas Soome return (BC_SUCCESS); 1821d7802caeSToomas Soome 1822d7802caeSToomas Soome outbuf: 1823d7802caeSToomas Soome (void) free(bblock->buf); 1824d7802caeSToomas Soome bblock->buf = NULL; 1825d7802caeSToomas Soome outfd: 1826d7802caeSToomas Soome (void) close(fd); 1827d7802caeSToomas Soome out: 1828d7802caeSToomas Soome if (retval == BC_ERROR) { 1829d7802caeSToomas Soome (void) fprintf(stderr, 1830d7802caeSToomas Soome gettext("Error reading bootblock from %s\n"), 1831d7802caeSToomas Soome file); 1832d7802caeSToomas Soome } 1833d7802caeSToomas Soome 1834d7802caeSToomas Soome if (retval == BC_NOEXTRA) { 1835d7802caeSToomas Soome BOOT_DEBUG("No multiboot header found on %s, unable to " 1836d7802caeSToomas Soome "locate extra information area (old/non versioned " 1837d7802caeSToomas Soome "bootblock?) \n", file); 1838d7802caeSToomas Soome (void) fprintf(stderr, gettext("No extended information" 1839d7802caeSToomas Soome " found\n")); 1840d7802caeSToomas Soome } 1841d7802caeSToomas Soome return (retval); 1842d7802caeSToomas Soome } 1843d7802caeSToomas Soome 1844d7802caeSToomas Soome static void 1845d7802caeSToomas Soome add_bootblock_einfo(ib_bootblock_t *bblock, char *updt_str) 1846d7802caeSToomas Soome { 1847d7802caeSToomas Soome bblk_hs_t hs; 1848d7802caeSToomas Soome uint32_t avail_space; 1849d7802caeSToomas Soome 1850d7802caeSToomas Soome assert(bblock != NULL); 1851d7802caeSToomas Soome 1852d7802caeSToomas Soome if (updt_str == NULL) { 1853d7802caeSToomas Soome BOOT_DEBUG("WARNING: no update string passed to " 1854d7802caeSToomas Soome "add_bootblock_einfo()\n"); 1855d7802caeSToomas Soome return; 1856d7802caeSToomas Soome } 1857d7802caeSToomas Soome 1858d7802caeSToomas Soome /* Fill bootblock hashing source information. */ 1859d7802caeSToomas Soome hs.src_buf = (unsigned char *)bblock->file; 1860d7802caeSToomas Soome hs.src_size = bblock->file_size; 1861d7802caeSToomas Soome /* How much space for the extended information structure? */ 1862d7802caeSToomas Soome avail_space = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8); 1863d7802caeSToomas Soome /* Place the extended information structure. */ 1864d7802caeSToomas Soome add_einfo(bblock->extra, updt_str, &hs, avail_space); 1865d7802caeSToomas Soome } 1866d7802caeSToomas Soome 1867d7802caeSToomas Soome /* 1868d7802caeSToomas Soome * set up data for case stage1 is installed as MBR 1869d7802caeSToomas Soome * set up location and size of bootblock 1870d7802caeSToomas Soome * set disk guid to provide unique information for biosdev command 1871d7802caeSToomas Soome */ 1872d7802caeSToomas Soome static void 1873d7802caeSToomas Soome prepare_stage1(struct partlist *stage1, struct partlist *stage2, uuid_t uuid) 1874d7802caeSToomas Soome { 1875d7802caeSToomas Soome char *src, *dest; 1876d7802caeSToomas Soome ib_bootblock_t *bblk; 1877d7802caeSToomas Soome ib_device_t *device; 1878d7802caeSToomas Soome uint16_t size; 1879d7802caeSToomas Soome struct mboot *mbr; 1880d7802caeSToomas Soome 1881d7802caeSToomas Soome src = stage1->pl_stage; 1882d7802caeSToomas Soome dest = stage1->pl_src_data; 1883d7802caeSToomas Soome device = stage2->pl_device; 1884d7802caeSToomas Soome 1885d7802caeSToomas Soome /* Only copy from valid source. */ 1886d7802caeSToomas Soome mbr = stage1->pl_stage; 1887d7802caeSToomas Soome if (mbr->signature == MBB_MAGIC) { 1888d7802caeSToomas Soome /* copy BPB */ 1889d7802caeSToomas Soome bcopy(src + STAGE1_BPB_OFFSET, dest + STAGE1_BPB_OFFSET, 1890d7802caeSToomas Soome STAGE1_BPB_SIZE); 1891d7802caeSToomas Soome 1892d7802caeSToomas Soome /* copy MBR, note STAGE1_SIG == BOOTSZ */ 1893d7802caeSToomas Soome bcopy(src + STAGE1_SIG, dest + STAGE1_SIG, 1894d7802caeSToomas Soome SECTOR_SIZE - STAGE1_SIG); 1895d7802caeSToomas Soome } 1896d7802caeSToomas Soome 1897d7802caeSToomas Soome bcopy(uuid, dest + STAGE1_STAGE2_UUID, UUID_LEN); 1898d7802caeSToomas Soome 1899d7802caeSToomas Soome /* set stage2 size */ 1900d7802caeSToomas Soome bblk = stage2->pl_src_data; 1901d7802caeSToomas Soome size = bblk->buf_size / SECTOR_SIZE; 1902d7802caeSToomas Soome *((uint16_t *)(dest + STAGE1_STAGE2_SIZE)) = size; 1903d7802caeSToomas Soome 1904d7802caeSToomas Soome /* set stage2 LBA */ 1905d7802caeSToomas Soome *((uint64_t *)(dest + STAGE1_STAGE2_LBA)) = 1906d7802caeSToomas Soome device->stage.start + device->stage.offset; 1907d7802caeSToomas Soome 1908d7802caeSToomas Soome /* Copy prepared data to stage1 block read from the disk. */ 1909d7802caeSToomas Soome bcopy(dest, src, SECTOR_SIZE); 1910d7802caeSToomas Soome } 1911d7802caeSToomas Soome 1912d7802caeSToomas Soome static void 1913d7802caeSToomas Soome prepare_bootblock(ib_data_t *data, struct partlist *pl, char *updt_str) 1914d7802caeSToomas Soome { 1915d7802caeSToomas Soome ib_bootblock_t *bblock; 1916d7802caeSToomas Soome uint64_t *ptr; 1917d7802caeSToomas Soome 1918d7802caeSToomas Soome assert(pl != NULL); 1919d7802caeSToomas Soome 1920d7802caeSToomas Soome bblock = pl->pl_src_data; 1921*46d70dceSToomas Soome if (bblock == NULL) 1922*46d70dceSToomas Soome return; 1923d7802caeSToomas Soome 1924d7802caeSToomas Soome ptr = (uint64_t *)(&bblock->mboot->bss_end_addr); 1925d7802caeSToomas Soome *ptr = data->target.start; 1926d7802caeSToomas Soome 1927d7802caeSToomas Soome /* 1928d7802caeSToomas Soome * the loader bootblock has built in version, if custom 1929d7802caeSToomas Soome * version was provided, update it. 1930d7802caeSToomas Soome */ 1931d7802caeSToomas Soome if (do_version) 1932d7802caeSToomas Soome add_bootblock_einfo(bblock, updt_str); 19330c946d80SToomas Soome } 19340c946d80SToomas Soome 19350c946d80SToomas Soome static int 1936d7802caeSToomas Soome open_device(const char *path) 19370c946d80SToomas Soome { 19380c946d80SToomas Soome struct stat statbuf = {0}; 19390c946d80SToomas Soome int fd = -1; 19400c946d80SToomas Soome 19410c946d80SToomas Soome if (nowrite) 19420c946d80SToomas Soome fd = open(path, O_RDONLY); 19430c946d80SToomas Soome else 19440c946d80SToomas Soome fd = open(path, O_RDWR); 19450c946d80SToomas Soome 19460c946d80SToomas Soome if (fd == -1) { 19470c946d80SToomas Soome BOOT_DEBUG("Unable to open %s\n", path); 19480c946d80SToomas Soome perror("open"); 19490c946d80SToomas Soome return (-1); 19500c946d80SToomas Soome } 19510c946d80SToomas Soome 19520c946d80SToomas Soome if (fstat(fd, &statbuf) != 0) { 19530c946d80SToomas Soome BOOT_DEBUG("Unable to stat %s\n", path); 19540c946d80SToomas Soome perror("stat"); 19550c946d80SToomas Soome (void) close(fd); 19560c946d80SToomas Soome return (-1); 19570c946d80SToomas Soome } 19580c946d80SToomas Soome 19590c946d80SToomas Soome if (S_ISCHR(statbuf.st_mode) == 0) { 19600c946d80SToomas Soome (void) fprintf(stderr, gettext("%s: Not a character device\n"), 19610c946d80SToomas Soome path); 19620c946d80SToomas Soome (void) close(fd); 19630c946d80SToomas Soome return (-1); 19640c946d80SToomas Soome } 19650c946d80SToomas Soome 19660c946d80SToomas Soome return (fd); 19670c946d80SToomas Soome } 19680c946d80SToomas Soome 1969d7802caeSToomas Soome /* 1970d7802caeSToomas Soome * We need to record stage2 location and size into pmbr/vbr. 1971d7802caeSToomas Soome * We need to record target partiton LBA to stage2. 1972d7802caeSToomas Soome */ 1973d7802caeSToomas Soome static void 1974d7802caeSToomas Soome prepare_bblocks(ib_data_t *data) 19750c946d80SToomas Soome { 1976d7802caeSToomas Soome struct partlist *pl; 1977d7802caeSToomas Soome struct partlist *mbr, *stage1, *stage2; 1978d7802caeSToomas Soome uuid_t uuid; 19790c946d80SToomas Soome 1980d7802caeSToomas Soome mbr = stage1 = stage2 = NULL; 1981d7802caeSToomas Soome /* 1982d7802caeSToomas Soome * Walk list and pick up BIOS boot blocks. EFI boot programs 1983d7802caeSToomas Soome * can be set in place. 1984d7802caeSToomas Soome */ 1985d7802caeSToomas Soome STAILQ_FOREACH(pl, data->plist, pl_next) { 1986d7802caeSToomas Soome switch (pl->pl_type) { 1987d7802caeSToomas Soome case IB_BBLK_MBR: 1988d7802caeSToomas Soome mbr = pl; 1989d7802caeSToomas Soome break; 1990d7802caeSToomas Soome case IB_BBLK_STAGE1: 1991d7802caeSToomas Soome stage1 = pl; 1992d7802caeSToomas Soome break; 1993d7802caeSToomas Soome case IB_BBLK_STAGE2: 1994d7802caeSToomas Soome stage2 = pl; 1995d7802caeSToomas Soome /* FALLTHROUGH */ 1996d7802caeSToomas Soome case IB_BBLK_EFI: 1997d7802caeSToomas Soome prepare_bootblock(data, pl, update_str); 1998d7802caeSToomas Soome break; 1999d7802caeSToomas Soome default: 20000c946d80SToomas Soome break; 20010c946d80SToomas Soome } 20020c946d80SToomas Soome } 20030c946d80SToomas Soome 2004d7802caeSToomas Soome /* If stage2 is missing, we are done. */ 2005d7802caeSToomas Soome if (stage2 == NULL) 2006d7802caeSToomas Soome return; 20070c946d80SToomas Soome 2008d7802caeSToomas Soome /* 2009d7802caeSToomas Soome * Create disk uuid. We only need reasonable amount of uniqueness 2010d7802caeSToomas Soome * to allow biosdev to identify disk based on mbr differences. 2011d7802caeSToomas Soome */ 2012d7802caeSToomas Soome uuid_generate(uuid); 20130c946d80SToomas Soome 2014d7802caeSToomas Soome if (mbr != NULL) { 2015d7802caeSToomas Soome prepare_stage1(mbr, stage2, uuid); 20160c946d80SToomas Soome 20170c946d80SToomas Soome /* 2018d7802caeSToomas Soome * If we have stage1, we point MBR to read stage 1. 20190c946d80SToomas Soome */ 2020d7802caeSToomas Soome if (stage1 != NULL) { 2021d7802caeSToomas Soome char *dest = mbr->pl_stage; 20220c946d80SToomas Soome 2023d7802caeSToomas Soome *((uint16_t *)(dest + STAGE1_STAGE2_SIZE)) = 1; 2024d7802caeSToomas Soome *((uint64_t *)(dest + STAGE1_STAGE2_LBA)) = 2025d7802caeSToomas Soome stage1->pl_device->stage.start; 20260c946d80SToomas Soome } 20270c946d80SToomas Soome } 20280c946d80SToomas Soome 2029d7802caeSToomas Soome if (stage1 != NULL) { 2030d7802caeSToomas Soome prepare_stage1(stage1, stage2, uuid); 20310c946d80SToomas Soome } 20320c946d80SToomas Soome } 20330c946d80SToomas Soome 20340c946d80SToomas Soome /* 20350c946d80SToomas Soome * Install a new bootblock on the given device. handle_install() expects argv 20360c946d80SToomas Soome * to contain 3 parameters (the target device path and the path to the 20370c946d80SToomas Soome * bootblock. 20380c946d80SToomas Soome * 20390c946d80SToomas Soome * Returns: BC_SUCCESS - if the installation is successful 20400c946d80SToomas Soome * BC_ERROR - if the installation failed 20410c946d80SToomas Soome * BC_NOUPDT - if no installation was performed because the 20420c946d80SToomas Soome * version currently installed is more recent than the 20430c946d80SToomas Soome * supplied one. 20440c946d80SToomas Soome * 20450c946d80SToomas Soome */ 20460c946d80SToomas Soome static int 2047d7802caeSToomas Soome handle_install(char *progname, int argc, char **argv) 20480c946d80SToomas Soome { 2049d7802caeSToomas Soome struct partlist *pl; 2050d7802caeSToomas Soome ib_data_t data = { 0 }; 20510c946d80SToomas Soome char *device_path = NULL; 20520c946d80SToomas Soome int ret = BC_ERROR; 20530c946d80SToomas Soome 2054d7802caeSToomas Soome switch (argc) { 2055d7802caeSToomas Soome case 1: 2056d7802caeSToomas Soome if ((device_path = strdup(argv[0])) == NULL) { 2057d7802caeSToomas Soome perror(gettext("Memory Allocation Failure")); 2058d7802caeSToomas Soome goto done; 2059d7802caeSToomas Soome } 2060d7802caeSToomas Soome if (asprintf(&stage1, "%s/%s", boot_dir, STAGE1) < 0) { 2061d7802caeSToomas Soome perror(gettext("Memory Allocation Failure")); 2062d7802caeSToomas Soome goto done; 2063d7802caeSToomas Soome } 2064d7802caeSToomas Soome if (asprintf(&stage2, "%s/%s", boot_dir, STAGE2) < 0) { 2065d7802caeSToomas Soome perror(gettext("Memory Allocation Failure")); 2066d7802caeSToomas Soome goto done; 2067d7802caeSToomas Soome } 2068d7802caeSToomas Soome if (asprintf(&efi32, "%s/%s", boot_dir, LOADER32) < 0) { 2069d7802caeSToomas Soome perror(gettext("Memory Allocation Failure")); 2070d7802caeSToomas Soome goto done; 2071d7802caeSToomas Soome } 2072d7802caeSToomas Soome if (asprintf(&efi64, "%s/%s", boot_dir, LOADER64) < 0) { 2073d7802caeSToomas Soome perror(gettext("Memory Allocation Failure")); 2074d7802caeSToomas Soome goto done; 2075d7802caeSToomas Soome } 2076d7802caeSToomas Soome break; 2077d7802caeSToomas Soome case 3: 2078d7802caeSToomas Soome if ((stage1 = strdup(argv[0])) == NULL) { 2079d7802caeSToomas Soome perror(gettext("Memory Allocation Failure")); 2080d7802caeSToomas Soome goto done; 2081d7802caeSToomas Soome } 2082d7802caeSToomas Soome if ((stage2 = strdup(argv[1])) == NULL) { 2083d7802caeSToomas Soome perror(gettext("Memory Allocation Failure")); 2084d7802caeSToomas Soome goto done; 2085d7802caeSToomas Soome } 2086d7802caeSToomas Soome if ((device_path = strdup(argv[2])) == NULL) { 2087d7802caeSToomas Soome perror(gettext("Memory Allocation Failure")); 2088d7802caeSToomas Soome goto done; 2089d7802caeSToomas Soome } 2090d7802caeSToomas Soome if (asprintf(&efi32, "%s/%s", boot_dir, LOADER32) < 0) { 2091d7802caeSToomas Soome perror(gettext("Memory Allocation Failure")); 2092d7802caeSToomas Soome goto done; 2093d7802caeSToomas Soome } 2094d7802caeSToomas Soome if (asprintf(&efi64, "%s/%s", boot_dir, LOADER64) < 0) { 2095d7802caeSToomas Soome perror(gettext("Memory Allocation Failure")); 2096d7802caeSToomas Soome goto done; 2097d7802caeSToomas Soome } 2098d7802caeSToomas Soome break; 2099d7802caeSToomas Soome default: 2100d7802caeSToomas Soome usage(progname, ret); 2101d7802caeSToomas Soome } 21020c946d80SToomas Soome 2103d7802caeSToomas Soome data.plist = malloc(sizeof (*data.plist)); 2104d7802caeSToomas Soome if (data.plist == NULL) { 2105d7802caeSToomas Soome perror(gettext("Memory Allocation Failure")); 2106d7802caeSToomas Soome goto done; 21070c946d80SToomas Soome } 2108d7802caeSToomas Soome STAILQ_INIT(data.plist); 21090c946d80SToomas Soome 21100c946d80SToomas Soome BOOT_DEBUG("device path: %s, stage1 path: %s bootblock path: %s\n", 2111d7802caeSToomas Soome device_path, stage1, stage2); 21120c946d80SToomas Soome 2113d7802caeSToomas Soome if (probe_device(&data, device_path)) { 2114d7802caeSToomas Soome /* Read all data. */ 2115d7802caeSToomas Soome STAILQ_FOREACH(pl, data.plist, pl_next) { 2116d7802caeSToomas Soome if (!pl->pl_cb.read(pl)) { 2117d7802caeSToomas Soome printf("\n"); 2118d7802caeSToomas Soome } 2119d7802caeSToomas Soome if (!pl->pl_cb.read_bbl(pl)) { 2120*46d70dceSToomas Soome /* 2121*46d70dceSToomas Soome * We will ignore ESP updates in case of 2122*46d70dceSToomas Soome * older system where we are missing 2123*46d70dceSToomas Soome * loader64.efi and loader32.efi. 2124*46d70dceSToomas Soome */ 2125*46d70dceSToomas Soome if (pl->pl_type != IB_BBLK_EFI) 2126*46d70dceSToomas Soome goto cleanup; 2127d7802caeSToomas Soome } 2128d7802caeSToomas Soome } 21290c946d80SToomas Soome 2130d7802caeSToomas Soome /* Prepare data. */ 2131d7802caeSToomas Soome prepare_bblocks(&data); 2132d7802caeSToomas Soome 2133d7802caeSToomas Soome /* Commit data to disk. */ 2134d7802caeSToomas Soome while ((pl = STAILQ_LAST(data.plist, partlist, pl_next)) != 2135d7802caeSToomas Soome NULL) { 2136d7802caeSToomas Soome if (pl->pl_cb.compare != NULL && 2137d7802caeSToomas Soome pl->pl_cb.compare(pl)) { 2138d7802caeSToomas Soome if (pl->pl_cb.install != NULL) 2139d7802caeSToomas Soome pl->pl_cb.install(&data, pl); 2140d7802caeSToomas Soome } else { 2141d7802caeSToomas Soome printf("\n"); 2142d7802caeSToomas Soome } 2143d7802caeSToomas Soome STAILQ_REMOVE(data.plist, pl, partlist, pl_next); 2144d7802caeSToomas Soome partlist_free(pl); 2145d7802caeSToomas Soome } 21460c946d80SToomas Soome } 2147d7802caeSToomas Soome ret = BC_SUCCESS; 21480c946d80SToomas Soome 2149d7802caeSToomas Soome cleanup: 2150d7802caeSToomas Soome while ((pl = STAILQ_LAST(data.plist, partlist, pl_next)) != NULL) { 2151d7802caeSToomas Soome STAILQ_REMOVE(data.plist, pl, partlist, pl_next); 2152d7802caeSToomas Soome partlist_free(pl); 21530c946d80SToomas Soome } 2154d7802caeSToomas Soome free(data.plist); 2155d7802caeSToomas Soome done: 21560c946d80SToomas Soome free(stage1); 2157d7802caeSToomas Soome free(stage2); 2158d7802caeSToomas Soome free(efi32); 2159d7802caeSToomas Soome free(efi64); 21600c946d80SToomas Soome free(device_path); 21610c946d80SToomas Soome return (ret); 21620c946d80SToomas Soome } 21630c946d80SToomas Soome 21640c946d80SToomas Soome /* 21650c946d80SToomas Soome * Retrieves from a device the extended information (einfo) associated to the 2166b6dfa2aeSToomas Soome * file or installed stage2. 2167b6dfa2aeSToomas Soome * Expects one parameter, the device path, in the form: /dev/rdsk/c?[t?]d?s0 2168b6dfa2aeSToomas Soome * or file name. 21690c946d80SToomas Soome * Returns: 21700c946d80SToomas Soome * - BC_SUCCESS (and prints out einfo contents depending on 'flags') 21710c946d80SToomas Soome * - BC_ERROR (on error) 21720c946d80SToomas Soome * - BC_NOEINFO (no extended information available) 21730c946d80SToomas Soome */ 21740c946d80SToomas Soome static int 2175d7802caeSToomas Soome handle_getinfo(char *progname, int argc, char **argv) 21760c946d80SToomas Soome { 2177d7802caeSToomas Soome struct partlist *pl; 2178d7802caeSToomas Soome ib_data_t data = { 0 }; 2179d7802caeSToomas Soome char *device_path; 21800c946d80SToomas Soome 2181d7802caeSToomas Soome if (argc != 1) { 21820c946d80SToomas Soome (void) fprintf(stderr, gettext("Missing parameter")); 2183bdecfb1eSToomas Soome usage(progname, BC_ERROR); 21840c946d80SToomas Soome } 21850c946d80SToomas Soome 2186d7802caeSToomas Soome if ((device_path = strdup(argv[0])) == NULL) { 2187d7802caeSToomas Soome perror(gettext("Memory Allocation Failure")); 2188d7802caeSToomas Soome return (BC_ERROR); 21890c946d80SToomas Soome } 21900c946d80SToomas Soome 2191d7802caeSToomas Soome data.plist = malloc(sizeof (*data.plist)); 2192d7802caeSToomas Soome if (data.plist == NULL) { 2193d7802caeSToomas Soome perror("malloc"); 2194d7802caeSToomas Soome free(device_path); 2195d7802caeSToomas Soome return (BC_ERROR); 21960c946d80SToomas Soome } 2197d7802caeSToomas Soome STAILQ_INIT(data.plist); 21980c946d80SToomas Soome 2199d7802caeSToomas Soome if (probe_device(&data, device_path)) { 2200d7802caeSToomas Soome STAILQ_FOREACH(pl, data.plist, pl_next) { 2201d7802caeSToomas Soome if (pl->pl_cb.read(pl)) 2202d7802caeSToomas Soome pl->pl_cb.print(pl); 2203d7802caeSToomas Soome else 2204d7802caeSToomas Soome printf("\n"); 2205d7802caeSToomas Soome } 22060c946d80SToomas Soome } 22070c946d80SToomas Soome 2208d7802caeSToomas Soome while ((pl = STAILQ_LAST(data.plist, partlist, pl_next)) != NULL) { 2209d7802caeSToomas Soome STAILQ_REMOVE(data.plist, pl, partlist, pl_next); 2210d7802caeSToomas Soome partlist_free(pl); 22110c946d80SToomas Soome } 2212d7802caeSToomas Soome free(data.plist); 22130c946d80SToomas Soome 2214d7802caeSToomas Soome return (BC_SUCCESS); 22150c946d80SToomas Soome } 22160c946d80SToomas Soome 22170c946d80SToomas Soome /* 22180c946d80SToomas Soome * Attempt to mirror (propagate) the current bootblock over the attaching disk. 22190c946d80SToomas Soome * 22200c946d80SToomas Soome * Returns: 22210c946d80SToomas Soome * - BC_SUCCESS (a successful propagation happened) 22220c946d80SToomas Soome * - BC_ERROR (an error occurred) 22230c946d80SToomas Soome * - BC_NOEXTRA (it is not possible to dump the current bootblock since 22240c946d80SToomas Soome * there is no multiboot information) 22250c946d80SToomas Soome */ 22260c946d80SToomas Soome static int 2227d7802caeSToomas Soome handle_mirror(char *progname, int argc, char **argv) 22280c946d80SToomas Soome { 2229d7802caeSToomas Soome ib_data_t src = { 0 }; 2230d7802caeSToomas Soome ib_data_t dest = { 0 }; 2231d7802caeSToomas Soome struct partlist *pl_src, *pl_dest; 2232d7802caeSToomas Soome char *curr_device_path = NULL; 2233d7802caeSToomas Soome char *attach_device_path = NULL; 22340c946d80SToomas Soome int retval = BC_ERROR; 22350c946d80SToomas Soome 2236d7802caeSToomas Soome if (argc == 2) { 2237d7802caeSToomas Soome curr_device_path = strdup(argv[0]); 2238d7802caeSToomas Soome attach_device_path = strdup(argv[1]); 2239d7802caeSToomas Soome } 22400c946d80SToomas Soome 22410c946d80SToomas Soome if (!curr_device_path || !attach_device_path) { 2242d7802caeSToomas Soome free(curr_device_path); 2243d7802caeSToomas Soome free(attach_device_path); 22440c946d80SToomas Soome (void) fprintf(stderr, gettext("Missing parameter")); 2245bdecfb1eSToomas Soome usage(progname, BC_ERROR); 22460c946d80SToomas Soome } 22470c946d80SToomas Soome BOOT_DEBUG("Current device path is: %s, attaching device path is: " 22480c946d80SToomas Soome " %s\n", curr_device_path, attach_device_path); 22490c946d80SToomas Soome 2250d7802caeSToomas Soome src.plist = malloc(sizeof (*src.plist)); 2251d7802caeSToomas Soome if (src.plist == NULL) { 2252d7802caeSToomas Soome perror("malloc"); 2253d7802caeSToomas Soome return (BC_ERROR); 2254d7802caeSToomas Soome } 2255d7802caeSToomas Soome STAILQ_INIT(src.plist); 2256d7802caeSToomas Soome 2257d7802caeSToomas Soome dest.plist = malloc(sizeof (*dest.plist)); 2258d7802caeSToomas Soome if (dest.plist == NULL) { 2259d7802caeSToomas Soome perror("malloc"); 2260d7802caeSToomas Soome goto out; 2261d7802caeSToomas Soome } 2262d7802caeSToomas Soome STAILQ_INIT(dest.plist); 22630c946d80SToomas Soome 2264d7802caeSToomas Soome if (!probe_device(&src, curr_device_path)) { 22650c946d80SToomas Soome (void) fprintf(stderr, gettext("Unable to gather device " 22660c946d80SToomas Soome "information from %s (current device)\n"), 22670c946d80SToomas Soome curr_device_path); 2268d7802caeSToomas Soome goto out; 22690c946d80SToomas Soome } 22700c946d80SToomas Soome 2271d7802caeSToomas Soome if (!probe_device(&dest, attach_device_path) != BC_SUCCESS) { 22720c946d80SToomas Soome (void) fprintf(stderr, gettext("Unable to gather device " 22730c946d80SToomas Soome "information from %s (attaching device)\n"), 22740c946d80SToomas Soome attach_device_path); 2275d7802caeSToomas Soome goto cleanup_src; 22760c946d80SToomas Soome } 22770c946d80SToomas Soome 2278d7802caeSToomas Soome write_mbr = true; 2279d7802caeSToomas Soome force_mbr = true; 2280d7802caeSToomas Soome 2281d7802caeSToomas Soome pl_dest = STAILQ_FIRST(dest.plist); 2282d7802caeSToomas Soome STAILQ_FOREACH(pl_src, src.plist, pl_next) { 2283d7802caeSToomas Soome if (pl_dest == NULL) { 2284d7802caeSToomas Soome (void) fprintf(stderr, 2285d7802caeSToomas Soome gettext("Destination disk layout is different " 2286d7802caeSToomas Soome "from source, can not mirror.\n")); 2287d7802caeSToomas Soome goto cleanup; 2288d7802caeSToomas Soome } 2289d7802caeSToomas Soome if (!pl_src->pl_cb.read(pl_src)) { 2290d7802caeSToomas Soome (void) fprintf(stderr, gettext("Failed to read " 2291d7802caeSToomas Soome "boot block from %s\n"), pl_src->pl_devname); 2292d7802caeSToomas Soome goto cleanup; 2293d7802caeSToomas Soome } 2294d7802caeSToomas Soome if (!pl_dest->pl_cb.read(pl_dest)) { 2295d7802caeSToomas Soome (void) fprintf(stderr, gettext("Failed to read " 2296d7802caeSToomas Soome "boot block from %s\n"), pl_dest->pl_devname); 2297d7802caeSToomas Soome } 2298d7802caeSToomas Soome 2299d7802caeSToomas Soome /* Set source pl_stage to destination source data */ 2300d7802caeSToomas Soome pl_dest->pl_src_data = pl_src->pl_stage; 2301d7802caeSToomas Soome pl_src->pl_stage = NULL; 23020c946d80SToomas Soome 2303d7802caeSToomas Soome pl_dest = STAILQ_NEXT(pl_dest, pl_next); 23040c946d80SToomas Soome } 23050c946d80SToomas Soome 2306d7802caeSToomas Soome /* Prepare data. */ 2307d7802caeSToomas Soome prepare_bblocks(&dest); 23080c946d80SToomas Soome 2309d7802caeSToomas Soome /* Commit data to disk. */ 2310d7802caeSToomas Soome while ((pl_dest = STAILQ_LAST(dest.plist, partlist, pl_next)) != NULL) { 2311d7802caeSToomas Soome pl_dest->pl_cb.install(&dest, pl_dest); 2312d7802caeSToomas Soome STAILQ_REMOVE(dest.plist, pl_dest, partlist, pl_next); 2313d7802caeSToomas Soome partlist_free(pl_dest); 2314d7802caeSToomas Soome 2315d7802caeSToomas Soome /* Free source list */ 2316d7802caeSToomas Soome pl_src = STAILQ_LAST(src.plist, partlist, pl_next); 2317d7802caeSToomas Soome STAILQ_REMOVE(src.plist, pl_src, partlist, pl_next); 2318d7802caeSToomas Soome partlist_free(pl_src); 2319d7802caeSToomas Soome } 2320d7802caeSToomas Soome retval = BC_SUCCESS; 2321d7802caeSToomas Soome 2322d7802caeSToomas Soome cleanup: 2323d7802caeSToomas Soome while ((pl_dest = STAILQ_LAST(dest.plist, partlist, pl_next)) != NULL) { 2324d7802caeSToomas Soome STAILQ_REMOVE(dest.plist, pl_dest, partlist, pl_next); 2325d7802caeSToomas Soome partlist_free(pl_dest); 2326d7802caeSToomas Soome } 2327d7802caeSToomas Soome free(dest.plist); 2328d7802caeSToomas Soome cleanup_src: 2329d7802caeSToomas Soome while ((pl_src = STAILQ_LAST(src.plist, partlist, pl_next)) != NULL) { 2330d7802caeSToomas Soome STAILQ_REMOVE(src.plist, pl_src, partlist, pl_next); 2331d7802caeSToomas Soome partlist_free(pl_src); 2332d7802caeSToomas Soome } 2333d7802caeSToomas Soome free(src.plist); 2334d7802caeSToomas Soome out: 23350c946d80SToomas Soome free(curr_device_path); 23360c946d80SToomas Soome free(attach_device_path); 23370c946d80SToomas Soome return (retval); 23380c946d80SToomas Soome } 23390c946d80SToomas Soome 2340d7802caeSToomas Soome #define USAGE_STRING \ 2341d7802caeSToomas Soome "Usage:\t%s [-fFmn] [-b boot_dir] [-u verstr]\n" \ 2342d7802caeSToomas Soome "\t\t[stage1 stage2] raw-device\n" \ 2343d7802caeSToomas Soome "\t%s -M [-n] raw-device attach-raw-device\n" \ 2344d7802caeSToomas Soome "\t%s [-e|-V] -i raw-device | file\n" 23450c946d80SToomas Soome 23460c946d80SToomas Soome #define CANON_USAGE_STR gettext(USAGE_STRING) 23470c946d80SToomas Soome 23480c946d80SToomas Soome static void 2349bdecfb1eSToomas Soome usage(char *progname, int rc) 23500c946d80SToomas Soome { 23510c946d80SToomas Soome (void) fprintf(stdout, CANON_USAGE_STR, progname, progname, progname); 2352d7802caeSToomas Soome fini_yes(); 2353bdecfb1eSToomas Soome exit(rc); 23540c946d80SToomas Soome } 23550c946d80SToomas Soome 23560c946d80SToomas Soome int 23570c946d80SToomas Soome main(int argc, char **argv) 23580c946d80SToomas Soome { 23590c946d80SToomas Soome int opt; 23600c946d80SToomas Soome int ret; 23610c946d80SToomas Soome char *progname; 2362d7802caeSToomas Soome struct stat sb; 23630c946d80SToomas Soome 23640c946d80SToomas Soome (void) setlocale(LC_ALL, ""); 23650c946d80SToomas Soome (void) textdomain(TEXT_DOMAIN); 2366bdecfb1eSToomas Soome if (init_yes() < 0) 2367bdecfb1eSToomas Soome errx(BC_ERROR, gettext(ERR_MSG_INIT_YES), strerror(errno)); 2368bdecfb1eSToomas Soome 2369d7802caeSToomas Soome /* Needed for mount pcfs. */ 2370d7802caeSToomas Soome tzset(); 2371d7802caeSToomas Soome 2372bdecfb1eSToomas Soome /* Determine our name */ 2373bdecfb1eSToomas Soome progname = basename(argv[0]); 23740c946d80SToomas Soome 2375d7802caeSToomas Soome while ((opt = getopt(argc, argv, "b:deFfhiMmnu:V")) != EOF) { 23760c946d80SToomas Soome switch (opt) { 2377d7802caeSToomas Soome case 'b': 2378d7802caeSToomas Soome boot_dir = strdup(optarg); 2379d7802caeSToomas Soome if (boot_dir == NULL) { 2380d7802caeSToomas Soome err(BC_ERROR, 2381d7802caeSToomas Soome gettext("Memory allocation failure")); 2382d7802caeSToomas Soome } 2383d7802caeSToomas Soome if (lstat(boot_dir, &sb) != 0) { 2384d7802caeSToomas Soome err(BC_ERROR, boot_dir); 2385d7802caeSToomas Soome } 2386d7802caeSToomas Soome if (!S_ISDIR(sb.st_mode)) { 2387d7802caeSToomas Soome errx(BC_ERROR, gettext("%s: not a directory"), 2388d7802caeSToomas Soome boot_dir); 2389d7802caeSToomas Soome } 2390d7802caeSToomas Soome break; 23910c946d80SToomas Soome case 'd': 2392d7802caeSToomas Soome boot_debug = true; 23930c946d80SToomas Soome break; 23940c946d80SToomas Soome case 'e': 2395d7802caeSToomas Soome strip = true; 23960c946d80SToomas Soome break; 23970c946d80SToomas Soome case 'F': 2398d7802caeSToomas Soome force_update = true; 23990c946d80SToomas Soome break; 24000c946d80SToomas Soome case 'f': 2401d7802caeSToomas Soome force_mbr = true; 24020c946d80SToomas Soome break; 24030c946d80SToomas Soome case 'h': 2404bdecfb1eSToomas Soome usage(progname, BC_SUCCESS); 24050c946d80SToomas Soome break; 24060c946d80SToomas Soome case 'i': 2407d7802caeSToomas Soome do_getinfo = true; 24080c946d80SToomas Soome break; 24090c946d80SToomas Soome case 'M': 2410d7802caeSToomas Soome do_mirror_bblk = true; 24110c946d80SToomas Soome break; 24120c946d80SToomas Soome case 'm': 2413d7802caeSToomas Soome write_mbr = true; 24140c946d80SToomas Soome break; 24150c946d80SToomas Soome case 'n': 2416d7802caeSToomas Soome nowrite = true; 24170c946d80SToomas Soome break; 24180c946d80SToomas Soome case 'u': 2419d7802caeSToomas Soome do_version = true; 24200c946d80SToomas Soome 2421bdecfb1eSToomas Soome update_str = strdup(optarg); 24220c946d80SToomas Soome if (update_str == NULL) { 24230c946d80SToomas Soome perror(gettext("Memory allocation failure")); 24240c946d80SToomas Soome exit(BC_ERROR); 24250c946d80SToomas Soome } 24260c946d80SToomas Soome break; 24270c946d80SToomas Soome case 'V': 2428d7802caeSToomas Soome verbose_dump = true; 24290c946d80SToomas Soome break; 24300c946d80SToomas Soome default: 24310c946d80SToomas Soome /* fall through to process non-optional args */ 24320c946d80SToomas Soome break; 24330c946d80SToomas Soome } 24340c946d80SToomas Soome } 24350c946d80SToomas Soome 24360c946d80SToomas Soome /* check arguments */ 24370c946d80SToomas Soome check_options(progname); 24380c946d80SToomas Soome 24390c946d80SToomas Soome if (nowrite) 24400c946d80SToomas Soome (void) fprintf(stdout, gettext("Dry run requested. Nothing will" 24410c946d80SToomas Soome " be written to disk.\n")); 24420c946d80SToomas Soome 24430c946d80SToomas Soome if (do_getinfo) { 2444d7802caeSToomas Soome ret = handle_getinfo(progname, argc - optind, argv + optind); 24450c946d80SToomas Soome } else if (do_mirror_bblk) { 2446d7802caeSToomas Soome ret = handle_mirror(progname, argc - optind, argv + optind); 24470c946d80SToomas Soome } else { 2448d7802caeSToomas Soome ret = handle_install(progname, argc - optind, argv + optind); 24490c946d80SToomas Soome } 2450d7802caeSToomas Soome fini_yes(); 24510c946d80SToomas Soome return (ret); 24520c946d80SToomas Soome } 24530c946d80SToomas Soome 24540c946d80SToomas Soome #define MEANINGLESS_OPT gettext("%s specified but meaningless, ignoring\n") 24550c946d80SToomas Soome static void 24560c946d80SToomas Soome check_options(char *progname) 24570c946d80SToomas Soome { 24580c946d80SToomas Soome if (do_getinfo && do_mirror_bblk) { 24590c946d80SToomas Soome (void) fprintf(stderr, gettext("Only one of -M and -i can be " 24600c946d80SToomas Soome "specified at the same time\n")); 2461bdecfb1eSToomas Soome usage(progname, BC_ERROR); 24620c946d80SToomas Soome } 24630c946d80SToomas Soome 24640c946d80SToomas Soome if (do_mirror_bblk) { 24650c946d80SToomas Soome /* 24660c946d80SToomas Soome * -u and -F may actually reflect a user intent that is not 24670c946d80SToomas Soome * correct with this command (mirror can be interpreted 24680c946d80SToomas Soome * "similar" to install. Emit a message and continue. 24690c946d80SToomas Soome * -e and -V have no meaning, be quiet here and only report the 24700c946d80SToomas Soome * incongruence if a debug output is requested. 24710c946d80SToomas Soome */ 24720c946d80SToomas Soome if (do_version) { 24730c946d80SToomas Soome (void) fprintf(stderr, MEANINGLESS_OPT, "-u"); 2474d7802caeSToomas Soome do_version = false; 24750c946d80SToomas Soome } 24760c946d80SToomas Soome if (force_update) { 24770c946d80SToomas Soome (void) fprintf(stderr, MEANINGLESS_OPT, "-F"); 2478d7802caeSToomas Soome force_update = false; 24790c946d80SToomas Soome } 24800c946d80SToomas Soome if (strip || verbose_dump) { 24810c946d80SToomas Soome BOOT_DEBUG(MEANINGLESS_OPT, "-e|-V"); 2482d7802caeSToomas Soome strip = false; 2483d7802caeSToomas Soome verbose_dump = false; 24840c946d80SToomas Soome } 24850c946d80SToomas Soome } 24860c946d80SToomas Soome 2487d7802caeSToomas Soome if ((strip || verbose_dump) && !do_getinfo) 2488d7802caeSToomas Soome usage(progname, BC_ERROR); 2489d7802caeSToomas Soome 24900c946d80SToomas Soome if (do_getinfo) { 24910c946d80SToomas Soome if (write_mbr || force_mbr || do_version || force_update) { 24920c946d80SToomas Soome BOOT_DEBUG(MEANINGLESS_OPT, "-m|-f|-u|-F"); 2493d7802caeSToomas Soome write_mbr = force_mbr = do_version = false; 2494d7802caeSToomas Soome force_update = false; 24950c946d80SToomas Soome } 24960c946d80SToomas Soome } 24970c946d80SToomas Soome } 2498