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. 24*d7802caeSToomas Soome * Copyright 2019 Toomas Soome <tsoome@me.com> 250c946d80SToomas Soome */ 260c946d80SToomas Soome 270c946d80SToomas Soome #include <stdio.h> 28*d7802caeSToomas 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> 37*d7802caeSToomas Soome #include <time.h> 38*d7802caeSToomas 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> 48*d7802caeSToomas Soome #include <sys/queue.h> 49*d7802caeSToomas Soome #include <sys/mount.h> 50*d7802caeSToomas Soome #include <sys/mntent.h> 51*d7802caeSToomas Soome #include <sys/mnttab.h> 52*d7802caeSToomas 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 108*d7802caeSToomas Soome static bool write_mbr = false; 109*d7802caeSToomas Soome static bool force_mbr = false; 110*d7802caeSToomas Soome static bool force_update = false; 111*d7802caeSToomas Soome static bool do_getinfo = false; 112*d7802caeSToomas Soome static bool do_version = false; 113*d7802caeSToomas Soome static bool do_mirror_bblk = false; 114*d7802caeSToomas Soome static bool strip = false; 115*d7802caeSToomas Soome static bool verbose_dump = false; 116*d7802caeSToomas Soome static size_t sector_size = SECTOR_SIZE; 1170c946d80SToomas Soome 1180c946d80SToomas Soome /* Versioning string, if present. */ 1190c946d80SToomas Soome static char *update_str; 1200c946d80SToomas Soome 121*d7802caeSToomas Soome /* Default location of boot programs. */ 122*d7802caeSToomas Soome static char *boot_dir = "/boot"; 123*d7802caeSToomas Soome 124*d7802caeSToomas Soome /* Our boot programs */ 125*d7802caeSToomas Soome #define STAGE1 "pmbr" 126*d7802caeSToomas Soome #define STAGE2 "gptzfsboot" 127*d7802caeSToomas Soome #define BOOTIA32 "bootia32.efi" 128*d7802caeSToomas Soome #define BOOTX64 "bootx64.efi" 129*d7802caeSToomas Soome #define LOADER32 "loader32.efi" 130*d7802caeSToomas Soome #define LOADER64 "loader64.efi" 131*d7802caeSToomas Soome 132*d7802caeSToomas Soome static char *stage1; 133*d7802caeSToomas Soome static char *stage2; 134*d7802caeSToomas Soome static char *efi32; 135*d7802caeSToomas Soome static char *efi64; 136*d7802caeSToomas Soome 137*d7802caeSToomas Soome #define GRUB_VERSION_OFF (0x3e) 138*d7802caeSToomas Soome #define GRUB_COMPAT_VERSION_MAJOR 3 139*d7802caeSToomas Soome #define GRUB_COMPAT_VERSION_MINOR 2 140*d7802caeSToomas Soome #define GRUB_VERSION (2 << 8 | 3) /* 3.2 */ 141*d7802caeSToomas Soome 142*d7802caeSToomas Soome #define LOADER_VERSION (1) 143*d7802caeSToomas Soome #define LOADER_JOYENT_VERSION (2) 144*d7802caeSToomas Soome 145*d7802caeSToomas Soome typedef enum { 146*d7802caeSToomas Soome MBR_TYPE_UNKNOWN, 147*d7802caeSToomas Soome MBR_TYPE_GRUB1, 148*d7802caeSToomas Soome MBR_TYPE_LOADER, 149*d7802caeSToomas Soome MBR_TYPE_LOADER_JOYENT, 150*d7802caeSToomas Soome } mbr_type_t; 151*d7802caeSToomas 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 *); 160*d7802caeSToomas Soome static int open_device(const char *); 161*d7802caeSToomas Soome static char *make_blkdev(const char *); 1620c946d80SToomas Soome 163*d7802caeSToomas Soome static int read_bootblock_from_file(const char *, ib_bootblock_t *); 1640c946d80SToomas Soome static void add_bootblock_einfo(ib_bootblock_t *, char *); 165*d7802caeSToomas Soome static void prepare_bootblock(ib_data_t *, struct partlist *, char *); 166*d7802caeSToomas Soome static int handle_install(char *, int, char **); 167*d7802caeSToomas Soome static int handle_getinfo(char *, int, char **); 168*d7802caeSToomas Soome static int handle_mirror(char *, int, char **); 169bdecfb1eSToomas Soome static void usage(char *, int) __NORETURN; 1700c946d80SToomas Soome 171*d7802caeSToomas Soome static char * 172*d7802caeSToomas Soome stagefs_mount(char *blkdev, struct partlist *plist) 1730c946d80SToomas Soome { 174*d7802caeSToomas Soome char *path; 175*d7802caeSToomas Soome char optbuf[MAX_MNTOPT_STR] = { '\0', }; 176*d7802caeSToomas Soome char *template = strdup("/tmp/ibootXXXXXX"); 177*d7802caeSToomas Soome int ret; 1780c946d80SToomas Soome 179*d7802caeSToomas Soome if (template == NULL) 180*d7802caeSToomas Soome return (NULL); 1810c946d80SToomas Soome 182*d7802caeSToomas Soome if ((path = mkdtemp(template)) == NULL) { 183*d7802caeSToomas Soome free(template); 184*d7802caeSToomas Soome return (NULL); 1850c946d80SToomas Soome } 186*d7802caeSToomas Soome 187*d7802caeSToomas Soome (void) snprintf(optbuf, MAX_MNTOPT_STR, "timezone=%d", 188*d7802caeSToomas Soome timezone); 189*d7802caeSToomas Soome ret = mount(blkdev, path, MS_OPTIONSTR, 190*d7802caeSToomas Soome MNTTYPE_PCFS, NULL, 0, optbuf, MAX_MNTOPT_STR); 191*d7802caeSToomas Soome if (ret != 0) { 192*d7802caeSToomas Soome (void) rmdir(path); 193*d7802caeSToomas Soome free(path); 194*d7802caeSToomas Soome path = NULL; 195*d7802caeSToomas Soome } 196*d7802caeSToomas Soome plist->pl_device->stage.mntpnt = path; 197*d7802caeSToomas Soome return (path); 1980c946d80SToomas Soome } 1990c946d80SToomas Soome 200*d7802caeSToomas Soome static void 201*d7802caeSToomas Soome install_stage1_cb(void *data, struct partlist *plist) 2020c946d80SToomas Soome { 203*d7802caeSToomas Soome int rv, fd; 204*d7802caeSToomas Soome ib_device_t *device = plist->pl_device; 2050c946d80SToomas Soome 206*d7802caeSToomas Soome if (plist->pl_type == IB_BBLK_MBR && !write_mbr) 207*d7802caeSToomas Soome return; 2080c946d80SToomas Soome 209*d7802caeSToomas Soome if ((fd = open_device(plist->pl_devname)) == -1) { 210*d7802caeSToomas Soome (void) fprintf(stdout, gettext("cannot open " 211*d7802caeSToomas Soome "device %s\n"), plist->pl_devname); 2120c946d80SToomas Soome perror("open"); 213*d7802caeSToomas Soome return; 2140c946d80SToomas Soome } 2150c946d80SToomas Soome 216*d7802caeSToomas Soome rv = write_out(fd, plist->pl_stage, sector_size, 0); 217*d7802caeSToomas Soome if (rv != BC_SUCCESS) { 218*d7802caeSToomas Soome (void) fprintf(stdout, gettext("cannot write " 219*d7802caeSToomas Soome "partition boot sector\n")); 220*d7802caeSToomas Soome perror("write"); 221*d7802caeSToomas Soome } else { 222*d7802caeSToomas Soome (void) fprintf(stdout, gettext("stage1 written to " 223*d7802caeSToomas Soome "%s %d sector 0 (abs %d)\n"), 224*d7802caeSToomas Soome device->devtype == IB_DEV_MBR? "partition" : "slice", 225*d7802caeSToomas Soome device->stage.id, device->stage.start); 2260c946d80SToomas Soome } 227*d7802caeSToomas Soome } 2280c946d80SToomas Soome 229*d7802caeSToomas Soome static void 230*d7802caeSToomas Soome install_stage2_cb(void *data, struct partlist *plist) 231*d7802caeSToomas Soome { 232*d7802caeSToomas Soome ib_bootblock_t *bblock = plist->pl_src_data; 233*d7802caeSToomas Soome int fd, ret; 234*d7802caeSToomas Soome off_t offset; 235*d7802caeSToomas Soome uint64_t abs; 2360c946d80SToomas Soome 237*d7802caeSToomas Soome /* 238*d7802caeSToomas Soome * ZFS bootblock area is 3.5MB, make sure we can fit. 239*d7802caeSToomas Soome * buf_size is size of bootblk+EINFO. 240*d7802caeSToomas Soome */ 241*d7802caeSToomas Soome if (bblock->buf_size > BBLK_ZFS_BLK_SIZE) { 242*d7802caeSToomas Soome (void) fprintf(stderr, gettext("bootblock is too large\n")); 243*d7802caeSToomas Soome return; 244*d7802caeSToomas Soome } 2450c946d80SToomas Soome 246*d7802caeSToomas Soome abs = plist->pl_device->stage.start + plist->pl_device->stage.offset; 247*d7802caeSToomas Soome 248*d7802caeSToomas Soome if ((fd = open_device(plist->pl_devname)) == -1) { 249*d7802caeSToomas Soome (void) fprintf(stdout, gettext("cannot open " 250*d7802caeSToomas Soome "device %s\n"), plist->pl_devname); 251*d7802caeSToomas Soome perror("open"); 252*d7802caeSToomas Soome return; 253*d7802caeSToomas Soome } 254*d7802caeSToomas Soome offset = plist->pl_device->stage.offset * SECTOR_SIZE; 255*d7802caeSToomas Soome ret = write_out(fd, bblock->buf, bblock->buf_size, offset); 256*d7802caeSToomas Soome (void) close(fd); 257*d7802caeSToomas Soome if (ret != BC_SUCCESS) { 258*d7802caeSToomas Soome BOOT_DEBUG("Error writing the ZFS bootblock " 259*d7802caeSToomas Soome "to %s at offset %d\n", plist->pl_devname, offset); 260*d7802caeSToomas Soome return; 261*d7802caeSToomas Soome } 262*d7802caeSToomas Soome (void) fprintf(stdout, gettext("bootblock written for %s," 263*d7802caeSToomas Soome " %d sectors starting at %d (abs %lld)\n"), plist->pl_devname, 264*d7802caeSToomas Soome (bblock->buf_size / SECTOR_SIZE) + 1, offset / SECTOR_SIZE, abs); 265*d7802caeSToomas Soome } 266*d7802caeSToomas Soome 267*d7802caeSToomas Soome static bool 268*d7802caeSToomas Soome mkfs_pcfs(const char *dev) 269*d7802caeSToomas Soome { 270*d7802caeSToomas Soome pid_t pid, w; 271*d7802caeSToomas Soome posix_spawnattr_t attr; 272*d7802caeSToomas Soome posix_spawn_file_actions_t file_actions; 273*d7802caeSToomas Soome int status; 274*d7802caeSToomas Soome char *cmd[7]; 275*d7802caeSToomas Soome 276*d7802caeSToomas Soome if (posix_spawnattr_init(&attr)) 277*d7802caeSToomas Soome return (false); 278*d7802caeSToomas Soome if (posix_spawn_file_actions_init(&file_actions)) { 279*d7802caeSToomas Soome (void) posix_spawnattr_destroy(&attr); 280*d7802caeSToomas Soome return (false); 281*d7802caeSToomas Soome } 282*d7802caeSToomas Soome 283*d7802caeSToomas Soome if (posix_spawnattr_setflags(&attr, 284*d7802caeSToomas Soome POSIX_SPAWN_NOSIGCHLD_NP | POSIX_SPAWN_WAITPID_NP)) { 285*d7802caeSToomas Soome (void) posix_spawnattr_destroy(&attr); 286*d7802caeSToomas Soome (void) posix_spawn_file_actions_destroy(&file_actions); 287*d7802caeSToomas Soome return (false); 288*d7802caeSToomas Soome } 289*d7802caeSToomas Soome if (posix_spawn_file_actions_addopen(&file_actions, 0, "/dev/null", 290*d7802caeSToomas Soome O_RDONLY, 0)) { 291*d7802caeSToomas Soome (void) posix_spawnattr_destroy(&attr); 292*d7802caeSToomas Soome (void) posix_spawn_file_actions_destroy(&file_actions); 293*d7802caeSToomas Soome return (false); 294*d7802caeSToomas Soome } 295*d7802caeSToomas Soome 296*d7802caeSToomas Soome cmd[0] = "/usr/sbin/mkfs"; 297*d7802caeSToomas Soome cmd[1] = "-F"; 298*d7802caeSToomas Soome cmd[2] = "pcfs"; 299*d7802caeSToomas Soome cmd[3] = "-o"; 300*d7802caeSToomas Soome cmd[4] = "fat=32"; 301*d7802caeSToomas Soome cmd[5] = (char *)dev; 302*d7802caeSToomas Soome cmd[6] = NULL; 303*d7802caeSToomas Soome 304*d7802caeSToomas Soome if (posix_spawn(&pid, cmd[0], &file_actions, &attr, cmd, NULL)) 305*d7802caeSToomas Soome return (false); 306*d7802caeSToomas Soome (void) posix_spawnattr_destroy(&attr); 307*d7802caeSToomas Soome (void) posix_spawn_file_actions_destroy(&file_actions); 308*d7802caeSToomas Soome 309*d7802caeSToomas Soome do { 310*d7802caeSToomas Soome w = waitpid(pid, &status, 0); 311*d7802caeSToomas Soome } while (w == -1 && errno == EINTR); 312*d7802caeSToomas Soome if (w == -1) 313*d7802caeSToomas Soome status = -1; 314*d7802caeSToomas Soome 315*d7802caeSToomas Soome return (status != -1); 316*d7802caeSToomas Soome } 317*d7802caeSToomas Soome 318*d7802caeSToomas Soome static void 319*d7802caeSToomas Soome install_esp_cb(void *data, struct partlist *plist) 320*d7802caeSToomas Soome { 321*d7802caeSToomas Soome fstyp_handle_t fhdl; 322*d7802caeSToomas Soome const char *fident; 323*d7802caeSToomas Soome bool pcfs; 324*d7802caeSToomas Soome char *blkdev, *path, *file; 325*d7802caeSToomas Soome FILE *fp; 326*d7802caeSToomas Soome struct mnttab mp, mpref = { 0 }; 327*d7802caeSToomas Soome ib_bootblock_t *bblock = plist->pl_src_data; 328*d7802caeSToomas Soome int fd, ret; 329*d7802caeSToomas Soome 330*d7802caeSToomas Soome if ((fd = open_device(plist->pl_devname)) == -1) 331*d7802caeSToomas Soome return; 332*d7802caeSToomas Soome 333*d7802caeSToomas Soome if (fstyp_init(fd, 0, NULL, &fhdl) != 0) { 334*d7802caeSToomas Soome (void) close(fd); 335*d7802caeSToomas Soome return; 336*d7802caeSToomas Soome } 337*d7802caeSToomas Soome 338*d7802caeSToomas Soome pcfs = false; 339*d7802caeSToomas Soome if (fstyp_ident(fhdl, NULL, &fident) == 0) { 340*d7802caeSToomas Soome if (strcmp(fident, MNTTYPE_PCFS) == 0) 341*d7802caeSToomas Soome pcfs = true; 342*d7802caeSToomas Soome } 343*d7802caeSToomas Soome fstyp_fini(fhdl); 344*d7802caeSToomas Soome (void) close(fd); 345*d7802caeSToomas Soome 346*d7802caeSToomas Soome if (!pcfs) { 347*d7802caeSToomas Soome (void) printf(gettext("Creating pcfs on ESP %s\n"), 348*d7802caeSToomas Soome plist->pl_devname); 349*d7802caeSToomas Soome 350*d7802caeSToomas Soome if (!mkfs_pcfs(plist->pl_devname)) { 351*d7802caeSToomas Soome (void) fprintf(stderr, gettext("mkfs -F pcfs failed " 352*d7802caeSToomas Soome "on %s\n"), plist->pl_devname); 353*d7802caeSToomas Soome return; 354*d7802caeSToomas Soome } 355*d7802caeSToomas Soome } 356*d7802caeSToomas Soome blkdev = make_blkdev(plist->pl_devname); 357*d7802caeSToomas Soome if (blkdev == NULL) 358*d7802caeSToomas Soome return; 359*d7802caeSToomas Soome 360*d7802caeSToomas Soome fp = fopen(MNTTAB, "r"); 361*d7802caeSToomas Soome if (fp == NULL) { 362*d7802caeSToomas Soome perror("fopen"); 363*d7802caeSToomas Soome free(blkdev); 364*d7802caeSToomas Soome return; 365*d7802caeSToomas Soome } 366*d7802caeSToomas Soome 367*d7802caeSToomas Soome mpref.mnt_special = blkdev; 368*d7802caeSToomas Soome ret = getmntany(fp, &mp, &mpref); 369*d7802caeSToomas Soome (void) fclose(fp); 370*d7802caeSToomas Soome if (ret == 0) 371*d7802caeSToomas Soome path = mp.mnt_mountp; 372*d7802caeSToomas Soome else 373*d7802caeSToomas Soome path = stagefs_mount(blkdev, plist); 374*d7802caeSToomas Soome 375*d7802caeSToomas Soome free(blkdev); 376*d7802caeSToomas Soome if (path == NULL) 377*d7802caeSToomas Soome return; 378*d7802caeSToomas Soome 379*d7802caeSToomas Soome if (asprintf(&file, "%s%s", path, "/EFI") < 0) { 3800c946d80SToomas Soome perror(gettext("Memory allocation failure")); 381*d7802caeSToomas Soome return; 3820c946d80SToomas Soome } 3830c946d80SToomas Soome 384*d7802caeSToomas Soome ret = mkdir(file, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); 385*d7802caeSToomas Soome if (ret == 0 || errno == EEXIST) { 386*d7802caeSToomas Soome free(file); 387*d7802caeSToomas Soome if (asprintf(&file, "%s%s", path, "/EFI/Boot") < 0) { 388*d7802caeSToomas Soome perror(gettext("Memory allocation failure")); 389*d7802caeSToomas Soome return; 390*d7802caeSToomas Soome } 391*d7802caeSToomas Soome ret = mkdir(file, 392*d7802caeSToomas Soome S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); 393*d7802caeSToomas Soome if (errno == EEXIST) 394*d7802caeSToomas Soome ret = 0; 395*d7802caeSToomas Soome } 396*d7802caeSToomas Soome free(file); 397*d7802caeSToomas Soome if (ret < 0) { 398*d7802caeSToomas Soome perror("mkdir"); 399*d7802caeSToomas Soome return; 4000c946d80SToomas Soome } 4010c946d80SToomas Soome 402*d7802caeSToomas Soome if (asprintf(&file, "%s%s", path, plist->pl_device->stage.path) < 0) { 403*d7802caeSToomas Soome perror(gettext("Memory allocation failure")); 404*d7802caeSToomas Soome return; 405*d7802caeSToomas Soome } 406*d7802caeSToomas Soome 407*d7802caeSToomas Soome /* Write stage file. Should create temp file and rename. */ 408*d7802caeSToomas Soome (void) chmod(file, S_IRUSR | S_IWUSR); 409*d7802caeSToomas Soome fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); 410*d7802caeSToomas Soome if (fd != -1) { 411*d7802caeSToomas Soome ret = write_out(fd, bblock->buf, bblock->buf_size, 0); 412*d7802caeSToomas Soome if (ret == BC_SUCCESS) { 413*d7802caeSToomas Soome (void) fprintf(stdout, 414*d7802caeSToomas Soome gettext("bootblock written to %s\n"), file); 415*d7802caeSToomas Soome } else { 416*d7802caeSToomas Soome (void) fprintf(stdout, 417*d7802caeSToomas Soome gettext("error while writing %s\n"), file); 418*d7802caeSToomas Soome } 419*d7802caeSToomas Soome (void) fchmod(fd, S_IRUSR | S_IRGRP | S_IROTH); 420*d7802caeSToomas Soome (void) close(fd); 421*d7802caeSToomas Soome } 422*d7802caeSToomas Soome free(file); 423*d7802caeSToomas Soome } 424*d7802caeSToomas Soome 425*d7802caeSToomas Soome /* 426*d7802caeSToomas Soome * MBR setup only depends on write_mbr toggle. 427*d7802caeSToomas Soome */ 428*d7802caeSToomas Soome static bool 429*d7802caeSToomas Soome compare_mbr_cb(struct partlist *plist) 430*d7802caeSToomas Soome { 431*d7802caeSToomas Soome /* get confirmation for -m */ 432*d7802caeSToomas Soome if (write_mbr && !force_mbr) { 433*d7802caeSToomas Soome (void) fprintf(stdout, gettext("Updating master boot sector " 434*d7802caeSToomas Soome "destroys existing boot managers (if any).\n" 435*d7802caeSToomas Soome "continue (y/n)? ")); 436*d7802caeSToomas Soome if (!yes()) { 437*d7802caeSToomas Soome write_mbr = false; 438*d7802caeSToomas Soome (void) fprintf(stdout, gettext("master boot sector " 439*d7802caeSToomas Soome "not updated\n")); 440*d7802caeSToomas Soome } 441*d7802caeSToomas Soome } 442*d7802caeSToomas Soome if (write_mbr) 443*d7802caeSToomas Soome (void) printf("%s is newer than one in %s\n", 444*d7802caeSToomas Soome plist->pl_src_name, plist->pl_devname); 445*d7802caeSToomas Soome return (write_mbr); 446*d7802caeSToomas Soome } 447*d7802caeSToomas Soome 448*d7802caeSToomas Soome /* 449*d7802caeSToomas Soome * VBR setup is always done. 450*d7802caeSToomas Soome */ 451*d7802caeSToomas Soome static bool 452*d7802caeSToomas Soome compare_stage1_cb(struct partlist *plist) 453*d7802caeSToomas Soome { 454*d7802caeSToomas Soome (void) printf("%s will be written to %s\n", plist->pl_src_name, 455*d7802caeSToomas Soome plist->pl_devname); 456*d7802caeSToomas Soome return (true); 457*d7802caeSToomas Soome } 458*d7802caeSToomas Soome 459*d7802caeSToomas Soome /* 460*d7802caeSToomas Soome * Return true if we can update, false if not. 461*d7802caeSToomas Soome */ 462*d7802caeSToomas Soome static bool 463*d7802caeSToomas Soome compare_einfo_cb(struct partlist *plist) 464*d7802caeSToomas Soome { 465*d7802caeSToomas Soome ib_bootblock_t *bblock, *bblock_file; 466*d7802caeSToomas Soome bblk_einfo_t *einfo, *einfo_file; 467*d7802caeSToomas Soome bblk_hs_t bblock_hs; 468*d7802caeSToomas Soome bool rv; 469*d7802caeSToomas Soome 470*d7802caeSToomas Soome bblock = plist->pl_stage; 471*d7802caeSToomas Soome if (bblock == NULL || bblock->extra == NULL || bblock->extra_size == 0) 472*d7802caeSToomas Soome return (true); 473*d7802caeSToomas Soome 474*d7802caeSToomas Soome einfo = find_einfo(bblock->extra, bblock->extra_size); 475*d7802caeSToomas Soome if (einfo == NULL) { 476*d7802caeSToomas Soome BOOT_DEBUG("No extended information available on disk\n"); 477*d7802caeSToomas Soome return (true); 478*d7802caeSToomas Soome } 479*d7802caeSToomas Soome 480*d7802caeSToomas Soome bblock_file = plist->pl_src_data; 481*d7802caeSToomas Soome einfo_file = find_einfo(bblock_file->extra, bblock_file->extra_size); 482*d7802caeSToomas Soome if (einfo_file == NULL) { 483*d7802caeSToomas Soome /* 484*d7802caeSToomas Soome * loader bootblock is versioned. missing version means 485*d7802caeSToomas Soome * probably incompatible block. installboot can not install 486*d7802caeSToomas Soome * grub, for example. 487*d7802caeSToomas Soome */ 4880c946d80SToomas Soome (void) fprintf(stderr, 489*d7802caeSToomas Soome gettext("ERROR: non versioned bootblock in file\n")); 490*d7802caeSToomas Soome return (false); 491*d7802caeSToomas Soome } else { 492*d7802caeSToomas Soome if (update_str == NULL) { 493*d7802caeSToomas Soome update_str = einfo_get_string(einfo_file); 494*d7802caeSToomas Soome do_version = true; 495*d7802caeSToomas Soome } 4960c946d80SToomas Soome } 4970c946d80SToomas Soome 498*d7802caeSToomas Soome if (!do_version || update_str == NULL) { 499*d7802caeSToomas Soome (void) fprintf(stderr, 500*d7802caeSToomas Soome gettext("WARNING: target device %s has a " 501*d7802caeSToomas Soome "versioned bootblock that is going to be overwritten by a " 502*d7802caeSToomas Soome "non versioned one\n"), plist->pl_devname); 503*d7802caeSToomas Soome return (true); 504*d7802caeSToomas Soome } 5050c946d80SToomas Soome 506*d7802caeSToomas Soome if (force_update) { 507*d7802caeSToomas Soome BOOT_DEBUG("Forcing update of %s bootblock\n", 508*d7802caeSToomas Soome plist->pl_devname); 509*d7802caeSToomas Soome return (true); 510*d7802caeSToomas Soome } 5110c946d80SToomas Soome 512*d7802caeSToomas Soome BOOT_DEBUG("Ready to check installed version vs %s\n", update_str); 5130c946d80SToomas Soome 514*d7802caeSToomas Soome bblock_hs.src_buf = (unsigned char *)bblock_file->file; 515*d7802caeSToomas Soome bblock_hs.src_size = bblock_file->file_size; 516*d7802caeSToomas Soome 517*d7802caeSToomas Soome rv = einfo_should_update(einfo, &bblock_hs, update_str); 518*d7802caeSToomas Soome if (rv == false) { 519*d7802caeSToomas Soome (void) fprintf(stderr, gettext("\nBootblock version installed " 520*d7802caeSToomas Soome "on %s is more recent or identical to\n%s\n" 521*d7802caeSToomas Soome "Use -F to override or install without the -u option.\n"), 522*d7802caeSToomas Soome plist->pl_devname, plist->pl_src_name); 523*d7802caeSToomas Soome } else { 524*d7802caeSToomas Soome (void) printf("%s is newer than one in %s\n", 525*d7802caeSToomas Soome plist->pl_src_name, plist->pl_devname); 526*d7802caeSToomas Soome } 527*d7802caeSToomas Soome return (rv); 528*d7802caeSToomas Soome } 529*d7802caeSToomas Soome 530*d7802caeSToomas Soome static bool 531*d7802caeSToomas Soome read_stage1_cb(struct partlist *plist) 532*d7802caeSToomas Soome { 533*d7802caeSToomas Soome int fd; 534*d7802caeSToomas Soome bool rv = false; 535*d7802caeSToomas Soome 536*d7802caeSToomas Soome if ((fd = open_device(plist->pl_devname)) == -1) 537*d7802caeSToomas Soome return (rv); 538*d7802caeSToomas Soome 539*d7802caeSToomas Soome if (plist->pl_stage == NULL) 540*d7802caeSToomas Soome plist->pl_stage = calloc(1, sector_size); 541*d7802caeSToomas Soome 542*d7802caeSToomas Soome if (plist->pl_stage == NULL) { 543*d7802caeSToomas Soome perror("calloc"); 544*d7802caeSToomas Soome goto done; 545*d7802caeSToomas Soome } 5460c946d80SToomas Soome 547*d7802caeSToomas Soome if (pread(fd, plist->pl_stage, sector_size, 0) == -1) { 548*d7802caeSToomas Soome perror("pread"); 549*d7802caeSToomas Soome goto done; 550*d7802caeSToomas Soome } 551*d7802caeSToomas Soome rv = true; 552*d7802caeSToomas Soome done: 5530c946d80SToomas Soome (void) close(fd); 554*d7802caeSToomas Soome return (rv); 555*d7802caeSToomas Soome } 5560c946d80SToomas Soome 557*d7802caeSToomas Soome static bool 558*d7802caeSToomas Soome read_stage1_bbl_cb(struct partlist *plist) 559*d7802caeSToomas Soome { 560*d7802caeSToomas Soome int fd; 561*d7802caeSToomas Soome void *data; 562*d7802caeSToomas Soome bool rv = false; 563*d7802caeSToomas Soome 564*d7802caeSToomas Soome data = malloc(SECTOR_SIZE); 565*d7802caeSToomas Soome if (data == NULL) 566*d7802caeSToomas Soome return (rv); 567*d7802caeSToomas Soome 568*d7802caeSToomas Soome /* read the stage1 file from filesystem */ 569*d7802caeSToomas Soome fd = open(plist->pl_src_name, O_RDONLY); 570*d7802caeSToomas Soome if (fd == -1 || 571*d7802caeSToomas Soome read(fd, data, SECTOR_SIZE) != SECTOR_SIZE) { 572*d7802caeSToomas Soome (void) fprintf(stderr, gettext("cannot read stage1 file %s\n"), 573*d7802caeSToomas Soome plist->pl_src_name); 574*d7802caeSToomas Soome free(data); 575*d7802caeSToomas Soome if (fd != -1) 576*d7802caeSToomas Soome (void) close(fd); 577*d7802caeSToomas Soome return (rv); 578*d7802caeSToomas Soome } 579*d7802caeSToomas Soome 580*d7802caeSToomas Soome plist->pl_src_data = data; 5810c946d80SToomas Soome (void) close(fd); 582*d7802caeSToomas Soome return (true); 5830c946d80SToomas Soome } 5840c946d80SToomas Soome 585*d7802caeSToomas Soome static bool 586*d7802caeSToomas Soome read_stage2_cb(struct partlist *plist) 5870c946d80SToomas Soome { 588*d7802caeSToomas Soome ib_device_t *device; 589*d7802caeSToomas Soome ib_bootblock_t *bblock; 590*d7802caeSToomas Soome int fd; 5910c946d80SToomas Soome uint32_t size, offset; 5920c946d80SToomas Soome uint32_t buf_size; 5930c946d80SToomas Soome uint32_t mboot_off; 5940c946d80SToomas Soome multiboot_header_t *mboot; 5950c946d80SToomas Soome 596*d7802caeSToomas Soome bblock = calloc(1, sizeof (ib_bootblock_t)); 597*d7802caeSToomas Soome if (bblock == NULL) 598*d7802caeSToomas Soome return (false); 5990c946d80SToomas Soome 600*d7802caeSToomas Soome if ((fd = open_device(plist->pl_devname)) == -1) { 601*d7802caeSToomas Soome free(bblock); 602*d7802caeSToomas Soome return (false); 6030c946d80SToomas Soome } 6040c946d80SToomas Soome 605*d7802caeSToomas Soome device = plist->pl_device; 606*d7802caeSToomas Soome plist->pl_stage = bblock; 607*d7802caeSToomas Soome offset = device->stage.offset * SECTOR_SIZE; 608*d7802caeSToomas Soome 609*d7802caeSToomas Soome if (read_in(fd, mboot_scan, sizeof (mboot_scan), offset) 6100c946d80SToomas Soome != BC_SUCCESS) { 6110c946d80SToomas Soome BOOT_DEBUG("Error reading bootblock area\n"); 6120c946d80SToomas Soome perror("read"); 613*d7802caeSToomas Soome (void) close(fd); 614*d7802caeSToomas Soome return (false); 6150c946d80SToomas Soome } 6160c946d80SToomas Soome 6170c946d80SToomas Soome /* No multiboot means no chance of knowing bootblock size */ 6180c946d80SToomas Soome if (find_multiboot(mboot_scan, sizeof (mboot_scan), &mboot_off) 6190c946d80SToomas Soome != BC_SUCCESS) { 6200c946d80SToomas Soome BOOT_DEBUG("Unable to find multiboot header\n"); 621*d7802caeSToomas Soome (void) close(fd); 622*d7802caeSToomas Soome return (false); 6230c946d80SToomas Soome } 6240c946d80SToomas Soome mboot = (multiboot_header_t *)(mboot_scan + mboot_off); 6250c946d80SToomas Soome 6260c946d80SToomas Soome /* 6270c946d80SToomas Soome * make sure mboot has sane values 6280c946d80SToomas Soome */ 6290c946d80SToomas Soome if (mboot->load_end_addr == 0 || 630*d7802caeSToomas Soome mboot->load_end_addr < mboot->load_addr) { 631*d7802caeSToomas Soome (void) close(fd); 632*d7802caeSToomas Soome return (false); 633*d7802caeSToomas Soome } 6340c946d80SToomas Soome 6350c946d80SToomas Soome /* 6360c946d80SToomas Soome * Currently, the amount of space reserved for extra information 6370c946d80SToomas Soome * is "fixed". We may have to scan for the terminating extra payload 6380c946d80SToomas Soome * in the future. 6390c946d80SToomas Soome */ 6400c946d80SToomas Soome size = mboot->load_end_addr - mboot->load_addr; 6410c946d80SToomas Soome buf_size = P2ROUNDUP(size + SECTOR_SIZE, SECTOR_SIZE); 6420c946d80SToomas Soome bblock->file_size = size; 6430c946d80SToomas Soome 6440c946d80SToomas Soome bblock->buf = malloc(buf_size); 6450c946d80SToomas Soome if (bblock->buf == NULL) { 6460c946d80SToomas Soome BOOT_DEBUG("Unable to allocate enough memory to read" 6470c946d80SToomas Soome " the extra bootblock from the disk\n"); 6480c946d80SToomas Soome perror(gettext("Memory allocation failure")); 649*d7802caeSToomas Soome (void) close(fd); 650*d7802caeSToomas Soome return (false); 6510c946d80SToomas Soome } 6520c946d80SToomas Soome bblock->buf_size = buf_size; 6530c946d80SToomas Soome 654*d7802caeSToomas Soome if (read_in(fd, bblock->buf, buf_size, offset) != BC_SUCCESS) { 6550c946d80SToomas Soome BOOT_DEBUG("Error reading the bootblock\n"); 6560c946d80SToomas Soome (void) free(bblock->buf); 6570c946d80SToomas Soome bblock->buf = NULL; 658*d7802caeSToomas Soome (void) close(fd); 659*d7802caeSToomas Soome return (false); 6600c946d80SToomas Soome } 6610c946d80SToomas Soome 6620c946d80SToomas Soome /* Update pointers. */ 6630c946d80SToomas Soome bblock->file = bblock->buf; 6640c946d80SToomas Soome bblock->mboot_off = mboot_off; 6650c946d80SToomas Soome bblock->mboot = (multiboot_header_t *)(bblock->buf + bblock->mboot_off); 6660c946d80SToomas Soome bblock->extra = bblock->buf + P2ROUNDUP(bblock->file_size, 8); 6670c946d80SToomas Soome bblock->extra_size = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8); 6680c946d80SToomas Soome 6690c946d80SToomas Soome BOOT_DEBUG("mboot at %p offset %d, extra at %p size %d, buf=%p " 6700c946d80SToomas Soome "(size=%d)\n", bblock->mboot, bblock->mboot_off, bblock->extra, 6710c946d80SToomas Soome bblock->extra_size, bblock->buf, bblock->buf_size); 6720c946d80SToomas Soome 673*d7802caeSToomas Soome return (true); 6740c946d80SToomas Soome } 6750c946d80SToomas Soome 676*d7802caeSToomas Soome static bool 677*d7802caeSToomas Soome read_einfo_file_cb(struct partlist *plist) 6780c946d80SToomas Soome { 679*d7802caeSToomas Soome plist->pl_stage = calloc(1, sizeof (ib_bootblock_t)); 680*d7802caeSToomas Soome if (plist->pl_stage == NULL) 681*d7802caeSToomas Soome return (false); 6820c946d80SToomas Soome 683*d7802caeSToomas Soome return (read_bootblock_from_file(plist->pl_devname, 684*d7802caeSToomas Soome plist->pl_stage) == BC_SUCCESS); 685*d7802caeSToomas Soome } 6860c946d80SToomas Soome 687*d7802caeSToomas Soome static bool 688*d7802caeSToomas Soome read_stage2_file_cb(struct partlist *plist) 689*d7802caeSToomas Soome { 690*d7802caeSToomas Soome plist->pl_src_data = calloc(1, sizeof (ib_bootblock_t)); 691*d7802caeSToomas Soome if (plist->pl_src_data == NULL) 692*d7802caeSToomas Soome return (false); 6930c946d80SToomas Soome 694*d7802caeSToomas Soome return (read_bootblock_from_file(plist->pl_src_name, 695*d7802caeSToomas Soome plist->pl_src_data) == BC_SUCCESS); 696*d7802caeSToomas Soome } 6970c946d80SToomas Soome 698*d7802caeSToomas Soome /* 699*d7802caeSToomas Soome * convert /dev/rdsk/... to /dev/dsk/... 700*d7802caeSToomas Soome */ 701*d7802caeSToomas Soome static char * 702*d7802caeSToomas Soome make_blkdev(const char *path) 703*d7802caeSToomas Soome { 704*d7802caeSToomas Soome char *tmp; 705*d7802caeSToomas Soome char *ptr = strdup(path); 7060c946d80SToomas Soome 707*d7802caeSToomas Soome if (ptr == NULL) 708*d7802caeSToomas Soome return (ptr); 7090c946d80SToomas Soome 710*d7802caeSToomas Soome tmp = strstr(ptr, "rdsk"); 711*d7802caeSToomas Soome if (tmp == NULL) { 712*d7802caeSToomas Soome free(ptr); 713*d7802caeSToomas Soome return (NULL); /* Something is very wrong */ 7140c946d80SToomas Soome } 715*d7802caeSToomas Soome /* This is safe because we do shorten the string */ 716*d7802caeSToomas Soome (void) memmove(tmp, tmp + 1, strlen(tmp)); 717*d7802caeSToomas Soome return (ptr); 718*d7802caeSToomas Soome } 7190c946d80SToomas Soome 720*d7802caeSToomas Soome /* 721*d7802caeSToomas Soome * Try to mount ESP and read boot program. 722*d7802caeSToomas Soome */ 723*d7802caeSToomas Soome static bool 724*d7802caeSToomas Soome read_einfo_esp_cb(struct partlist *plist) 725*d7802caeSToomas Soome { 726*d7802caeSToomas Soome fstyp_handle_t fhdl; 727*d7802caeSToomas Soome const char *fident; 728*d7802caeSToomas Soome char *blkdev, *path, *file; 729*d7802caeSToomas Soome bool rv = false; 730*d7802caeSToomas Soome FILE *fp; 731*d7802caeSToomas Soome struct mnttab mp, mpref = { 0 }; 732*d7802caeSToomas Soome int fd, ret; 7330c946d80SToomas Soome 734*d7802caeSToomas Soome if ((fd = open_device(plist->pl_devname)) == -1) 735*d7802caeSToomas Soome return (rv); 7360c946d80SToomas Soome 737*d7802caeSToomas Soome if (fstyp_init(fd, 0, NULL, &fhdl) != 0) { 738*d7802caeSToomas Soome (void) close(fd); 739*d7802caeSToomas Soome return (rv); 740*d7802caeSToomas Soome } 7410c946d80SToomas Soome 742*d7802caeSToomas Soome if (fstyp_ident(fhdl, NULL, &fident) != 0) { 743*d7802caeSToomas Soome fstyp_fini(fhdl); 744*d7802caeSToomas Soome (void) close(fd); 745*d7802caeSToomas Soome (void) fprintf(stderr, gettext("Failed to detect file " 746*d7802caeSToomas Soome "system type\n")); 747*d7802caeSToomas Soome return (rv); 748*d7802caeSToomas Soome } 7490c946d80SToomas Soome 750*d7802caeSToomas Soome /* We only do expect pcfs. */ 751*d7802caeSToomas Soome if (strcmp(fident, MNTTYPE_PCFS) != 0) { 752*d7802caeSToomas Soome (void) fprintf(stderr, 753*d7802caeSToomas Soome gettext("File system %s is not supported.\n"), fident); 754*d7802caeSToomas Soome fstyp_fini(fhdl); 755*d7802caeSToomas Soome (void) close(fd); 756*d7802caeSToomas Soome return (rv); 757*d7802caeSToomas Soome } 758*d7802caeSToomas Soome fstyp_fini(fhdl); 759*d7802caeSToomas Soome (void) close(fd); 760*d7802caeSToomas Soome 761*d7802caeSToomas Soome blkdev = make_blkdev(plist->pl_devname); 762*d7802caeSToomas Soome if (blkdev == NULL) 763*d7802caeSToomas Soome return (rv); 764*d7802caeSToomas Soome 765*d7802caeSToomas Soome /* mount ESP if needed, read boot program(s) and unmount. */ 766*d7802caeSToomas Soome fp = fopen(MNTTAB, "r"); 767*d7802caeSToomas Soome if (fp == NULL) { 768*d7802caeSToomas Soome perror("fopen"); 769*d7802caeSToomas Soome free(blkdev); 770*d7802caeSToomas Soome return (rv); 7710c946d80SToomas Soome } 7720c946d80SToomas Soome 773*d7802caeSToomas Soome mpref.mnt_special = blkdev; 774*d7802caeSToomas Soome ret = getmntany(fp, &mp, &mpref); 775*d7802caeSToomas Soome (void) fclose(fp); 776*d7802caeSToomas Soome if (ret == 0) 777*d7802caeSToomas Soome path = mp.mnt_mountp; 778*d7802caeSToomas Soome else 779*d7802caeSToomas Soome path = stagefs_mount(blkdev, plist); 780*d7802caeSToomas Soome 781*d7802caeSToomas Soome free(blkdev); 782*d7802caeSToomas Soome if (path == NULL) 783*d7802caeSToomas Soome return (rv); 784*d7802caeSToomas Soome 785*d7802caeSToomas Soome if (asprintf(&file, "%s%s", path, plist->pl_device->stage.path) < 0) { 786*d7802caeSToomas Soome return (rv); 787*d7802caeSToomas Soome } 788*d7802caeSToomas Soome 789*d7802caeSToomas Soome plist->pl_stage = calloc(1, sizeof (ib_bootblock_t)); 790*d7802caeSToomas Soome if (plist->pl_stage == NULL) { 791*d7802caeSToomas Soome free(file); 792*d7802caeSToomas Soome return (rv); 793*d7802caeSToomas Soome } 794*d7802caeSToomas Soome if (read_bootblock_from_file(file, plist->pl_stage) != BC_SUCCESS) { 795*d7802caeSToomas Soome free(plist->pl_stage); 796*d7802caeSToomas Soome plist->pl_stage = NULL; 797*d7802caeSToomas Soome } else { 798*d7802caeSToomas Soome rv = true; 799*d7802caeSToomas Soome } 800*d7802caeSToomas Soome 801*d7802caeSToomas Soome free(file); 802*d7802caeSToomas Soome return (rv); 8030c946d80SToomas Soome } 8040c946d80SToomas Soome 805*d7802caeSToomas Soome static void 806*d7802caeSToomas Soome print_stage1_cb(struct partlist *plist) 8070c946d80SToomas Soome { 808*d7802caeSToomas Soome struct mboot *mbr; 809*d7802caeSToomas Soome struct ipart *part; 810*d7802caeSToomas Soome mbr_type_t type = MBR_TYPE_UNKNOWN; 811*d7802caeSToomas Soome bool pmbr = false; 812*d7802caeSToomas Soome char *label; 8130c946d80SToomas Soome 814*d7802caeSToomas Soome mbr = plist->pl_stage; 8150c946d80SToomas Soome 816*d7802caeSToomas Soome if (*((uint16_t *)&mbr->bootinst[GRUB_VERSION_OFF]) == GRUB_VERSION) { 817*d7802caeSToomas Soome type = MBR_TYPE_GRUB1; 818*d7802caeSToomas Soome } else if (mbr->bootinst[STAGE1_MBR_VERSION] == LOADER_VERSION) { 819*d7802caeSToomas Soome type = MBR_TYPE_LOADER; 820*d7802caeSToomas Soome } else if (mbr->bootinst[STAGE1_MBR_VERSION] == LOADER_JOYENT_VERSION) { 821*d7802caeSToomas Soome type = MBR_TYPE_LOADER_JOYENT; 822*d7802caeSToomas Soome } 8230c946d80SToomas Soome 824*d7802caeSToomas Soome part = (struct ipart *)mbr->parts; 825*d7802caeSToomas Soome for (int i = 0; i < FD_NUMPART; i++) { 826*d7802caeSToomas Soome if (part[i].systid == EFI_PMBR) 827*d7802caeSToomas Soome pmbr = true; 828*d7802caeSToomas Soome } 8290c946d80SToomas Soome 830*d7802caeSToomas Soome if (plist->pl_type == IB_BBLK_MBR) 831*d7802caeSToomas Soome label = pmbr ? "PMBR" : "MBR"; 832*d7802caeSToomas Soome else 833*d7802caeSToomas Soome label = "VBR"; 8340c946d80SToomas Soome 835*d7802caeSToomas Soome printf("%s block from %s:\n", label, plist->pl_devname); 8360c946d80SToomas Soome 837*d7802caeSToomas Soome switch (type) { 838*d7802caeSToomas Soome case MBR_TYPE_UNKNOWN: 839*d7802caeSToomas Soome printf("Format: unknown\n"); 840*d7802caeSToomas Soome break; 841*d7802caeSToomas Soome case MBR_TYPE_GRUB1: 842*d7802caeSToomas Soome printf("Format: grub1\n"); 843*d7802caeSToomas Soome break; 844*d7802caeSToomas Soome case MBR_TYPE_LOADER: 845*d7802caeSToomas Soome printf("Format: loader (illumos)\n"); 846*d7802caeSToomas Soome break; 847*d7802caeSToomas Soome case MBR_TYPE_LOADER_JOYENT: 848*d7802caeSToomas Soome printf("Format: loader (joyent)\n"); 849*d7802caeSToomas Soome break; 8500c946d80SToomas Soome } 8510c946d80SToomas Soome 852*d7802caeSToomas Soome printf("Signature: 0x%hx (%s)\n", mbr->signature, 853*d7802caeSToomas Soome mbr->signature == MBB_MAGIC ? "valid" : "invalid"); 8540c946d80SToomas Soome 855*d7802caeSToomas Soome printf("UniqueMBRDiskSignature: %#lx\n", 856*d7802caeSToomas Soome *(uint32_t *)&mbr->bootinst[STAGE1_SIG]); 857*d7802caeSToomas Soome 858*d7802caeSToomas Soome if (type == MBR_TYPE_LOADER || type == MBR_TYPE_LOADER_JOYENT) { 859*d7802caeSToomas Soome char uuid[UUID_PRINTABLE_STRING_LENGTH]; 860*d7802caeSToomas Soome 861*d7802caeSToomas Soome printf("Loader STAGE1_STAGE2_LBA: %llu\n", 862*d7802caeSToomas Soome *(uint64_t *)&mbr->bootinst[STAGE1_STAGE2_LBA]); 863*d7802caeSToomas Soome 864*d7802caeSToomas Soome printf("Loader STAGE1_STAGE2_SIZE: %hu\n", 865*d7802caeSToomas Soome *(uint16_t *)&mbr->bootinst[STAGE1_STAGE2_SIZE]); 866*d7802caeSToomas Soome 867*d7802caeSToomas Soome uuid_unparse((uchar_t *)&mbr->bootinst[STAGE1_STAGE2_UUID], 868*d7802caeSToomas Soome uuid); 869*d7802caeSToomas Soome 870*d7802caeSToomas Soome printf("Loader STAGE1_STAGE2_UUID: %s\n", uuid); 871*d7802caeSToomas Soome } 872*d7802caeSToomas Soome printf("\n"); 8730c946d80SToomas Soome } 8740c946d80SToomas Soome 875*d7802caeSToomas Soome static void 876*d7802caeSToomas Soome print_einfo_cb(struct partlist *plist) 8770c946d80SToomas Soome { 878*d7802caeSToomas Soome uint8_t flags = 0; 879*d7802caeSToomas Soome ib_bootblock_t *bblock; 880*d7802caeSToomas Soome bblk_einfo_t *einfo = NULL; 881*d7802caeSToomas Soome const char *filepath; 882*d7802caeSToomas Soome 883*d7802caeSToomas Soome /* No stage, get out. */ 884*d7802caeSToomas Soome bblock = plist->pl_stage; 885*d7802caeSToomas Soome if (bblock == NULL) 886*d7802caeSToomas Soome return; 8870c946d80SToomas Soome 888*d7802caeSToomas Soome if (plist->pl_device->stage.path == NULL) 889*d7802caeSToomas Soome filepath = ""; 890*d7802caeSToomas Soome else 891*d7802caeSToomas Soome filepath = plist->pl_device->stage.path; 8920c946d80SToomas Soome 893*d7802caeSToomas Soome printf("Boot block from %s:%s\n", plist->pl_devname, filepath); 8940c946d80SToomas Soome 895*d7802caeSToomas Soome if (bblock->extra != NULL) 896*d7802caeSToomas Soome einfo = find_einfo(bblock->extra, bblock->extra_size); 8970c946d80SToomas Soome 898*d7802caeSToomas Soome if (einfo == NULL) { 899*d7802caeSToomas Soome (void) fprintf(stderr, 900*d7802caeSToomas Soome gettext("No extended information found.\n\n")); 901*d7802caeSToomas Soome return; 902*d7802caeSToomas Soome } 9030c946d80SToomas Soome 904*d7802caeSToomas Soome /* Print the extended information. */ 905*d7802caeSToomas Soome if (strip) 906*d7802caeSToomas Soome flags |= EINFO_EASY_PARSE; 907*d7802caeSToomas Soome if (verbose_dump) 908*d7802caeSToomas Soome flags |= EINFO_PRINT_HEADER; 909*d7802caeSToomas Soome 910*d7802caeSToomas Soome print_einfo(flags, einfo, bblock->extra_size); 911*d7802caeSToomas Soome printf("\n"); 9120c946d80SToomas Soome } 9130c946d80SToomas Soome 914*d7802caeSToomas Soome static size_t 915*d7802caeSToomas Soome get_media_info(int fd) 9160c946d80SToomas Soome { 917*d7802caeSToomas Soome struct dk_minfo disk_info; 9180c946d80SToomas Soome 919*d7802caeSToomas Soome if ((ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info)) == -1) 920*d7802caeSToomas Soome return (SECTOR_SIZE); 9210c946d80SToomas Soome 922*d7802caeSToomas Soome return (disk_info.dki_lbsize); 923*d7802caeSToomas Soome } 924*d7802caeSToomas Soome 925*d7802caeSToomas Soome static struct partlist * 926*d7802caeSToomas Soome partlist_alloc(void) 927*d7802caeSToomas Soome { 928*d7802caeSToomas Soome struct partlist *pl; 929*d7802caeSToomas Soome 930*d7802caeSToomas Soome if ((pl = calloc(1, sizeof (*pl))) == NULL) { 931*d7802caeSToomas Soome perror("calloc"); 932*d7802caeSToomas Soome return (NULL); 9330c946d80SToomas Soome } 9340c946d80SToomas Soome 935*d7802caeSToomas Soome pl->pl_device = calloc(1, sizeof (*pl->pl_device)); 936*d7802caeSToomas Soome if (pl->pl_device == NULL) { 937*d7802caeSToomas Soome perror("calloc"); 938*d7802caeSToomas Soome free(pl); 939*d7802caeSToomas Soome return (NULL); 940*d7802caeSToomas Soome } 941*d7802caeSToomas Soome 942*d7802caeSToomas Soome return (pl); 943*d7802caeSToomas Soome } 944*d7802caeSToomas Soome 945*d7802caeSToomas Soome static void 946*d7802caeSToomas Soome partlist_free(struct partlist *pl) 947*d7802caeSToomas Soome { 948*d7802caeSToomas Soome ib_bootblock_t *bblock; 949*d7802caeSToomas Soome ib_device_t *device; 950*d7802caeSToomas Soome 951*d7802caeSToomas Soome switch (pl->pl_type) { 952*d7802caeSToomas Soome case IB_BBLK_MBR: 953*d7802caeSToomas Soome case IB_BBLK_STAGE1: 954*d7802caeSToomas Soome free(pl->pl_stage); 955*d7802caeSToomas Soome break; 956*d7802caeSToomas Soome default: 957*d7802caeSToomas Soome if (pl->pl_stage != NULL) { 958*d7802caeSToomas Soome bblock = pl->pl_stage; 959*d7802caeSToomas Soome free(bblock->buf); 960*d7802caeSToomas Soome free(bblock); 9610c946d80SToomas Soome } 9620c946d80SToomas Soome } 963*d7802caeSToomas Soome 964*d7802caeSToomas Soome /* umount the stage fs. */ 965*d7802caeSToomas Soome if (pl->pl_device->stage.mntpnt != NULL) { 966*d7802caeSToomas Soome if (umount(pl->pl_device->stage.mntpnt) == 0) 967*d7802caeSToomas Soome (void) rmdir(pl->pl_device->stage.mntpnt); 968*d7802caeSToomas Soome free(pl->pl_device->stage.mntpnt); 9690c946d80SToomas Soome } 970*d7802caeSToomas Soome device = pl->pl_device; 971*d7802caeSToomas Soome free(device->target.path); 972*d7802caeSToomas Soome free(pl->pl_device); 9730c946d80SToomas Soome 974*d7802caeSToomas Soome free(pl->pl_src_data); 975*d7802caeSToomas Soome free(pl->pl_devname); 976*d7802caeSToomas Soome free(pl); 977*d7802caeSToomas Soome } 9780c946d80SToomas Soome 979*d7802caeSToomas Soome static bool 980*d7802caeSToomas Soome probe_fstyp(ib_data_t *data) 981*d7802caeSToomas Soome { 982*d7802caeSToomas Soome fstyp_handle_t fhdl; 983*d7802caeSToomas Soome const char *fident; 984*d7802caeSToomas Soome char *ptr; 985*d7802caeSToomas Soome int fd; 986*d7802caeSToomas Soome bool rv = false; 987*d7802caeSToomas Soome 988*d7802caeSToomas Soome /* Record partition id */ 989*d7802caeSToomas Soome ptr = strrchr(data->target.path, 'p'); 990*d7802caeSToomas Soome if (ptr == NULL) 991*d7802caeSToomas Soome ptr = strrchr(data->target.path, 's'); 992*d7802caeSToomas Soome data->target.id = atoi(++ptr); 993*d7802caeSToomas Soome if ((fd = open_device(data->target.path)) == -1) 994*d7802caeSToomas Soome return (rv); 995*d7802caeSToomas Soome 996*d7802caeSToomas Soome if (fstyp_init(fd, 0, NULL, &fhdl) != 0) { 997*d7802caeSToomas Soome (void) close(fd); 998*d7802caeSToomas Soome return (rv); 999*d7802caeSToomas Soome } 1000*d7802caeSToomas Soome 1001*d7802caeSToomas Soome if (fstyp_ident(fhdl, NULL, &fident) != 0) { 1002*d7802caeSToomas Soome fstyp_fini(fhdl); 1003*d7802caeSToomas Soome (void) fprintf(stderr, gettext("Failed to detect file " 1004*d7802caeSToomas Soome "system type\n")); 1005*d7802caeSToomas Soome (void) close(fd); 1006*d7802caeSToomas Soome return (rv); 1007*d7802caeSToomas Soome } 1008*d7802caeSToomas Soome 1009*d7802caeSToomas Soome rv = true; 1010*d7802caeSToomas Soome if (strcmp(fident, MNTTYPE_ZFS) == 0) 1011*d7802caeSToomas Soome data->target.fstype = IB_FS_ZFS; 1012*d7802caeSToomas Soome else if (strcmp(fident, MNTTYPE_UFS) == 0) { 1013*d7802caeSToomas Soome data->target.fstype = IB_FS_UFS; 1014*d7802caeSToomas Soome } else if (strcmp(fident, MNTTYPE_PCFS) == 0) { 1015*d7802caeSToomas Soome data->target.fstype = IB_FS_PCFS; 1016*d7802caeSToomas Soome } else { 1017*d7802caeSToomas Soome (void) fprintf(stderr, gettext("File system %s is not " 1018*d7802caeSToomas Soome "supported by loader\n"), fident); 1019*d7802caeSToomas Soome rv = false; 1020*d7802caeSToomas Soome } 1021*d7802caeSToomas Soome fstyp_fini(fhdl); 1022*d7802caeSToomas Soome (void) close(fd); 1023*d7802caeSToomas Soome return (rv); 10240c946d80SToomas Soome } 10250c946d80SToomas Soome 1026*d7802caeSToomas Soome static bool 1027*d7802caeSToomas Soome get_slice(ib_data_t *data, struct partlist *pl, struct dk_gpt *vtoc, 1028*d7802caeSToomas Soome uint16_t tag) 10290c946d80SToomas Soome { 1030*d7802caeSToomas Soome uint_t i; 1031*d7802caeSToomas Soome ib_device_t *device = pl->pl_device; 1032*d7802caeSToomas Soome char *path, *ptr; 10330c946d80SToomas Soome 1034*d7802caeSToomas Soome if (tag != V_BOOT && tag != V_SYSTEM) 1035*d7802caeSToomas Soome return (false); 10360c946d80SToomas Soome 1037*d7802caeSToomas Soome for (i = 0; i < vtoc->efi_nparts; i++) { 1038*d7802caeSToomas Soome if (vtoc->efi_parts[i].p_tag == tag) { 1039*d7802caeSToomas Soome if ((path = strdup(data->target.path)) == NULL) { 1040*d7802caeSToomas Soome perror(gettext("Memory allocation failure")); 1041*d7802caeSToomas Soome return (false); 1042*d7802caeSToomas Soome } 1043*d7802caeSToomas Soome ptr = strrchr(path, 's'); 1044*d7802caeSToomas Soome ptr++; 1045*d7802caeSToomas Soome *ptr = '\0'; 1046*d7802caeSToomas Soome (void) asprintf(&ptr, "%s%d", path, i); 1047*d7802caeSToomas Soome free(path); 1048*d7802caeSToomas Soome if (ptr == NULL) { 1049*d7802caeSToomas Soome perror(gettext("Memory allocation failure")); 1050*d7802caeSToomas Soome return (false); 1051*d7802caeSToomas Soome } 1052*d7802caeSToomas Soome pl->pl_devname = ptr; 1053*d7802caeSToomas Soome device->stage.id = i; 1054*d7802caeSToomas Soome device->stage.devtype = IB_DEV_EFI; 1055*d7802caeSToomas Soome switch (vtoc->efi_parts[i].p_tag) { 1056*d7802caeSToomas Soome case V_BOOT: 1057*d7802caeSToomas Soome device->stage.fstype = IB_FS_NONE; 1058*d7802caeSToomas Soome /* leave sector 0 for VBR */ 1059*d7802caeSToomas Soome device->stage.offset = 1; 1060*d7802caeSToomas Soome break; 1061*d7802caeSToomas Soome case V_SYSTEM: 1062*d7802caeSToomas Soome device->stage.fstype = IB_FS_PCFS; 1063*d7802caeSToomas Soome break; 1064*d7802caeSToomas Soome } 1065*d7802caeSToomas Soome device->stage.tag = vtoc->efi_parts[i].p_tag; 1066*d7802caeSToomas Soome device->stage.start = vtoc->efi_parts[i].p_start; 1067*d7802caeSToomas Soome device->stage.size = vtoc->efi_parts[i].p_size; 1068*d7802caeSToomas Soome break; 10690c946d80SToomas Soome } 10700c946d80SToomas Soome } 1071*d7802caeSToomas Soome return (true); 1072*d7802caeSToomas Soome } 10730c946d80SToomas Soome 1074*d7802caeSToomas Soome static bool 1075*d7802caeSToomas Soome allocate_slice(ib_data_t *data, struct dk_gpt *vtoc, uint16_t tag, 1076*d7802caeSToomas Soome struct partlist **plp) 1077*d7802caeSToomas Soome { 1078*d7802caeSToomas Soome struct partlist *pl; 10790c946d80SToomas Soome 1080*d7802caeSToomas Soome *plp = NULL; 1081*d7802caeSToomas Soome if ((pl = partlist_alloc()) == NULL) 1082*d7802caeSToomas Soome return (false); 10830c946d80SToomas Soome 1084*d7802caeSToomas Soome pl->pl_device = calloc(1, sizeof (*pl->pl_device)); 1085*d7802caeSToomas Soome if (pl->pl_device == NULL) { 1086*d7802caeSToomas Soome perror("calloc"); 1087*d7802caeSToomas Soome partlist_free(pl); 1088*d7802caeSToomas Soome return (false); 1089*d7802caeSToomas Soome } 1090*d7802caeSToomas Soome if (!get_slice(data, pl, vtoc, tag)) { 1091*d7802caeSToomas Soome partlist_free(pl); 1092*d7802caeSToomas Soome return (false); 10930c946d80SToomas Soome } 10940c946d80SToomas Soome 1095*d7802caeSToomas Soome /* tag was not found */ 1096*d7802caeSToomas Soome if (pl->pl_devname == NULL) 1097*d7802caeSToomas Soome partlist_free(pl); 1098*d7802caeSToomas Soome else 1099*d7802caeSToomas Soome *plp = pl; 1100*d7802caeSToomas Soome 1101*d7802caeSToomas Soome return (true); 11020c946d80SToomas Soome } 11030c946d80SToomas Soome 1104*d7802caeSToomas Soome static bool 1105*d7802caeSToomas Soome probe_gpt(ib_data_t *data) 11060c946d80SToomas Soome { 1107*d7802caeSToomas Soome struct partlist *pl; 1108*d7802caeSToomas Soome struct dk_gpt *vtoc; 1109*d7802caeSToomas Soome ib_device_t *device; 1110*d7802caeSToomas Soome int slice, fd; 1111*d7802caeSToomas Soome bool rv = false; 11120c946d80SToomas Soome 1113*d7802caeSToomas Soome if ((fd = open_device(data->target.path)) < 0) 1114*d7802caeSToomas Soome return (rv); 11150c946d80SToomas Soome 1116*d7802caeSToomas Soome slice = efi_alloc_and_read(fd, &vtoc); 1117*d7802caeSToomas Soome (void) close(fd); 1118*d7802caeSToomas Soome if (slice < 0) 1119*d7802caeSToomas Soome return (rv); 1120*d7802caeSToomas Soome 1121*d7802caeSToomas Soome data->device.devtype = IB_DEV_EFI; 1122*d7802caeSToomas Soome data->target.start = vtoc->efi_parts[slice].p_start; 1123*d7802caeSToomas Soome data->target.size = vtoc->efi_parts[slice].p_size; 11240c946d80SToomas Soome 1125*d7802caeSToomas Soome /* Always update PMBR. */ 1126*d7802caeSToomas Soome force_mbr = 1; 1127*d7802caeSToomas Soome write_mbr = 1; 1128*d7802caeSToomas Soome 1129*d7802caeSToomas Soome /* 1130*d7802caeSToomas Soome * With GPT we can have boot partition and ESP. 1131*d7802caeSToomas Soome * Boot partition can have both stage 1 and stage 2. 1132*d7802caeSToomas Soome */ 1133*d7802caeSToomas Soome if (!allocate_slice(data, vtoc, V_BOOT, &pl)) 1134*d7802caeSToomas Soome goto done; 1135*d7802caeSToomas Soome if (pl != NULL) { 1136*d7802caeSToomas Soome pl->pl_src_name = stage1; 1137*d7802caeSToomas Soome pl->pl_type = IB_BBLK_STAGE1; 1138*d7802caeSToomas Soome pl->pl_cb.compare = compare_stage1_cb; 1139*d7802caeSToomas Soome pl->pl_cb.install = install_stage1_cb; 1140*d7802caeSToomas Soome pl->pl_cb.read = read_stage1_cb; 1141*d7802caeSToomas Soome pl->pl_cb.read_bbl = read_stage1_bbl_cb; 1142*d7802caeSToomas Soome pl->pl_cb.print = print_stage1_cb; 1143*d7802caeSToomas Soome STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1144*d7802caeSToomas Soome } else if (data->target.fstype != IB_FS_ZFS) { 1145*d7802caeSToomas Soome (void) fprintf(stderr, gettext("Booting %s from EFI " 1146*d7802caeSToomas Soome "labeled disks requires the boot partition.\n"), 1147*d7802caeSToomas Soome data->target.fstype == IB_FS_UFS? 1148*d7802caeSToomas Soome MNTTYPE_UFS : MNTTYPE_PCFS); 1149*d7802caeSToomas Soome goto done; 1150*d7802caeSToomas Soome } 1151*d7802caeSToomas Soome /* Add stage 2 */ 1152*d7802caeSToomas Soome if (!allocate_slice(data, vtoc, V_BOOT, &pl)) 1153*d7802caeSToomas Soome goto done; 1154*d7802caeSToomas Soome if (pl != NULL) { 1155*d7802caeSToomas Soome pl->pl_src_name = stage2; 1156*d7802caeSToomas Soome pl->pl_type = IB_BBLK_STAGE2; 1157*d7802caeSToomas Soome pl->pl_cb.compare = compare_einfo_cb; 1158*d7802caeSToomas Soome pl->pl_cb.install = install_stage2_cb; 1159*d7802caeSToomas Soome pl->pl_cb.read = read_stage2_cb; 1160*d7802caeSToomas Soome pl->pl_cb.read_bbl = read_stage2_file_cb; 1161*d7802caeSToomas Soome pl->pl_cb.print = print_einfo_cb; 1162*d7802caeSToomas Soome STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1163*d7802caeSToomas Soome } 1164*d7802caeSToomas Soome 1165*d7802caeSToomas Soome /* ESP can have 32- and 64-bit boot code. */ 1166*d7802caeSToomas Soome if (!allocate_slice(data, vtoc, V_SYSTEM, &pl)) 1167*d7802caeSToomas Soome goto done; 1168*d7802caeSToomas Soome if (pl != NULL) { 1169*d7802caeSToomas Soome pl->pl_device->stage.path = "/EFI/Boot/" BOOTIA32; 1170*d7802caeSToomas Soome pl->pl_src_name = efi32; 1171*d7802caeSToomas Soome pl->pl_type = IB_BBLK_EFI; 1172*d7802caeSToomas Soome pl->pl_cb.compare = compare_einfo_cb; 1173*d7802caeSToomas Soome pl->pl_cb.install = install_esp_cb; 1174*d7802caeSToomas Soome pl->pl_cb.read = read_einfo_esp_cb; 1175*d7802caeSToomas Soome pl->pl_cb.read_bbl = read_stage2_file_cb; 1176*d7802caeSToomas Soome pl->pl_cb.print = print_einfo_cb; 1177*d7802caeSToomas Soome STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1178*d7802caeSToomas Soome } 1179*d7802caeSToomas Soome if (!allocate_slice(data, vtoc, V_SYSTEM, &pl)) 1180*d7802caeSToomas Soome goto done; 1181*d7802caeSToomas Soome if (pl != NULL) { 1182*d7802caeSToomas Soome pl->pl_device->stage.path = "/EFI/Boot/" BOOTX64; 1183*d7802caeSToomas Soome pl->pl_src_name = efi64; 1184*d7802caeSToomas Soome pl->pl_type = IB_BBLK_EFI; 1185*d7802caeSToomas Soome pl->pl_cb.compare = compare_einfo_cb; 1186*d7802caeSToomas Soome pl->pl_cb.install = install_esp_cb; 1187*d7802caeSToomas Soome pl->pl_cb.read = read_einfo_esp_cb; 1188*d7802caeSToomas Soome pl->pl_cb.read_bbl = read_stage2_file_cb; 1189*d7802caeSToomas Soome pl->pl_cb.print = print_einfo_cb; 1190*d7802caeSToomas Soome STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1191*d7802caeSToomas Soome } 1192*d7802caeSToomas Soome 1193*d7802caeSToomas Soome /* add stage for our target file system slice */ 1194*d7802caeSToomas Soome pl = partlist_alloc(); 1195*d7802caeSToomas Soome if (pl == NULL) 1196*d7802caeSToomas Soome goto done; 1197*d7802caeSToomas Soome 1198*d7802caeSToomas Soome device = pl->pl_device; 1199*d7802caeSToomas Soome device->stage.devtype = data->device.devtype; 1200*d7802caeSToomas Soome if ((pl->pl_devname = strdup(data->target.path)) == NULL) { 1201*d7802caeSToomas Soome perror(gettext("Memory allocation failure")); 1202*d7802caeSToomas Soome partlist_free(pl); 1203*d7802caeSToomas Soome goto done; 12040c946d80SToomas Soome } 12050c946d80SToomas Soome 1206*d7802caeSToomas Soome device->stage.id = slice; 1207*d7802caeSToomas Soome device->stage.start = vtoc->efi_parts[slice].p_start; 1208*d7802caeSToomas Soome device->stage.size = vtoc->efi_parts[slice].p_size; 12090c946d80SToomas Soome 1210*d7802caeSToomas Soome /* ZFS and UFS can have stage1 in boot area. */ 1211*d7802caeSToomas Soome if (data->target.fstype == IB_FS_ZFS || 1212*d7802caeSToomas Soome data->target.fstype == IB_FS_UFS) { 1213*d7802caeSToomas Soome pl->pl_src_name = stage1; 1214*d7802caeSToomas Soome pl->pl_type = IB_BBLK_STAGE1; 1215*d7802caeSToomas Soome pl->pl_cb.compare = compare_stage1_cb; 1216*d7802caeSToomas Soome pl->pl_cb.install = install_stage1_cb; 1217*d7802caeSToomas Soome pl->pl_cb.read = read_stage1_cb; 1218*d7802caeSToomas Soome pl->pl_cb.read_bbl = read_stage1_bbl_cb; 1219*d7802caeSToomas Soome pl->pl_cb.print = print_stage1_cb; 1220*d7802caeSToomas Soome STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1221*d7802caeSToomas Soome } 12220c946d80SToomas Soome 1223*d7802caeSToomas Soome if (data->target.fstype == IB_FS_ZFS) { 1224*d7802caeSToomas Soome pl = partlist_alloc(); 1225*d7802caeSToomas Soome if (pl == NULL) 1226*d7802caeSToomas Soome goto done; 12270c946d80SToomas Soome 1228*d7802caeSToomas Soome device = pl->pl_device; 1229*d7802caeSToomas Soome device->stage.devtype = data->device.devtype; 1230*d7802caeSToomas Soome 1231*d7802caeSToomas Soome if ((pl->pl_devname = strdup(data->target.path)) == NULL) { 1232*d7802caeSToomas Soome perror(gettext("Memory allocation failure")); 1233*d7802caeSToomas Soome goto done; 12340c946d80SToomas Soome } 12350c946d80SToomas Soome 1236*d7802caeSToomas Soome device->stage.id = slice; 1237*d7802caeSToomas Soome device->stage.start = vtoc->efi_parts[slice].p_start; 1238*d7802caeSToomas Soome device->stage.size = vtoc->efi_parts[slice].p_size; 1239*d7802caeSToomas Soome 1240*d7802caeSToomas Soome device->stage.offset = BBLK_ZFS_BLK_OFF; 1241*d7802caeSToomas Soome pl->pl_src_name = stage2; 1242*d7802caeSToomas Soome pl->pl_type = IB_BBLK_STAGE2; 1243*d7802caeSToomas Soome pl->pl_cb.compare = compare_einfo_cb; 1244*d7802caeSToomas Soome pl->pl_cb.install = install_stage2_cb; 1245*d7802caeSToomas Soome pl->pl_cb.read = read_stage2_cb; 1246*d7802caeSToomas Soome pl->pl_cb.read_bbl = read_stage2_file_cb; 1247*d7802caeSToomas Soome pl->pl_cb.print = print_einfo_cb; 1248*d7802caeSToomas Soome STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1249*d7802caeSToomas Soome } 1250*d7802caeSToomas Soome rv = true; 1251*d7802caeSToomas Soome done: 1252*d7802caeSToomas Soome efi_free(vtoc); 1253*d7802caeSToomas Soome return (rv); 1254*d7802caeSToomas Soome } 12550c946d80SToomas Soome 1256*d7802caeSToomas Soome static bool 1257*d7802caeSToomas Soome get_start_sector(ib_data_t *data, struct extpartition *v_part, 1258*d7802caeSToomas Soome diskaddr_t *start) 1259*d7802caeSToomas Soome { 1260*d7802caeSToomas Soome struct partlist *pl; 1261*d7802caeSToomas Soome struct mboot *mbr; 1262*d7802caeSToomas Soome struct ipart *part; 1263*d7802caeSToomas Soome struct part_info dkpi; 1264*d7802caeSToomas Soome struct extpart_info edkpi; 1265*d7802caeSToomas Soome uint32_t secnum, numsec; 1266*d7802caeSToomas Soome ext_part_t *epp; 1267*d7802caeSToomas Soome ushort_t i; 1268*d7802caeSToomas Soome int fd, rval, pno; 1269*d7802caeSToomas Soome 1270*d7802caeSToomas Soome if ((fd = open_device(data->target.path)) < 0) 1271*d7802caeSToomas Soome return (false); 1272*d7802caeSToomas Soome 1273*d7802caeSToomas Soome if (ioctl(fd, DKIOCEXTPARTINFO, &edkpi) < 0) { 1274*d7802caeSToomas Soome if (ioctl(fd, DKIOCPARTINFO, &dkpi) < 0) { 12750c946d80SToomas Soome (void) fprintf(stderr, gettext("cannot get the " 12760c946d80SToomas Soome "slice information of the disk\n")); 1277*d7802caeSToomas Soome (void) close(fd); 1278*d7802caeSToomas Soome return (false); 12790c946d80SToomas Soome } else { 12800c946d80SToomas Soome edkpi.p_start = dkpi.p_start; 12810c946d80SToomas Soome edkpi.p_length = dkpi.p_length; 12820c946d80SToomas Soome } 12830c946d80SToomas Soome } 1284*d7802caeSToomas Soome (void) close(fd); 12850c946d80SToomas Soome 1286*d7802caeSToomas Soome /* Set target file system start and size */ 1287*d7802caeSToomas Soome data->target.start = edkpi.p_start; 1288*d7802caeSToomas Soome data->target.size = edkpi.p_length; 12890c946d80SToomas Soome 1290*d7802caeSToomas Soome /* This is our MBR partition start. */ 1291*d7802caeSToomas Soome edkpi.p_start -= v_part->p_start; 12920c946d80SToomas Soome 1293*d7802caeSToomas Soome /* Head is always MBR */ 1294*d7802caeSToomas Soome pl = STAILQ_FIRST(data->plist); 1295*d7802caeSToomas Soome if (!read_stage1_cb(pl)) 1296*d7802caeSToomas Soome return (false); 12970c946d80SToomas Soome 1298*d7802caeSToomas Soome mbr = (struct mboot *)pl->pl_stage; 1299*d7802caeSToomas Soome part = (struct ipart *)mbr->parts; 13000c946d80SToomas Soome 1301*d7802caeSToomas Soome for (i = 0; i < FD_NUMPART; i++) { 1302*d7802caeSToomas Soome if (part[i].relsect == edkpi.p_start) { 1303*d7802caeSToomas Soome *start = part[i].relsect; 1304*d7802caeSToomas Soome return (true); 1305*d7802caeSToomas Soome } 13060c946d80SToomas Soome } 13070c946d80SToomas Soome 1308*d7802caeSToomas Soome rval = libfdisk_init(&epp, pl->pl_devname, part, FDISK_READ_DISK); 1309*d7802caeSToomas Soome if (rval != FDISK_SUCCESS) { 13100c946d80SToomas Soome switch (rval) { 13110c946d80SToomas Soome /* 13120c946d80SToomas Soome * The first 3 cases are not an error per-se, just that 13130c946d80SToomas Soome * there is no Solaris logical partition 13140c946d80SToomas Soome */ 13150c946d80SToomas Soome case FDISK_EBADLOGDRIVE: 13160c946d80SToomas Soome case FDISK_ENOLOGDRIVE: 13170c946d80SToomas Soome case FDISK_EBADMAGIC: 13180c946d80SToomas Soome (void) fprintf(stderr, gettext("Solaris " 13190c946d80SToomas Soome "partition not found. " 1320*d7802caeSToomas Soome "Aborting operation. %d\n"), rval); 1321*d7802caeSToomas Soome return (false); 13220c946d80SToomas Soome case FDISK_ENOVGEOM: 13230c946d80SToomas Soome (void) fprintf(stderr, gettext("Could not get " 13240c946d80SToomas Soome "virtual geometry\n")); 1325*d7802caeSToomas Soome return (false); 13260c946d80SToomas Soome case FDISK_ENOPGEOM: 13270c946d80SToomas Soome (void) fprintf(stderr, gettext("Could not get " 13280c946d80SToomas Soome "physical geometry\n")); 1329*d7802caeSToomas Soome return (false); 13300c946d80SToomas Soome case FDISK_ENOLGEOM: 13310c946d80SToomas Soome (void) fprintf(stderr, gettext("Could not get " 13320c946d80SToomas Soome "label geometry\n")); 1333*d7802caeSToomas Soome return (false); 13340c946d80SToomas Soome default: 13350c946d80SToomas Soome (void) fprintf(stderr, gettext("Failed to " 13360c946d80SToomas Soome "initialize libfdisk.\n")); 1337*d7802caeSToomas Soome return (false); 13380c946d80SToomas Soome } 13390c946d80SToomas Soome } 13400c946d80SToomas Soome rval = fdisk_get_solaris_part(epp, &pno, &secnum, &numsec); 13410c946d80SToomas Soome libfdisk_fini(&epp); 13420c946d80SToomas Soome if (rval != FDISK_SUCCESS) { 13430c946d80SToomas Soome /* No solaris logical partition */ 13440c946d80SToomas Soome (void) fprintf(stderr, gettext("Solaris partition not found. " 13450c946d80SToomas Soome "Aborting operation.\n")); 1346*d7802caeSToomas Soome return (false); 13470c946d80SToomas Soome } 1348*d7802caeSToomas Soome *start = secnum; 1349*d7802caeSToomas Soome return (true); 1350*d7802caeSToomas Soome } 13510c946d80SToomas Soome 1352*d7802caeSToomas Soome /* 1353*d7802caeSToomas Soome * On x86 the VTOC table is inside MBR partition and to get 1354*d7802caeSToomas Soome * absolute sectors, we need to add MBR partition start to VTOC slice start. 1355*d7802caeSToomas Soome */ 1356*d7802caeSToomas Soome static bool 1357*d7802caeSToomas Soome probe_vtoc(ib_data_t *data) 1358*d7802caeSToomas Soome { 1359*d7802caeSToomas Soome struct partlist *pl; 1360*d7802caeSToomas Soome struct extvtoc exvtoc; 1361*d7802caeSToomas Soome ib_device_t *device; 1362*d7802caeSToomas Soome char *path, *ptr; 1363*d7802caeSToomas Soome ushort_t i; 1364*d7802caeSToomas Soome int slice, fd; 1365*d7802caeSToomas Soome diskaddr_t start; 1366*d7802caeSToomas Soome bool rv; 13670c946d80SToomas Soome 1368*d7802caeSToomas Soome rv = false; 1369*d7802caeSToomas Soome 1370*d7802caeSToomas Soome if ((fd = open_device(data->target.path)) < 0) 1371*d7802caeSToomas Soome return (rv); 1372*d7802caeSToomas Soome 1373*d7802caeSToomas Soome slice = read_extvtoc(fd, &exvtoc); 1374*d7802caeSToomas Soome (void) close(fd); 1375*d7802caeSToomas Soome if (slice < 0) 1376*d7802caeSToomas Soome return (rv); 1377*d7802caeSToomas Soome data->device.devtype = IB_DEV_VTOC; 1378*d7802caeSToomas Soome 1379*d7802caeSToomas Soome if (!get_start_sector(data, exvtoc.v_part + slice, &start)) 1380*d7802caeSToomas Soome return (rv); 1381*d7802caeSToomas Soome 1382*d7802caeSToomas Soome if (exvtoc.v_part[slice].p_tag == V_BACKUP) { 1383*d7802caeSToomas Soome /* 1384*d7802caeSToomas Soome * NOTE: we could relax there and allow zfs boot on 1385*d7802caeSToomas Soome * slice 2, but lets keep traditional limits. 1386*d7802caeSToomas Soome */ 1387*d7802caeSToomas Soome (void) fprintf(stderr, gettext( 1388*d7802caeSToomas Soome "raw device must be a root slice (not backup)\n")); 1389*d7802caeSToomas Soome return (rv); 1390*d7802caeSToomas Soome } 1391*d7802caeSToomas Soome 1392*d7802caeSToomas Soome if ((path = strdup(data->target.path)) == NULL) { 1393*d7802caeSToomas Soome perror(gettext("Memory allocation failure")); 1394*d7802caeSToomas Soome return (false); 1395*d7802caeSToomas Soome } 1396*d7802caeSToomas Soome 1397*d7802caeSToomas Soome data->target.start = start + exvtoc.v_part[slice].p_start; 1398*d7802caeSToomas Soome data->target.size = exvtoc.v_part[slice].p_size; 1399*d7802caeSToomas Soome 1400*d7802caeSToomas Soome /* Search for boot slice. */ 1401*d7802caeSToomas Soome for (i = 0; i < exvtoc.v_nparts; i++) { 1402*d7802caeSToomas Soome if (exvtoc.v_part[i].p_tag == V_BOOT) 1403*d7802caeSToomas Soome break; 1404*d7802caeSToomas Soome } 1405*d7802caeSToomas Soome 1406*d7802caeSToomas Soome if (i == exvtoc.v_nparts || 1407*d7802caeSToomas Soome exvtoc.v_part[i].p_size == 0) { 1408*d7802caeSToomas Soome /* fall back to slice V_BACKUP */ 1409*d7802caeSToomas Soome for (i = 0; i < exvtoc.v_nparts; i++) { 1410*d7802caeSToomas Soome if (exvtoc.v_part[i].p_tag == V_BACKUP) 1411*d7802caeSToomas Soome break; 1412*d7802caeSToomas Soome } 1413*d7802caeSToomas Soome /* Still nothing? Error out. */ 1414*d7802caeSToomas Soome if (i == exvtoc.v_nparts || 1415*d7802caeSToomas Soome exvtoc.v_part[i].p_size == 0) { 1416*d7802caeSToomas Soome free(path); 1417*d7802caeSToomas Soome return (false); 1418*d7802caeSToomas Soome } 1419*d7802caeSToomas Soome } 1420*d7802caeSToomas Soome 1421*d7802caeSToomas Soome /* Create path. */ 1422*d7802caeSToomas Soome ptr = strrchr(path, 's'); 1423*d7802caeSToomas Soome ptr++; 1424*d7802caeSToomas Soome *ptr = '\0'; 1425*d7802caeSToomas Soome (void) asprintf(&ptr, "%s%d", path, i); 1426*d7802caeSToomas Soome free(path); 1427*d7802caeSToomas Soome if (ptr == NULL) { 1428*d7802caeSToomas Soome perror(gettext("Memory allocation failure")); 1429*d7802caeSToomas Soome return (false); 1430*d7802caeSToomas Soome } 1431*d7802caeSToomas Soome 1432*d7802caeSToomas Soome pl = partlist_alloc(); 1433*d7802caeSToomas Soome if (pl == NULL) { 1434*d7802caeSToomas Soome free(ptr); 1435*d7802caeSToomas Soome return (false); 1436*d7802caeSToomas Soome } 1437*d7802caeSToomas Soome pl->pl_devname = ptr; 1438*d7802caeSToomas Soome device = pl->pl_device; 1439*d7802caeSToomas Soome device->stage.devtype = data->device.devtype; 1440*d7802caeSToomas Soome device->stage.id = i; 1441*d7802caeSToomas Soome device->stage.tag = exvtoc.v_part[i].p_tag; 1442*d7802caeSToomas Soome device->stage.start = start + exvtoc.v_part[i].p_start; 1443*d7802caeSToomas Soome device->stage.size = exvtoc.v_part[i].p_size; 1444*d7802caeSToomas Soome 1445*d7802caeSToomas Soome /* Fix size if this slice is in fact V_BACKUP */ 1446*d7802caeSToomas Soome if (exvtoc.v_part[i].p_tag == V_BACKUP) { 1447*d7802caeSToomas Soome for (i = 0; i < exvtoc.v_nparts; i++) { 1448*d7802caeSToomas Soome if (exvtoc.v_part[i].p_start == 0) 1449*d7802caeSToomas Soome continue; 1450*d7802caeSToomas Soome if (exvtoc.v_part[i].p_size == 0) 1451*d7802caeSToomas Soome continue; 1452*d7802caeSToomas Soome if (exvtoc.v_part[i].p_start < 1453*d7802caeSToomas Soome device->stage.size) 1454*d7802caeSToomas Soome device->stage.size = 1455*d7802caeSToomas Soome exvtoc.v_part[i].p_start; 14560c946d80SToomas Soome } 14570c946d80SToomas Soome } 14580c946d80SToomas Soome 1459*d7802caeSToomas Soome pl->pl_src_name = stage1; 1460*d7802caeSToomas Soome pl->pl_type = IB_BBLK_STAGE1; 1461*d7802caeSToomas Soome pl->pl_cb.compare = compare_stage1_cb; 1462*d7802caeSToomas Soome pl->pl_cb.install = install_stage1_cb; 1463*d7802caeSToomas Soome pl->pl_cb.read = read_stage1_cb; 1464*d7802caeSToomas Soome pl->pl_cb.read_bbl = read_stage1_bbl_cb; 1465*d7802caeSToomas Soome pl->pl_cb.print = print_stage1_cb; 1466*d7802caeSToomas Soome STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1467*d7802caeSToomas Soome 1468*d7802caeSToomas Soome /* Create instance for stage 2 */ 1469*d7802caeSToomas Soome pl = partlist_alloc(); 1470*d7802caeSToomas Soome if (pl == NULL) { 1471*d7802caeSToomas Soome free(ptr); 1472*d7802caeSToomas Soome return (false); 1473*d7802caeSToomas Soome } 1474*d7802caeSToomas Soome pl->pl_devname = strdup(ptr); 1475*d7802caeSToomas Soome if (pl->pl_devname == NULL) { 1476*d7802caeSToomas Soome partlist_free(pl); 1477*d7802caeSToomas Soome return (false); 1478*d7802caeSToomas Soome } 1479*d7802caeSToomas Soome pl->pl_device->stage.devtype = data->device.devtype; 1480*d7802caeSToomas Soome pl->pl_device->stage.id = device->stage.id; 1481*d7802caeSToomas Soome pl->pl_device->stage.offset = BBLK_BLKLIST_OFF; 1482*d7802caeSToomas Soome pl->pl_device->stage.tag = device->stage.tag; 1483*d7802caeSToomas Soome pl->pl_device->stage.start = device->stage.start; 1484*d7802caeSToomas Soome pl->pl_device->stage.size = device->stage.size; 1485*d7802caeSToomas Soome pl->pl_src_name = stage2; 1486*d7802caeSToomas Soome pl->pl_type = IB_BBLK_STAGE2; 1487*d7802caeSToomas Soome pl->pl_cb.compare = compare_einfo_cb; 1488*d7802caeSToomas Soome pl->pl_cb.install = install_stage2_cb; 1489*d7802caeSToomas Soome pl->pl_cb.read = read_stage2_cb; 1490*d7802caeSToomas Soome pl->pl_cb.read_bbl = read_stage2_file_cb; 1491*d7802caeSToomas Soome pl->pl_cb.print = print_einfo_cb; 1492*d7802caeSToomas Soome STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1493*d7802caeSToomas Soome 1494*d7802caeSToomas Soome /* And we are done. */ 1495*d7802caeSToomas Soome rv = true; 1496*d7802caeSToomas Soome return (rv); 1497*d7802caeSToomas Soome } 1498*d7802caeSToomas Soome 1499*d7802caeSToomas Soome static bool 1500*d7802caeSToomas Soome probe_mbr(ib_data_t *data) 1501*d7802caeSToomas Soome { 1502*d7802caeSToomas Soome struct partlist *pl; 1503*d7802caeSToomas Soome struct ipart *part; 1504*d7802caeSToomas Soome struct mboot *mbr; 1505*d7802caeSToomas Soome ib_device_t *device; 1506*d7802caeSToomas Soome char *path, *ptr; 1507*d7802caeSToomas Soome int i, rv; 1508*d7802caeSToomas Soome 1509*d7802caeSToomas Soome data->device.devtype = IB_DEV_MBR; 1510*d7802caeSToomas Soome 1511*d7802caeSToomas Soome /* Head is always MBR */ 1512*d7802caeSToomas Soome pl = STAILQ_FIRST(data->plist); 1513*d7802caeSToomas Soome if (!read_stage1_cb(pl)) 1514*d7802caeSToomas Soome return (false); 1515*d7802caeSToomas Soome 1516*d7802caeSToomas Soome mbr = (struct mboot *)pl->pl_stage; 1517*d7802caeSToomas Soome part = (struct ipart *)mbr->parts; 1518*d7802caeSToomas Soome 1519*d7802caeSToomas Soome /* Set target file system start and size */ 1520*d7802caeSToomas Soome data->target.start = part[data->target.id - 1].relsect; 1521*d7802caeSToomas Soome data->target.size = part[data->target.id - 1].numsect; 1522*d7802caeSToomas Soome 1523*d7802caeSToomas Soome /* Use X86BOOT partition if we have one. */ 1524*d7802caeSToomas Soome for (i = 0; i < FD_NUMPART; i++) { 1525*d7802caeSToomas Soome if (part[i].systid == X86BOOT) 1526*d7802caeSToomas Soome break; 1527*d7802caeSToomas Soome } 1528*d7802caeSToomas Soome 1529*d7802caeSToomas Soome /* Keep device name of whole disk device. */ 1530*d7802caeSToomas Soome path = (char *)pl->pl_devname; 1531*d7802caeSToomas Soome if ((pl = partlist_alloc()) == NULL) 1532*d7802caeSToomas Soome return (false); 1533*d7802caeSToomas Soome device = pl->pl_device; 1534*d7802caeSToomas Soome 15350c946d80SToomas Soome /* 1536*d7802caeSToomas Soome * No X86BOOT, try to use space between MBR and first 1537*d7802caeSToomas Soome * partition. 15380c946d80SToomas Soome */ 1539*d7802caeSToomas Soome if (i == FD_NUMPART) { 1540*d7802caeSToomas Soome /* with pcfs we always write MBR */ 1541*d7802caeSToomas Soome if (data->target.fstype == IB_FS_PCFS) { 1542*d7802caeSToomas Soome force_mbr = true; 1543*d7802caeSToomas Soome write_mbr = true; 15440c946d80SToomas Soome } 1545*d7802caeSToomas Soome 1546*d7802caeSToomas Soome pl->pl_devname = strdup(path); 1547*d7802caeSToomas Soome if (pl->pl_devname == NULL) { 1548*d7802caeSToomas Soome perror(gettext("Memory allocation failure")); 1549*d7802caeSToomas Soome partlist_free(pl); 1550*d7802caeSToomas Soome return (false); 1551*d7802caeSToomas Soome } 1552*d7802caeSToomas Soome device->stage.id = 0; 1553*d7802caeSToomas Soome device->stage.devtype = IB_DEV_MBR; 1554*d7802caeSToomas Soome device->stage.fstype = IB_FS_NONE; 1555*d7802caeSToomas Soome device->stage.start = 0; 1556*d7802caeSToomas Soome device->stage.size = part[0].relsect; 1557*d7802caeSToomas Soome device->stage.offset = BBLK_BLKLIST_OFF; 1558*d7802caeSToomas Soome pl->pl_src_name = stage2; 1559*d7802caeSToomas Soome pl->pl_type = IB_BBLK_STAGE2; 1560*d7802caeSToomas Soome pl->pl_cb.compare = compare_einfo_cb; 1561*d7802caeSToomas Soome pl->pl_cb.install = install_stage2_cb; 1562*d7802caeSToomas Soome pl->pl_cb.read = read_stage2_cb; 1563*d7802caeSToomas Soome pl->pl_cb.read_bbl = read_stage2_file_cb; 1564*d7802caeSToomas Soome pl->pl_cb.print = print_einfo_cb; 1565*d7802caeSToomas Soome STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1566*d7802caeSToomas Soome 1567*d7802caeSToomas Soome /* We have MBR for stage1 and gap for stage2, we are done. */ 1568*d7802caeSToomas Soome return (true); 15690c946d80SToomas Soome } 15700c946d80SToomas Soome 1571*d7802caeSToomas Soome if ((path = strdup(path)) == NULL) { 1572*d7802caeSToomas Soome perror(gettext("Memory allocation failure")); 1573*d7802caeSToomas Soome partlist_free(pl); 1574*d7802caeSToomas Soome return (false); 1575*d7802caeSToomas Soome } 1576*d7802caeSToomas Soome ptr = strrchr(path, 'p'); 1577*d7802caeSToomas Soome ptr++; 1578*d7802caeSToomas Soome *ptr = '\0'; 1579*d7802caeSToomas Soome /* partitions are p1..p4 */ 1580*d7802caeSToomas Soome rv = asprintf(&ptr, "%s%d", path, i + 1); 1581*d7802caeSToomas Soome free(path); 1582*d7802caeSToomas Soome if (rv < 0) { 1583*d7802caeSToomas Soome perror(gettext("Memory allocation failure")); 1584*d7802caeSToomas Soome partlist_free(pl); 1585*d7802caeSToomas Soome return (false); 1586*d7802caeSToomas Soome } 1587*d7802caeSToomas Soome pl->pl_devname = ptr; 1588*d7802caeSToomas Soome device->stage.id = i + 1; 1589*d7802caeSToomas Soome device->stage.devtype = IB_DEV_MBR; 1590*d7802caeSToomas Soome device->stage.fstype = IB_FS_NONE; 1591*d7802caeSToomas Soome device->stage.start = part[i].relsect; 1592*d7802caeSToomas Soome device->stage.size = part[i].numsect; 1593*d7802caeSToomas Soome pl->pl_src_name = stage1; 1594*d7802caeSToomas Soome pl->pl_type = IB_BBLK_STAGE1; 1595*d7802caeSToomas Soome pl->pl_cb.compare = compare_stage1_cb; 1596*d7802caeSToomas Soome pl->pl_cb.install = install_stage1_cb; 1597*d7802caeSToomas Soome pl->pl_cb.read = read_stage1_cb; 1598*d7802caeSToomas Soome pl->pl_cb.read_bbl = read_stage1_bbl_cb; 1599*d7802caeSToomas Soome pl->pl_cb.print = print_stage1_cb; 1600*d7802caeSToomas Soome STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1601*d7802caeSToomas Soome 1602*d7802caeSToomas Soome pl = partlist_alloc(); 1603*d7802caeSToomas Soome if (pl == NULL) 1604*d7802caeSToomas Soome return (false); 1605*d7802caeSToomas Soome device = pl->pl_device; 1606*d7802caeSToomas Soome pl->pl_devname = strdup(ptr); 1607*d7802caeSToomas Soome if (pl->pl_devname == NULL) { 1608*d7802caeSToomas Soome perror(gettext("Memory allocation failure")); 1609*d7802caeSToomas Soome partlist_free(pl); 1610*d7802caeSToomas Soome return (false); 1611*d7802caeSToomas Soome } 1612*d7802caeSToomas Soome device->stage.id = i + 1; 1613*d7802caeSToomas Soome device->stage.devtype = IB_DEV_MBR; 1614*d7802caeSToomas Soome device->stage.fstype = IB_FS_NONE; 1615*d7802caeSToomas Soome device->stage.start = part[i].relsect; 1616*d7802caeSToomas Soome device->stage.size = part[i].numsect; 1617*d7802caeSToomas Soome device->stage.offset = 1; 1618*d7802caeSToomas Soome /* This is boot partition */ 1619*d7802caeSToomas Soome device->stage.tag = V_BOOT; 1620*d7802caeSToomas Soome pl->pl_src_name = stage2; 1621*d7802caeSToomas Soome pl->pl_type = IB_BBLK_STAGE2; 1622*d7802caeSToomas Soome pl->pl_cb.compare = compare_einfo_cb; 1623*d7802caeSToomas Soome pl->pl_cb.install = install_stage2_cb; 1624*d7802caeSToomas Soome pl->pl_cb.read = read_stage2_cb; 1625*d7802caeSToomas Soome pl->pl_cb.read_bbl = read_stage2_file_cb; 1626*d7802caeSToomas Soome pl->pl_cb.print = print_einfo_cb; 1627*d7802caeSToomas Soome STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1628*d7802caeSToomas Soome 1629*d7802caeSToomas Soome return (true); 1630*d7802caeSToomas Soome } 1631*d7802caeSToomas Soome 1632*d7802caeSToomas Soome static bool 1633*d7802caeSToomas Soome probe_device(ib_data_t *data, const char *dev) 1634*d7802caeSToomas Soome { 1635*d7802caeSToomas Soome struct partlist *pl; 1636*d7802caeSToomas Soome struct stat sb; 1637*d7802caeSToomas Soome const char *ptr; 1638*d7802caeSToomas Soome char *p0; 1639*d7802caeSToomas Soome int fd, len; 1640*d7802caeSToomas Soome 1641*d7802caeSToomas Soome if (dev == NULL) 1642*d7802caeSToomas Soome return (NULL); 1643*d7802caeSToomas Soome 1644*d7802caeSToomas Soome len = strlen(dev); 1645*d7802caeSToomas Soome 1646*d7802caeSToomas Soome if ((pl = partlist_alloc()) == NULL) 1647*d7802caeSToomas Soome return (false); 1648*d7802caeSToomas Soome 1649*d7802caeSToomas Soome if (stat(dev, &sb) == -1) { 1650*d7802caeSToomas Soome perror("stat"); 1651*d7802caeSToomas Soome partlist_free(pl); 1652*d7802caeSToomas Soome return (false); 1653*d7802caeSToomas Soome } 1654*d7802caeSToomas Soome 1655*d7802caeSToomas Soome /* We have regular file, register it and we are done. */ 1656*d7802caeSToomas Soome if (S_ISREG(sb.st_mode) != 0) { 1657*d7802caeSToomas Soome pl->pl_devname = (char *)dev; 1658*d7802caeSToomas Soome 1659*d7802caeSToomas Soome pl->pl_type = IB_BBLK_FILE; 1660*d7802caeSToomas Soome pl->pl_cb.read = read_einfo_file_cb; 1661*d7802caeSToomas Soome pl->pl_cb.print = print_einfo_cb; 1662*d7802caeSToomas Soome STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1663*d7802caeSToomas Soome return (true); 1664*d7802caeSToomas Soome } 1665*d7802caeSToomas Soome 1666*d7802caeSToomas Soome /* 1667*d7802caeSToomas Soome * This is block device. 1668*d7802caeSToomas Soome * We do not allow to specify whole disk device (cXtYdZp0 or cXtYdZ). 1669*d7802caeSToomas Soome */ 1670*d7802caeSToomas Soome if ((ptr = strrchr(dev, '/')) == NULL) 1671*d7802caeSToomas Soome ptr = dev; 1672*d7802caeSToomas Soome if ((strrchr(ptr, 'p') == NULL && strrchr(ptr, 's') == NULL) || 1673*d7802caeSToomas Soome (dev[len - 2] == 'p' && dev[len - 1] == '0')) { 1674*d7802caeSToomas Soome (void) fprintf(stderr, 1675*d7802caeSToomas Soome gettext("whole disk device is not supported\n")); 1676*d7802caeSToomas Soome partlist_free(pl); 1677*d7802caeSToomas Soome return (false); 1678*d7802caeSToomas Soome } 1679*d7802caeSToomas Soome 1680*d7802caeSToomas Soome data->target.path = (char *)dev; 1681*d7802caeSToomas Soome if (!probe_fstyp(data)) { 1682*d7802caeSToomas Soome partlist_free(pl); 1683*d7802caeSToomas Soome return (false); 1684*d7802caeSToomas Soome } 1685*d7802caeSToomas Soome 1686*d7802caeSToomas Soome /* We start from identifying the whole disk. */ 1687*d7802caeSToomas Soome if ((p0 = strdup(dev)) == NULL) { 1688*d7802caeSToomas Soome perror("calloc"); 1689*d7802caeSToomas Soome partlist_free(pl); 1690*d7802caeSToomas Soome return (false); 1691*d7802caeSToomas Soome } 1692*d7802caeSToomas Soome 1693*d7802caeSToomas Soome pl->pl_devname = p0; 1694*d7802caeSToomas Soome /* Change device name to p0 */ 1695*d7802caeSToomas Soome if ((ptr = strrchr(p0, 'p')) == NULL) 1696*d7802caeSToomas Soome ptr = strrchr(p0, 's'); 1697*d7802caeSToomas Soome p0 = (char *)ptr; 1698*d7802caeSToomas Soome p0[0] = 'p'; 1699*d7802caeSToomas Soome p0[1] = '0'; 1700*d7802caeSToomas Soome p0[2] = '\0'; 1701*d7802caeSToomas Soome 1702*d7802caeSToomas Soome if ((fd = open_device(pl->pl_devname)) == -1) { 1703*d7802caeSToomas Soome partlist_free(pl); 1704*d7802caeSToomas Soome return (false); 1705*d7802caeSToomas Soome } 1706*d7802caeSToomas Soome 1707*d7802caeSToomas Soome sector_size = get_media_info(fd); 1708*d7802caeSToomas Soome (void) close(fd); 1709*d7802caeSToomas Soome 1710*d7802caeSToomas Soome pl->pl_src_name = stage1; 1711*d7802caeSToomas Soome pl->pl_type = IB_BBLK_MBR; 1712*d7802caeSToomas Soome pl->pl_cb.compare = compare_mbr_cb; 1713*d7802caeSToomas Soome pl->pl_cb.install = install_stage1_cb; 1714*d7802caeSToomas Soome pl->pl_cb.read = read_stage1_cb; 1715*d7802caeSToomas Soome pl->pl_cb.read_bbl = read_stage1_bbl_cb; 1716*d7802caeSToomas Soome pl->pl_cb.print = print_stage1_cb; 1717*d7802caeSToomas Soome STAILQ_INSERT_TAIL(data->plist, pl, pl_next); 1718*d7802caeSToomas Soome 1719*d7802caeSToomas Soome if (probe_gpt(data)) 1720*d7802caeSToomas Soome return (true); 1721*d7802caeSToomas Soome 1722*d7802caeSToomas Soome if (data->device.devtype == IB_DEV_UNKNOWN) 1723*d7802caeSToomas Soome if (probe_vtoc(data)) 1724*d7802caeSToomas Soome return (true); 1725*d7802caeSToomas Soome 1726*d7802caeSToomas Soome if (data->device.devtype == IB_DEV_UNKNOWN) 1727*d7802caeSToomas Soome return (probe_mbr(data)); 1728*d7802caeSToomas Soome 1729*d7802caeSToomas Soome return (false); 1730*d7802caeSToomas Soome } 1731*d7802caeSToomas Soome 1732*d7802caeSToomas Soome static int 1733*d7802caeSToomas Soome read_bootblock_from_file(const char *file, ib_bootblock_t *bblock) 1734*d7802caeSToomas Soome { 1735*d7802caeSToomas Soome struct stat sb; 1736*d7802caeSToomas Soome uint32_t buf_size; 1737*d7802caeSToomas Soome uint32_t mboot_off; 1738*d7802caeSToomas Soome int fd = -1; 1739*d7802caeSToomas Soome int retval = BC_ERROR; 1740*d7802caeSToomas Soome 1741*d7802caeSToomas Soome assert(bblock != NULL); 1742*d7802caeSToomas Soome assert(file != NULL); 1743*d7802caeSToomas Soome 1744*d7802caeSToomas Soome fd = open(file, O_RDONLY); 1745*d7802caeSToomas Soome if (fd == -1) { 1746*d7802caeSToomas Soome BOOT_DEBUG("Error opening %s\n", file); 1747*d7802caeSToomas Soome goto out; 1748*d7802caeSToomas Soome } 1749*d7802caeSToomas Soome 1750*d7802caeSToomas Soome if (fstat(fd, &sb) == -1) { 1751*d7802caeSToomas Soome BOOT_DEBUG("Error getting information (stat) about %s", file); 1752*d7802caeSToomas Soome perror("stat"); 1753*d7802caeSToomas Soome goto outfd; 1754*d7802caeSToomas Soome } 1755*d7802caeSToomas Soome 1756*d7802caeSToomas Soome /* loader bootblock has version built in */ 1757*d7802caeSToomas Soome buf_size = sb.st_size; 1758*d7802caeSToomas Soome 1759*d7802caeSToomas Soome bblock->buf_size = buf_size; 1760*d7802caeSToomas Soome BOOT_DEBUG("bootblock in-memory buffer size is %d\n", 1761*d7802caeSToomas Soome bblock->buf_size); 1762*d7802caeSToomas Soome 1763*d7802caeSToomas Soome bblock->buf = malloc(buf_size); 1764*d7802caeSToomas Soome if (bblock->buf == NULL) { 1765*d7802caeSToomas Soome perror(gettext("Memory allocation failure")); 1766*d7802caeSToomas Soome goto outbuf; 1767*d7802caeSToomas Soome } 1768*d7802caeSToomas Soome bblock->file = bblock->buf; 1769*d7802caeSToomas Soome 1770*d7802caeSToomas Soome if (read(fd, bblock->file, bblock->buf_size) != bblock->buf_size) { 1771*d7802caeSToomas Soome BOOT_DEBUG("Read from %s failed\n", file); 1772*d7802caeSToomas Soome perror("read"); 1773*d7802caeSToomas Soome goto outfd; 1774*d7802caeSToomas Soome } 1775*d7802caeSToomas Soome 1776*d7802caeSToomas Soome buf_size = MIN(buf_size, MBOOT_SCAN_SIZE); 1777*d7802caeSToomas Soome if (find_multiboot(bblock->file, buf_size, &mboot_off) 1778*d7802caeSToomas Soome != BC_SUCCESS) { 1779*d7802caeSToomas Soome (void) fprintf(stderr, 1780*d7802caeSToomas Soome gettext("Unable to find multiboot header\n")); 1781*d7802caeSToomas Soome goto outfd; 1782*d7802caeSToomas Soome } 1783*d7802caeSToomas Soome 1784*d7802caeSToomas Soome bblock->mboot = (multiboot_header_t *)(bblock->file + mboot_off); 1785*d7802caeSToomas Soome bblock->mboot_off = mboot_off; 1786*d7802caeSToomas Soome 1787*d7802caeSToomas Soome bblock->file_size = 1788*d7802caeSToomas Soome bblock->mboot->load_end_addr - bblock->mboot->load_addr; 1789*d7802caeSToomas Soome BOOT_DEBUG("bootblock file size is %d\n", bblock->file_size); 1790*d7802caeSToomas Soome 1791*d7802caeSToomas Soome bblock->extra = bblock->buf + P2ROUNDUP(bblock->file_size, 8); 1792*d7802caeSToomas Soome bblock->extra_size = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8); 1793*d7802caeSToomas Soome 1794*d7802caeSToomas Soome BOOT_DEBUG("mboot at %p offset %d, extra at %p size %d, buf=%p " 1795*d7802caeSToomas Soome "(size=%d)\n", bblock->mboot, bblock->mboot_off, bblock->extra, 1796*d7802caeSToomas Soome bblock->extra_size, bblock->buf, bblock->buf_size); 1797*d7802caeSToomas Soome 1798*d7802caeSToomas Soome (void) close(fd); 17990c946d80SToomas Soome return (BC_SUCCESS); 1800*d7802caeSToomas Soome 1801*d7802caeSToomas Soome outbuf: 1802*d7802caeSToomas Soome (void) free(bblock->buf); 1803*d7802caeSToomas Soome bblock->buf = NULL; 1804*d7802caeSToomas Soome outfd: 1805*d7802caeSToomas Soome (void) close(fd); 1806*d7802caeSToomas Soome out: 1807*d7802caeSToomas Soome if (retval == BC_ERROR) { 1808*d7802caeSToomas Soome (void) fprintf(stderr, 1809*d7802caeSToomas Soome gettext("Error reading bootblock from %s\n"), 1810*d7802caeSToomas Soome file); 1811*d7802caeSToomas Soome } 1812*d7802caeSToomas Soome 1813*d7802caeSToomas Soome if (retval == BC_NOEXTRA) { 1814*d7802caeSToomas Soome BOOT_DEBUG("No multiboot header found on %s, unable to " 1815*d7802caeSToomas Soome "locate extra information area (old/non versioned " 1816*d7802caeSToomas Soome "bootblock?) \n", file); 1817*d7802caeSToomas Soome (void) fprintf(stderr, gettext("No extended information" 1818*d7802caeSToomas Soome " found\n")); 1819*d7802caeSToomas Soome } 1820*d7802caeSToomas Soome return (retval); 1821*d7802caeSToomas Soome } 1822*d7802caeSToomas Soome 1823*d7802caeSToomas Soome static void 1824*d7802caeSToomas Soome add_bootblock_einfo(ib_bootblock_t *bblock, char *updt_str) 1825*d7802caeSToomas Soome { 1826*d7802caeSToomas Soome bblk_hs_t hs; 1827*d7802caeSToomas Soome uint32_t avail_space; 1828*d7802caeSToomas Soome 1829*d7802caeSToomas Soome assert(bblock != NULL); 1830*d7802caeSToomas Soome 1831*d7802caeSToomas Soome if (updt_str == NULL) { 1832*d7802caeSToomas Soome BOOT_DEBUG("WARNING: no update string passed to " 1833*d7802caeSToomas Soome "add_bootblock_einfo()\n"); 1834*d7802caeSToomas Soome return; 1835*d7802caeSToomas Soome } 1836*d7802caeSToomas Soome 1837*d7802caeSToomas Soome /* Fill bootblock hashing source information. */ 1838*d7802caeSToomas Soome hs.src_buf = (unsigned char *)bblock->file; 1839*d7802caeSToomas Soome hs.src_size = bblock->file_size; 1840*d7802caeSToomas Soome /* How much space for the extended information structure? */ 1841*d7802caeSToomas Soome avail_space = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8); 1842*d7802caeSToomas Soome /* Place the extended information structure. */ 1843*d7802caeSToomas Soome add_einfo(bblock->extra, updt_str, &hs, avail_space); 1844*d7802caeSToomas Soome } 1845*d7802caeSToomas Soome 1846*d7802caeSToomas Soome /* 1847*d7802caeSToomas Soome * set up data for case stage1 is installed as MBR 1848*d7802caeSToomas Soome * set up location and size of bootblock 1849*d7802caeSToomas Soome * set disk guid to provide unique information for biosdev command 1850*d7802caeSToomas Soome */ 1851*d7802caeSToomas Soome static void 1852*d7802caeSToomas Soome prepare_stage1(struct partlist *stage1, struct partlist *stage2, uuid_t uuid) 1853*d7802caeSToomas Soome { 1854*d7802caeSToomas Soome char *src, *dest; 1855*d7802caeSToomas Soome ib_bootblock_t *bblk; 1856*d7802caeSToomas Soome ib_device_t *device; 1857*d7802caeSToomas Soome uint16_t size; 1858*d7802caeSToomas Soome struct mboot *mbr; 1859*d7802caeSToomas Soome 1860*d7802caeSToomas Soome src = stage1->pl_stage; 1861*d7802caeSToomas Soome dest = stage1->pl_src_data; 1862*d7802caeSToomas Soome device = stage2->pl_device; 1863*d7802caeSToomas Soome 1864*d7802caeSToomas Soome /* Only copy from valid source. */ 1865*d7802caeSToomas Soome mbr = stage1->pl_stage; 1866*d7802caeSToomas Soome if (mbr->signature == MBB_MAGIC) { 1867*d7802caeSToomas Soome /* copy BPB */ 1868*d7802caeSToomas Soome bcopy(src + STAGE1_BPB_OFFSET, dest + STAGE1_BPB_OFFSET, 1869*d7802caeSToomas Soome STAGE1_BPB_SIZE); 1870*d7802caeSToomas Soome 1871*d7802caeSToomas Soome /* copy MBR, note STAGE1_SIG == BOOTSZ */ 1872*d7802caeSToomas Soome bcopy(src + STAGE1_SIG, dest + STAGE1_SIG, 1873*d7802caeSToomas Soome SECTOR_SIZE - STAGE1_SIG); 1874*d7802caeSToomas Soome } 1875*d7802caeSToomas Soome 1876*d7802caeSToomas Soome bcopy(uuid, dest + STAGE1_STAGE2_UUID, UUID_LEN); 1877*d7802caeSToomas Soome 1878*d7802caeSToomas Soome /* set stage2 size */ 1879*d7802caeSToomas Soome bblk = stage2->pl_src_data; 1880*d7802caeSToomas Soome size = bblk->buf_size / SECTOR_SIZE; 1881*d7802caeSToomas Soome *((uint16_t *)(dest + STAGE1_STAGE2_SIZE)) = size; 1882*d7802caeSToomas Soome 1883*d7802caeSToomas Soome /* set stage2 LBA */ 1884*d7802caeSToomas Soome *((uint64_t *)(dest + STAGE1_STAGE2_LBA)) = 1885*d7802caeSToomas Soome device->stage.start + device->stage.offset; 1886*d7802caeSToomas Soome 1887*d7802caeSToomas Soome /* Copy prepared data to stage1 block read from the disk. */ 1888*d7802caeSToomas Soome bcopy(dest, src, SECTOR_SIZE); 1889*d7802caeSToomas Soome } 1890*d7802caeSToomas Soome 1891*d7802caeSToomas Soome static void 1892*d7802caeSToomas Soome prepare_bootblock(ib_data_t *data, struct partlist *pl, char *updt_str) 1893*d7802caeSToomas Soome { 1894*d7802caeSToomas Soome ib_bootblock_t *bblock; 1895*d7802caeSToomas Soome uint64_t *ptr; 1896*d7802caeSToomas Soome 1897*d7802caeSToomas Soome assert(pl != NULL); 1898*d7802caeSToomas Soome 1899*d7802caeSToomas Soome bblock = pl->pl_src_data; 1900*d7802caeSToomas Soome 1901*d7802caeSToomas Soome ptr = (uint64_t *)(&bblock->mboot->bss_end_addr); 1902*d7802caeSToomas Soome *ptr = data->target.start; 1903*d7802caeSToomas Soome 1904*d7802caeSToomas Soome /* 1905*d7802caeSToomas Soome * the loader bootblock has built in version, if custom 1906*d7802caeSToomas Soome * version was provided, update it. 1907*d7802caeSToomas Soome */ 1908*d7802caeSToomas Soome if (do_version) 1909*d7802caeSToomas Soome add_bootblock_einfo(bblock, updt_str); 19100c946d80SToomas Soome } 19110c946d80SToomas Soome 19120c946d80SToomas Soome static int 1913*d7802caeSToomas Soome open_device(const char *path) 19140c946d80SToomas Soome { 19150c946d80SToomas Soome struct stat statbuf = {0}; 19160c946d80SToomas Soome int fd = -1; 19170c946d80SToomas Soome 19180c946d80SToomas Soome if (nowrite) 19190c946d80SToomas Soome fd = open(path, O_RDONLY); 19200c946d80SToomas Soome else 19210c946d80SToomas Soome fd = open(path, O_RDWR); 19220c946d80SToomas Soome 19230c946d80SToomas Soome if (fd == -1) { 19240c946d80SToomas Soome BOOT_DEBUG("Unable to open %s\n", path); 19250c946d80SToomas Soome perror("open"); 19260c946d80SToomas Soome return (-1); 19270c946d80SToomas Soome } 19280c946d80SToomas Soome 19290c946d80SToomas Soome if (fstat(fd, &statbuf) != 0) { 19300c946d80SToomas Soome BOOT_DEBUG("Unable to stat %s\n", path); 19310c946d80SToomas Soome perror("stat"); 19320c946d80SToomas Soome (void) close(fd); 19330c946d80SToomas Soome return (-1); 19340c946d80SToomas Soome } 19350c946d80SToomas Soome 19360c946d80SToomas Soome if (S_ISCHR(statbuf.st_mode) == 0) { 19370c946d80SToomas Soome (void) fprintf(stderr, gettext("%s: Not a character device\n"), 19380c946d80SToomas Soome path); 19390c946d80SToomas Soome (void) close(fd); 19400c946d80SToomas Soome return (-1); 19410c946d80SToomas Soome } 19420c946d80SToomas Soome 19430c946d80SToomas Soome return (fd); 19440c946d80SToomas Soome } 19450c946d80SToomas Soome 1946*d7802caeSToomas Soome /* 1947*d7802caeSToomas Soome * We need to record stage2 location and size into pmbr/vbr. 1948*d7802caeSToomas Soome * We need to record target partiton LBA to stage2. 1949*d7802caeSToomas Soome */ 1950*d7802caeSToomas Soome static void 1951*d7802caeSToomas Soome prepare_bblocks(ib_data_t *data) 19520c946d80SToomas Soome { 1953*d7802caeSToomas Soome struct partlist *pl; 1954*d7802caeSToomas Soome struct partlist *mbr, *stage1, *stage2; 1955*d7802caeSToomas Soome uuid_t uuid; 19560c946d80SToomas Soome 1957*d7802caeSToomas Soome mbr = stage1 = stage2 = NULL; 1958*d7802caeSToomas Soome /* 1959*d7802caeSToomas Soome * Walk list and pick up BIOS boot blocks. EFI boot programs 1960*d7802caeSToomas Soome * can be set in place. 1961*d7802caeSToomas Soome */ 1962*d7802caeSToomas Soome STAILQ_FOREACH(pl, data->plist, pl_next) { 1963*d7802caeSToomas Soome switch (pl->pl_type) { 1964*d7802caeSToomas Soome case IB_BBLK_MBR: 1965*d7802caeSToomas Soome mbr = pl; 1966*d7802caeSToomas Soome break; 1967*d7802caeSToomas Soome case IB_BBLK_STAGE1: 1968*d7802caeSToomas Soome stage1 = pl; 1969*d7802caeSToomas Soome break; 1970*d7802caeSToomas Soome case IB_BBLK_STAGE2: 1971*d7802caeSToomas Soome stage2 = pl; 1972*d7802caeSToomas Soome /* FALLTHROUGH */ 1973*d7802caeSToomas Soome case IB_BBLK_EFI: 1974*d7802caeSToomas Soome prepare_bootblock(data, pl, update_str); 1975*d7802caeSToomas Soome break; 1976*d7802caeSToomas Soome default: 19770c946d80SToomas Soome break; 19780c946d80SToomas Soome } 19790c946d80SToomas Soome } 19800c946d80SToomas Soome 1981*d7802caeSToomas Soome /* If stage2 is missing, we are done. */ 1982*d7802caeSToomas Soome if (stage2 == NULL) 1983*d7802caeSToomas Soome return; 19840c946d80SToomas Soome 1985*d7802caeSToomas Soome /* 1986*d7802caeSToomas Soome * Create disk uuid. We only need reasonable amount of uniqueness 1987*d7802caeSToomas Soome * to allow biosdev to identify disk based on mbr differences. 1988*d7802caeSToomas Soome */ 1989*d7802caeSToomas Soome uuid_generate(uuid); 19900c946d80SToomas Soome 1991*d7802caeSToomas Soome if (mbr != NULL) { 1992*d7802caeSToomas Soome prepare_stage1(mbr, stage2, uuid); 19930c946d80SToomas Soome 19940c946d80SToomas Soome /* 1995*d7802caeSToomas Soome * If we have stage1, we point MBR to read stage 1. 19960c946d80SToomas Soome */ 1997*d7802caeSToomas Soome if (stage1 != NULL) { 1998*d7802caeSToomas Soome char *dest = mbr->pl_stage; 19990c946d80SToomas Soome 2000*d7802caeSToomas Soome *((uint16_t *)(dest + STAGE1_STAGE2_SIZE)) = 1; 2001*d7802caeSToomas Soome *((uint64_t *)(dest + STAGE1_STAGE2_LBA)) = 2002*d7802caeSToomas Soome stage1->pl_device->stage.start; 20030c946d80SToomas Soome } 20040c946d80SToomas Soome } 20050c946d80SToomas Soome 2006*d7802caeSToomas Soome if (stage1 != NULL) { 2007*d7802caeSToomas Soome prepare_stage1(stage1, stage2, uuid); 20080c946d80SToomas Soome } 20090c946d80SToomas Soome } 20100c946d80SToomas Soome 20110c946d80SToomas Soome /* 20120c946d80SToomas Soome * Install a new bootblock on the given device. handle_install() expects argv 20130c946d80SToomas Soome * to contain 3 parameters (the target device path and the path to the 20140c946d80SToomas Soome * bootblock. 20150c946d80SToomas Soome * 20160c946d80SToomas Soome * Returns: BC_SUCCESS - if the installation is successful 20170c946d80SToomas Soome * BC_ERROR - if the installation failed 20180c946d80SToomas Soome * BC_NOUPDT - if no installation was performed because the 20190c946d80SToomas Soome * version currently installed is more recent than the 20200c946d80SToomas Soome * supplied one. 20210c946d80SToomas Soome * 20220c946d80SToomas Soome */ 20230c946d80SToomas Soome static int 2024*d7802caeSToomas Soome handle_install(char *progname, int argc, char **argv) 20250c946d80SToomas Soome { 2026*d7802caeSToomas Soome struct partlist *pl; 2027*d7802caeSToomas Soome ib_data_t data = { 0 }; 20280c946d80SToomas Soome char *device_path = NULL; 20290c946d80SToomas Soome int ret = BC_ERROR; 20300c946d80SToomas Soome 2031*d7802caeSToomas Soome switch (argc) { 2032*d7802caeSToomas Soome case 1: 2033*d7802caeSToomas Soome if ((device_path = strdup(argv[0])) == NULL) { 2034*d7802caeSToomas Soome perror(gettext("Memory Allocation Failure")); 2035*d7802caeSToomas Soome goto done; 2036*d7802caeSToomas Soome } 2037*d7802caeSToomas Soome if (asprintf(&stage1, "%s/%s", boot_dir, STAGE1) < 0) { 2038*d7802caeSToomas Soome perror(gettext("Memory Allocation Failure")); 2039*d7802caeSToomas Soome goto done; 2040*d7802caeSToomas Soome } 2041*d7802caeSToomas Soome if (asprintf(&stage2, "%s/%s", boot_dir, STAGE2) < 0) { 2042*d7802caeSToomas Soome perror(gettext("Memory Allocation Failure")); 2043*d7802caeSToomas Soome goto done; 2044*d7802caeSToomas Soome } 2045*d7802caeSToomas Soome if (asprintf(&efi32, "%s/%s", boot_dir, LOADER32) < 0) { 2046*d7802caeSToomas Soome perror(gettext("Memory Allocation Failure")); 2047*d7802caeSToomas Soome goto done; 2048*d7802caeSToomas Soome } 2049*d7802caeSToomas Soome if (asprintf(&efi64, "%s/%s", boot_dir, LOADER64) < 0) { 2050*d7802caeSToomas Soome perror(gettext("Memory Allocation Failure")); 2051*d7802caeSToomas Soome goto done; 2052*d7802caeSToomas Soome } 2053*d7802caeSToomas Soome break; 2054*d7802caeSToomas Soome case 3: 2055*d7802caeSToomas Soome if ((stage1 = strdup(argv[0])) == NULL) { 2056*d7802caeSToomas Soome perror(gettext("Memory Allocation Failure")); 2057*d7802caeSToomas Soome goto done; 2058*d7802caeSToomas Soome } 2059*d7802caeSToomas Soome if ((stage2 = strdup(argv[1])) == NULL) { 2060*d7802caeSToomas Soome perror(gettext("Memory Allocation Failure")); 2061*d7802caeSToomas Soome goto done; 2062*d7802caeSToomas Soome } 2063*d7802caeSToomas Soome if ((device_path = strdup(argv[2])) == NULL) { 2064*d7802caeSToomas Soome perror(gettext("Memory Allocation Failure")); 2065*d7802caeSToomas Soome goto done; 2066*d7802caeSToomas Soome } 2067*d7802caeSToomas Soome if (asprintf(&efi32, "%s/%s", boot_dir, LOADER32) < 0) { 2068*d7802caeSToomas Soome perror(gettext("Memory Allocation Failure")); 2069*d7802caeSToomas Soome goto done; 2070*d7802caeSToomas Soome } 2071*d7802caeSToomas Soome if (asprintf(&efi64, "%s/%s", boot_dir, LOADER64) < 0) { 2072*d7802caeSToomas Soome perror(gettext("Memory Allocation Failure")); 2073*d7802caeSToomas Soome goto done; 2074*d7802caeSToomas Soome } 2075*d7802caeSToomas Soome break; 2076*d7802caeSToomas Soome default: 2077*d7802caeSToomas Soome usage(progname, ret); 2078*d7802caeSToomas Soome } 20790c946d80SToomas Soome 2080*d7802caeSToomas Soome data.plist = malloc(sizeof (*data.plist)); 2081*d7802caeSToomas Soome if (data.plist == NULL) { 2082*d7802caeSToomas Soome perror(gettext("Memory Allocation Failure")); 2083*d7802caeSToomas Soome goto done; 20840c946d80SToomas Soome } 2085*d7802caeSToomas Soome STAILQ_INIT(data.plist); 20860c946d80SToomas Soome 20870c946d80SToomas Soome BOOT_DEBUG("device path: %s, stage1 path: %s bootblock path: %s\n", 2088*d7802caeSToomas Soome device_path, stage1, stage2); 20890c946d80SToomas Soome 2090*d7802caeSToomas Soome if (probe_device(&data, device_path)) { 2091*d7802caeSToomas Soome /* Read all data. */ 2092*d7802caeSToomas Soome STAILQ_FOREACH(pl, data.plist, pl_next) { 2093*d7802caeSToomas Soome if (!pl->pl_cb.read(pl)) { 2094*d7802caeSToomas Soome printf("\n"); 2095*d7802caeSToomas Soome } 2096*d7802caeSToomas Soome if (!pl->pl_cb.read_bbl(pl)) { 2097*d7802caeSToomas Soome (void) fprintf(stderr, 2098*d7802caeSToomas Soome gettext("Error reading %s\n"), 2099*d7802caeSToomas Soome pl->pl_src_name); 2100*d7802caeSToomas Soome goto cleanup; 2101*d7802caeSToomas Soome } 2102*d7802caeSToomas Soome } 21030c946d80SToomas Soome 2104*d7802caeSToomas Soome /* Prepare data. */ 2105*d7802caeSToomas Soome prepare_bblocks(&data); 2106*d7802caeSToomas Soome 2107*d7802caeSToomas Soome /* Commit data to disk. */ 2108*d7802caeSToomas Soome while ((pl = STAILQ_LAST(data.plist, partlist, pl_next)) != 2109*d7802caeSToomas Soome NULL) { 2110*d7802caeSToomas Soome if (pl->pl_cb.compare != NULL && 2111*d7802caeSToomas Soome pl->pl_cb.compare(pl)) { 2112*d7802caeSToomas Soome if (pl->pl_cb.install != NULL) 2113*d7802caeSToomas Soome pl->pl_cb.install(&data, pl); 2114*d7802caeSToomas Soome } else { 2115*d7802caeSToomas Soome printf("\n"); 2116*d7802caeSToomas Soome } 2117*d7802caeSToomas Soome STAILQ_REMOVE(data.plist, pl, partlist, pl_next); 2118*d7802caeSToomas Soome partlist_free(pl); 2119*d7802caeSToomas Soome } 21200c946d80SToomas Soome } 2121*d7802caeSToomas Soome ret = BC_SUCCESS; 21220c946d80SToomas Soome 2123*d7802caeSToomas Soome cleanup: 2124*d7802caeSToomas Soome while ((pl = STAILQ_LAST(data.plist, partlist, pl_next)) != NULL) { 2125*d7802caeSToomas Soome STAILQ_REMOVE(data.plist, pl, partlist, pl_next); 2126*d7802caeSToomas Soome partlist_free(pl); 21270c946d80SToomas Soome } 2128*d7802caeSToomas Soome free(data.plist); 2129*d7802caeSToomas Soome done: 21300c946d80SToomas Soome free(stage1); 2131*d7802caeSToomas Soome free(stage2); 2132*d7802caeSToomas Soome free(efi32); 2133*d7802caeSToomas Soome free(efi64); 21340c946d80SToomas Soome free(device_path); 21350c946d80SToomas Soome return (ret); 21360c946d80SToomas Soome } 21370c946d80SToomas Soome 21380c946d80SToomas Soome /* 21390c946d80SToomas Soome * Retrieves from a device the extended information (einfo) associated to the 2140b6dfa2aeSToomas Soome * file or installed stage2. 2141b6dfa2aeSToomas Soome * Expects one parameter, the device path, in the form: /dev/rdsk/c?[t?]d?s0 2142b6dfa2aeSToomas Soome * or file name. 21430c946d80SToomas Soome * Returns: 21440c946d80SToomas Soome * - BC_SUCCESS (and prints out einfo contents depending on 'flags') 21450c946d80SToomas Soome * - BC_ERROR (on error) 21460c946d80SToomas Soome * - BC_NOEINFO (no extended information available) 21470c946d80SToomas Soome */ 21480c946d80SToomas Soome static int 2149*d7802caeSToomas Soome handle_getinfo(char *progname, int argc, char **argv) 21500c946d80SToomas Soome { 2151*d7802caeSToomas Soome struct partlist *pl; 2152*d7802caeSToomas Soome ib_data_t data = { 0 }; 2153*d7802caeSToomas Soome char *device_path; 21540c946d80SToomas Soome 2155*d7802caeSToomas Soome if (argc != 1) { 21560c946d80SToomas Soome (void) fprintf(stderr, gettext("Missing parameter")); 2157bdecfb1eSToomas Soome usage(progname, BC_ERROR); 21580c946d80SToomas Soome } 21590c946d80SToomas Soome 2160*d7802caeSToomas Soome if ((device_path = strdup(argv[0])) == NULL) { 2161*d7802caeSToomas Soome perror(gettext("Memory Allocation Failure")); 2162*d7802caeSToomas Soome return (BC_ERROR); 21630c946d80SToomas Soome } 21640c946d80SToomas Soome 2165*d7802caeSToomas Soome data.plist = malloc(sizeof (*data.plist)); 2166*d7802caeSToomas Soome if (data.plist == NULL) { 2167*d7802caeSToomas Soome perror("malloc"); 2168*d7802caeSToomas Soome free(device_path); 2169*d7802caeSToomas Soome return (BC_ERROR); 21700c946d80SToomas Soome } 2171*d7802caeSToomas Soome STAILQ_INIT(data.plist); 21720c946d80SToomas Soome 2173*d7802caeSToomas Soome if (probe_device(&data, device_path)) { 2174*d7802caeSToomas Soome STAILQ_FOREACH(pl, data.plist, pl_next) { 2175*d7802caeSToomas Soome if (pl->pl_cb.read(pl)) 2176*d7802caeSToomas Soome pl->pl_cb.print(pl); 2177*d7802caeSToomas Soome else 2178*d7802caeSToomas Soome printf("\n"); 2179*d7802caeSToomas Soome } 21800c946d80SToomas Soome } 21810c946d80SToomas Soome 2182*d7802caeSToomas Soome while ((pl = STAILQ_LAST(data.plist, partlist, pl_next)) != NULL) { 2183*d7802caeSToomas Soome STAILQ_REMOVE(data.plist, pl, partlist, pl_next); 2184*d7802caeSToomas Soome partlist_free(pl); 21850c946d80SToomas Soome } 2186*d7802caeSToomas Soome free(data.plist); 21870c946d80SToomas Soome 2188*d7802caeSToomas Soome return (BC_SUCCESS); 21890c946d80SToomas Soome } 21900c946d80SToomas Soome 21910c946d80SToomas Soome /* 21920c946d80SToomas Soome * Attempt to mirror (propagate) the current bootblock over the attaching disk. 21930c946d80SToomas Soome * 21940c946d80SToomas Soome * Returns: 21950c946d80SToomas Soome * - BC_SUCCESS (a successful propagation happened) 21960c946d80SToomas Soome * - BC_ERROR (an error occurred) 21970c946d80SToomas Soome * - BC_NOEXTRA (it is not possible to dump the current bootblock since 21980c946d80SToomas Soome * there is no multiboot information) 21990c946d80SToomas Soome */ 22000c946d80SToomas Soome static int 2201*d7802caeSToomas Soome handle_mirror(char *progname, int argc, char **argv) 22020c946d80SToomas Soome { 2203*d7802caeSToomas Soome ib_data_t src = { 0 }; 2204*d7802caeSToomas Soome ib_data_t dest = { 0 }; 2205*d7802caeSToomas Soome struct partlist *pl_src, *pl_dest; 2206*d7802caeSToomas Soome char *curr_device_path = NULL; 2207*d7802caeSToomas Soome char *attach_device_path = NULL; 22080c946d80SToomas Soome int retval = BC_ERROR; 22090c946d80SToomas Soome 2210*d7802caeSToomas Soome if (argc == 2) { 2211*d7802caeSToomas Soome curr_device_path = strdup(argv[0]); 2212*d7802caeSToomas Soome attach_device_path = strdup(argv[1]); 2213*d7802caeSToomas Soome } 22140c946d80SToomas Soome 22150c946d80SToomas Soome if (!curr_device_path || !attach_device_path) { 2216*d7802caeSToomas Soome free(curr_device_path); 2217*d7802caeSToomas Soome free(attach_device_path); 22180c946d80SToomas Soome (void) fprintf(stderr, gettext("Missing parameter")); 2219bdecfb1eSToomas Soome usage(progname, BC_ERROR); 22200c946d80SToomas Soome } 22210c946d80SToomas Soome BOOT_DEBUG("Current device path is: %s, attaching device path is: " 22220c946d80SToomas Soome " %s\n", curr_device_path, attach_device_path); 22230c946d80SToomas Soome 2224*d7802caeSToomas Soome src.plist = malloc(sizeof (*src.plist)); 2225*d7802caeSToomas Soome if (src.plist == NULL) { 2226*d7802caeSToomas Soome perror("malloc"); 2227*d7802caeSToomas Soome return (BC_ERROR); 2228*d7802caeSToomas Soome } 2229*d7802caeSToomas Soome STAILQ_INIT(src.plist); 2230*d7802caeSToomas Soome 2231*d7802caeSToomas Soome dest.plist = malloc(sizeof (*dest.plist)); 2232*d7802caeSToomas Soome if (dest.plist == NULL) { 2233*d7802caeSToomas Soome perror("malloc"); 2234*d7802caeSToomas Soome goto out; 2235*d7802caeSToomas Soome } 2236*d7802caeSToomas Soome STAILQ_INIT(dest.plist); 22370c946d80SToomas Soome 2238*d7802caeSToomas Soome if (!probe_device(&src, curr_device_path)) { 22390c946d80SToomas Soome (void) fprintf(stderr, gettext("Unable to gather device " 22400c946d80SToomas Soome "information from %s (current device)\n"), 22410c946d80SToomas Soome curr_device_path); 2242*d7802caeSToomas Soome goto out; 22430c946d80SToomas Soome } 22440c946d80SToomas Soome 2245*d7802caeSToomas Soome if (!probe_device(&dest, attach_device_path) != BC_SUCCESS) { 22460c946d80SToomas Soome (void) fprintf(stderr, gettext("Unable to gather device " 22470c946d80SToomas Soome "information from %s (attaching device)\n"), 22480c946d80SToomas Soome attach_device_path); 2249*d7802caeSToomas Soome goto cleanup_src; 22500c946d80SToomas Soome } 22510c946d80SToomas Soome 2252*d7802caeSToomas Soome write_mbr = true; 2253*d7802caeSToomas Soome force_mbr = true; 2254*d7802caeSToomas Soome 2255*d7802caeSToomas Soome pl_dest = STAILQ_FIRST(dest.plist); 2256*d7802caeSToomas Soome STAILQ_FOREACH(pl_src, src.plist, pl_next) { 2257*d7802caeSToomas Soome if (pl_dest == NULL) { 2258*d7802caeSToomas Soome (void) fprintf(stderr, 2259*d7802caeSToomas Soome gettext("Destination disk layout is different " 2260*d7802caeSToomas Soome "from source, can not mirror.\n")); 2261*d7802caeSToomas Soome goto cleanup; 2262*d7802caeSToomas Soome } 2263*d7802caeSToomas Soome if (!pl_src->pl_cb.read(pl_src)) { 2264*d7802caeSToomas Soome (void) fprintf(stderr, gettext("Failed to read " 2265*d7802caeSToomas Soome "boot block from %s\n"), pl_src->pl_devname); 2266*d7802caeSToomas Soome goto cleanup; 2267*d7802caeSToomas Soome } 2268*d7802caeSToomas Soome if (!pl_dest->pl_cb.read(pl_dest)) { 2269*d7802caeSToomas Soome (void) fprintf(stderr, gettext("Failed to read " 2270*d7802caeSToomas Soome "boot block from %s\n"), pl_dest->pl_devname); 2271*d7802caeSToomas Soome } 2272*d7802caeSToomas Soome 2273*d7802caeSToomas Soome /* Set source pl_stage to destination source data */ 2274*d7802caeSToomas Soome pl_dest->pl_src_data = pl_src->pl_stage; 2275*d7802caeSToomas Soome pl_src->pl_stage = NULL; 22760c946d80SToomas Soome 2277*d7802caeSToomas Soome pl_dest = STAILQ_NEXT(pl_dest, pl_next); 22780c946d80SToomas Soome } 22790c946d80SToomas Soome 2280*d7802caeSToomas Soome /* Prepare data. */ 2281*d7802caeSToomas Soome prepare_bblocks(&dest); 22820c946d80SToomas Soome 2283*d7802caeSToomas Soome /* Commit data to disk. */ 2284*d7802caeSToomas Soome while ((pl_dest = STAILQ_LAST(dest.plist, partlist, pl_next)) != NULL) { 2285*d7802caeSToomas Soome pl_dest->pl_cb.install(&dest, pl_dest); 2286*d7802caeSToomas Soome STAILQ_REMOVE(dest.plist, pl_dest, partlist, pl_next); 2287*d7802caeSToomas Soome partlist_free(pl_dest); 2288*d7802caeSToomas Soome 2289*d7802caeSToomas Soome /* Free source list */ 2290*d7802caeSToomas Soome pl_src = STAILQ_LAST(src.plist, partlist, pl_next); 2291*d7802caeSToomas Soome STAILQ_REMOVE(src.plist, pl_src, partlist, pl_next); 2292*d7802caeSToomas Soome partlist_free(pl_src); 2293*d7802caeSToomas Soome } 2294*d7802caeSToomas Soome retval = BC_SUCCESS; 2295*d7802caeSToomas Soome 2296*d7802caeSToomas Soome cleanup: 2297*d7802caeSToomas Soome while ((pl_dest = STAILQ_LAST(dest.plist, partlist, pl_next)) != NULL) { 2298*d7802caeSToomas Soome STAILQ_REMOVE(dest.plist, pl_dest, partlist, pl_next); 2299*d7802caeSToomas Soome partlist_free(pl_dest); 2300*d7802caeSToomas Soome } 2301*d7802caeSToomas Soome free(dest.plist); 2302*d7802caeSToomas Soome cleanup_src: 2303*d7802caeSToomas Soome while ((pl_src = STAILQ_LAST(src.plist, partlist, pl_next)) != NULL) { 2304*d7802caeSToomas Soome STAILQ_REMOVE(src.plist, pl_src, partlist, pl_next); 2305*d7802caeSToomas Soome partlist_free(pl_src); 2306*d7802caeSToomas Soome } 2307*d7802caeSToomas Soome free(src.plist); 2308*d7802caeSToomas Soome out: 23090c946d80SToomas Soome free(curr_device_path); 23100c946d80SToomas Soome free(attach_device_path); 23110c946d80SToomas Soome return (retval); 23120c946d80SToomas Soome } 23130c946d80SToomas Soome 2314*d7802caeSToomas Soome #define USAGE_STRING \ 2315*d7802caeSToomas Soome "Usage:\t%s [-fFmn] [-b boot_dir] [-u verstr]\n" \ 2316*d7802caeSToomas Soome "\t\t[stage1 stage2] raw-device\n" \ 2317*d7802caeSToomas Soome "\t%s -M [-n] raw-device attach-raw-device\n" \ 2318*d7802caeSToomas Soome "\t%s [-e|-V] -i raw-device | file\n" 23190c946d80SToomas Soome 23200c946d80SToomas Soome #define CANON_USAGE_STR gettext(USAGE_STRING) 23210c946d80SToomas Soome 23220c946d80SToomas Soome static void 2323bdecfb1eSToomas Soome usage(char *progname, int rc) 23240c946d80SToomas Soome { 23250c946d80SToomas Soome (void) fprintf(stdout, CANON_USAGE_STR, progname, progname, progname); 2326*d7802caeSToomas Soome fini_yes(); 2327bdecfb1eSToomas Soome exit(rc); 23280c946d80SToomas Soome } 23290c946d80SToomas Soome 23300c946d80SToomas Soome int 23310c946d80SToomas Soome main(int argc, char **argv) 23320c946d80SToomas Soome { 23330c946d80SToomas Soome int opt; 23340c946d80SToomas Soome int ret; 23350c946d80SToomas Soome char *progname; 2336*d7802caeSToomas Soome struct stat sb; 23370c946d80SToomas Soome 23380c946d80SToomas Soome (void) setlocale(LC_ALL, ""); 23390c946d80SToomas Soome (void) textdomain(TEXT_DOMAIN); 2340bdecfb1eSToomas Soome if (init_yes() < 0) 2341bdecfb1eSToomas Soome errx(BC_ERROR, gettext(ERR_MSG_INIT_YES), strerror(errno)); 2342bdecfb1eSToomas Soome 2343*d7802caeSToomas Soome /* Needed for mount pcfs. */ 2344*d7802caeSToomas Soome tzset(); 2345*d7802caeSToomas Soome 2346bdecfb1eSToomas Soome /* Determine our name */ 2347bdecfb1eSToomas Soome progname = basename(argv[0]); 23480c946d80SToomas Soome 2349*d7802caeSToomas Soome while ((opt = getopt(argc, argv, "b:deFfhiMmnu:V")) != EOF) { 23500c946d80SToomas Soome switch (opt) { 2351*d7802caeSToomas Soome case 'b': 2352*d7802caeSToomas Soome boot_dir = strdup(optarg); 2353*d7802caeSToomas Soome if (boot_dir == NULL) { 2354*d7802caeSToomas Soome err(BC_ERROR, 2355*d7802caeSToomas Soome gettext("Memory allocation failure")); 2356*d7802caeSToomas Soome } 2357*d7802caeSToomas Soome if (lstat(boot_dir, &sb) != 0) { 2358*d7802caeSToomas Soome err(BC_ERROR, boot_dir); 2359*d7802caeSToomas Soome } 2360*d7802caeSToomas Soome if (!S_ISDIR(sb.st_mode)) { 2361*d7802caeSToomas Soome errx(BC_ERROR, gettext("%s: not a directory"), 2362*d7802caeSToomas Soome boot_dir); 2363*d7802caeSToomas Soome } 2364*d7802caeSToomas Soome break; 23650c946d80SToomas Soome case 'd': 2366*d7802caeSToomas Soome boot_debug = true; 23670c946d80SToomas Soome break; 23680c946d80SToomas Soome case 'e': 2369*d7802caeSToomas Soome strip = true; 23700c946d80SToomas Soome break; 23710c946d80SToomas Soome case 'F': 2372*d7802caeSToomas Soome force_update = true; 23730c946d80SToomas Soome break; 23740c946d80SToomas Soome case 'f': 2375*d7802caeSToomas Soome force_mbr = true; 23760c946d80SToomas Soome break; 23770c946d80SToomas Soome case 'h': 2378bdecfb1eSToomas Soome usage(progname, BC_SUCCESS); 23790c946d80SToomas Soome break; 23800c946d80SToomas Soome case 'i': 2381*d7802caeSToomas Soome do_getinfo = true; 23820c946d80SToomas Soome break; 23830c946d80SToomas Soome case 'M': 2384*d7802caeSToomas Soome do_mirror_bblk = true; 23850c946d80SToomas Soome break; 23860c946d80SToomas Soome case 'm': 2387*d7802caeSToomas Soome write_mbr = true; 23880c946d80SToomas Soome break; 23890c946d80SToomas Soome case 'n': 2390*d7802caeSToomas Soome nowrite = true; 23910c946d80SToomas Soome break; 23920c946d80SToomas Soome case 'u': 2393*d7802caeSToomas Soome do_version = true; 23940c946d80SToomas Soome 2395bdecfb1eSToomas Soome update_str = strdup(optarg); 23960c946d80SToomas Soome if (update_str == NULL) { 23970c946d80SToomas Soome perror(gettext("Memory allocation failure")); 23980c946d80SToomas Soome exit(BC_ERROR); 23990c946d80SToomas Soome } 24000c946d80SToomas Soome break; 24010c946d80SToomas Soome case 'V': 2402*d7802caeSToomas Soome verbose_dump = true; 24030c946d80SToomas Soome break; 24040c946d80SToomas Soome default: 24050c946d80SToomas Soome /* fall through to process non-optional args */ 24060c946d80SToomas Soome break; 24070c946d80SToomas Soome } 24080c946d80SToomas Soome } 24090c946d80SToomas Soome 24100c946d80SToomas Soome /* check arguments */ 24110c946d80SToomas Soome check_options(progname); 24120c946d80SToomas Soome 24130c946d80SToomas Soome if (nowrite) 24140c946d80SToomas Soome (void) fprintf(stdout, gettext("Dry run requested. Nothing will" 24150c946d80SToomas Soome " be written to disk.\n")); 24160c946d80SToomas Soome 24170c946d80SToomas Soome if (do_getinfo) { 2418*d7802caeSToomas Soome ret = handle_getinfo(progname, argc - optind, argv + optind); 24190c946d80SToomas Soome } else if (do_mirror_bblk) { 2420*d7802caeSToomas Soome ret = handle_mirror(progname, argc - optind, argv + optind); 24210c946d80SToomas Soome } else { 2422*d7802caeSToomas Soome ret = handle_install(progname, argc - optind, argv + optind); 24230c946d80SToomas Soome } 2424*d7802caeSToomas Soome fini_yes(); 24250c946d80SToomas Soome return (ret); 24260c946d80SToomas Soome } 24270c946d80SToomas Soome 24280c946d80SToomas Soome #define MEANINGLESS_OPT gettext("%s specified but meaningless, ignoring\n") 24290c946d80SToomas Soome static void 24300c946d80SToomas Soome check_options(char *progname) 24310c946d80SToomas Soome { 24320c946d80SToomas Soome if (do_getinfo && do_mirror_bblk) { 24330c946d80SToomas Soome (void) fprintf(stderr, gettext("Only one of -M and -i can be " 24340c946d80SToomas Soome "specified at the same time\n")); 2435bdecfb1eSToomas Soome usage(progname, BC_ERROR); 24360c946d80SToomas Soome } 24370c946d80SToomas Soome 24380c946d80SToomas Soome if (do_mirror_bblk) { 24390c946d80SToomas Soome /* 24400c946d80SToomas Soome * -u and -F may actually reflect a user intent that is not 24410c946d80SToomas Soome * correct with this command (mirror can be interpreted 24420c946d80SToomas Soome * "similar" to install. Emit a message and continue. 24430c946d80SToomas Soome * -e and -V have no meaning, be quiet here and only report the 24440c946d80SToomas Soome * incongruence if a debug output is requested. 24450c946d80SToomas Soome */ 24460c946d80SToomas Soome if (do_version) { 24470c946d80SToomas Soome (void) fprintf(stderr, MEANINGLESS_OPT, "-u"); 2448*d7802caeSToomas Soome do_version = false; 24490c946d80SToomas Soome } 24500c946d80SToomas Soome if (force_update) { 24510c946d80SToomas Soome (void) fprintf(stderr, MEANINGLESS_OPT, "-F"); 2452*d7802caeSToomas Soome force_update = false; 24530c946d80SToomas Soome } 24540c946d80SToomas Soome if (strip || verbose_dump) { 24550c946d80SToomas Soome BOOT_DEBUG(MEANINGLESS_OPT, "-e|-V"); 2456*d7802caeSToomas Soome strip = false; 2457*d7802caeSToomas Soome verbose_dump = false; 24580c946d80SToomas Soome } 24590c946d80SToomas Soome } 24600c946d80SToomas Soome 2461*d7802caeSToomas Soome if ((strip || verbose_dump) && !do_getinfo) 2462*d7802caeSToomas Soome usage(progname, BC_ERROR); 2463*d7802caeSToomas Soome 24640c946d80SToomas Soome if (do_getinfo) { 24650c946d80SToomas Soome if (write_mbr || force_mbr || do_version || force_update) { 24660c946d80SToomas Soome BOOT_DEBUG(MEANINGLESS_OPT, "-m|-f|-u|-F"); 2467*d7802caeSToomas Soome write_mbr = force_mbr = do_version = false; 2468*d7802caeSToomas Soome force_update = false; 24690c946d80SToomas Soome } 24700c946d80SToomas Soome } 24710c946d80SToomas Soome } 2472