14c1177a4SToomas Soome /* 24c1177a4SToomas Soome * CDDL HEADER START 34c1177a4SToomas Soome * 44c1177a4SToomas Soome * The contents of this file are subject to the terms of the 54c1177a4SToomas Soome * Common Development and Distribution License (the "License"). 64c1177a4SToomas Soome * You may not use this file except in compliance with the License. 74c1177a4SToomas Soome * 84c1177a4SToomas Soome * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 94c1177a4SToomas Soome * or http://www.opensolaris.org/os/licensing. 104c1177a4SToomas Soome * See the License for the specific language governing permissions 114c1177a4SToomas Soome * and limitations under the License. 124c1177a4SToomas Soome * 134c1177a4SToomas Soome * When distributing Covered Code, include this CDDL HEADER in each 144c1177a4SToomas Soome * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 154c1177a4SToomas Soome * If applicable, add the following below this CDDL HEADER, with the 164c1177a4SToomas Soome * fields enclosed by brackets "[]" replaced with your own identifying 174c1177a4SToomas Soome * information: Portions Copyright [yyyy] [name of copyright owner] 184c1177a4SToomas Soome * 194c1177a4SToomas Soome * CDDL HEADER END 204c1177a4SToomas Soome */ 214c1177a4SToomas Soome /* 224c1177a4SToomas Soome * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 234c1177a4SToomas Soome * Copyright 2012 Nexenta Systems, Inc. All rights reserved. 24*161da084SToomas Soome * Copyright 2017 Toomas Soome <tsoome@me.com> 254c1177a4SToomas Soome */ 264c1177a4SToomas Soome 274c1177a4SToomas Soome #include <stdio.h> 284c1177a4SToomas Soome #include <errno.h> 294c1177a4SToomas Soome #include <unistd.h> 304c1177a4SToomas Soome #include <fcntl.h> 314c1177a4SToomas Soome #include <assert.h> 324c1177a4SToomas Soome #include <locale.h> 334c1177a4SToomas Soome #include <strings.h> 344c1177a4SToomas Soome #include <libfdisk.h> 354c1177a4SToomas Soome 364c1177a4SToomas Soome #include <sys/dktp/fdisk.h> 374c1177a4SToomas Soome #include <sys/dkio.h> 384c1177a4SToomas Soome #include <sys/vtoc.h> 394c1177a4SToomas Soome #include <sys/multiboot.h> 404c1177a4SToomas Soome #include <sys/types.h> 414c1177a4SToomas Soome #include <sys/stat.h> 424c1177a4SToomas Soome #include <sys/sysmacros.h> 434c1177a4SToomas Soome #include <sys/efi_partition.h> 444c1177a4SToomas Soome #include <libfstyp.h> 454c1177a4SToomas Soome #include <uuid/uuid.h> 464c1177a4SToomas Soome 474c1177a4SToomas Soome #include "installboot.h" 484c1177a4SToomas Soome #include "../../common/bblk_einfo.h" 494c1177a4SToomas Soome #include "../../common/boot_utils.h" 504c1177a4SToomas Soome #include "../../common/mboot_extra.h" 514c1177a4SToomas Soome #include "getresponse.h" 524c1177a4SToomas Soome 534c1177a4SToomas Soome #ifndef TEXT_DOMAIN 544c1177a4SToomas Soome #define TEXT_DOMAIN "SUNW_OST_OSCMD" 554c1177a4SToomas Soome #endif 564c1177a4SToomas Soome 574c1177a4SToomas Soome /* 584c1177a4SToomas Soome * BIOS bootblock installation: 594c1177a4SToomas Soome * 604c1177a4SToomas Soome * 1. MBR is first sector of the disk. If the file system on target is 614c1177a4SToomas Soome * ufs or zfs, the same MBR code is installed on first sector of the 624c1177a4SToomas Soome * partition as well; this will allow to have real MBR sector to be 634c1177a4SToomas Soome * replaced by some other boot loader and have illumos chainloaded. 644c1177a4SToomas Soome * 654c1177a4SToomas Soome * installboot will record the start LBA and size of stage2 code in MBR code. 664c1177a4SToomas Soome * On boot, the MBR code will read the stage2 code and executes it. 674c1177a4SToomas Soome * 684c1177a4SToomas Soome * 2. Stage2 location depends on file system type; 694c1177a4SToomas Soome * In case of zfs, installboot will store stage2 to zfs bootblk area, 704c1177a4SToomas Soome * which is 512k bytes from partition start and size is 3.5MB. 714c1177a4SToomas Soome * 724c1177a4SToomas Soome * In case of ufs, the stage2 location is 50 512B sectors from 734c1177a4SToomas Soome * Solaris2 MBR partition start, within boot slice, boot slice size is 744c1177a4SToomas Soome * one cylinder. 754c1177a4SToomas Soome * 764c1177a4SToomas Soome * In case of pcfs, the stage2 location is 50 512B sectors from beginning 774c1177a4SToomas Soome * of the disk, filling the space between MBR and first partition. 784c1177a4SToomas Soome * This location assumes no other bootloader and the space is one cylinder, 794c1177a4SToomas Soome * as first partition is starting from cylinder 1. 804c1177a4SToomas Soome * 814c1177a4SToomas Soome * In case of GPT partitioning and if file system is not zfs, the boot 824c1177a4SToomas Soome * support is only possible with dedicated boot partition. For GPT, 834c1177a4SToomas Soome * the current implementation is using BOOT partition, which must exist. 844c1177a4SToomas Soome * BOOT partition does only contain raw boot blocks, without any file system. 854c1177a4SToomas Soome * 864c1177a4SToomas Soome * Loader stage2 is created with embedded version, by using fake multiboot (MB) 874c1177a4SToomas Soome * header within first 32k and EINFO block is at the end of the actual 884c1177a4SToomas Soome * boot block. MB header load_addr is set to 0 and load_end_addr is set to 894c1177a4SToomas Soome * actual block end, so the EINFO size is (file size - load_end_addr). 904c1177a4SToomas Soome * installboot does also store the illumos boot partition LBA to MB space, 914c1177a4SToomas Soome * starting from bss_end_addr structure member location; stage2 will 924c1177a4SToomas Soome * detect the partition and file system based on this value. 934c1177a4SToomas Soome * 944c1177a4SToomas Soome * Stored location values in MBR/stage2 also mean the bootblocks must be 954c1177a4SToomas Soome * reinstalled in case the partition content is relocated. 964c1177a4SToomas Soome */ 974c1177a4SToomas Soome 984c1177a4SToomas Soome static boolean_t write_mbr = B_FALSE; 994c1177a4SToomas Soome static boolean_t force_mbr = B_FALSE; 1004c1177a4SToomas Soome static boolean_t force_update = B_FALSE; 1014c1177a4SToomas Soome static boolean_t do_getinfo = B_FALSE; 1024c1177a4SToomas Soome static boolean_t do_version = B_FALSE; 1034c1177a4SToomas Soome static boolean_t do_mirror_bblk = B_FALSE; 1044c1177a4SToomas Soome static boolean_t strip = B_FALSE; 1054c1177a4SToomas Soome static boolean_t verbose_dump = B_FALSE; 1064c1177a4SToomas Soome 1074c1177a4SToomas Soome /* Versioning string, if present. */ 1084c1177a4SToomas Soome static char *update_str; 1094c1177a4SToomas Soome 1104c1177a4SToomas Soome /* 1114c1177a4SToomas Soome * Temporary buffer to store the first 32K of data looking for a multiboot 1124c1177a4SToomas Soome * signature. 1134c1177a4SToomas Soome */ 1144c1177a4SToomas Soome char mboot_scan[MBOOT_SCAN_SIZE]; 1154c1177a4SToomas Soome 1164c1177a4SToomas Soome /* Function prototypes. */ 1174c1177a4SToomas Soome static void check_options(char *); 1184c1177a4SToomas Soome static int get_start_sector(ib_device_t *); 1194c1177a4SToomas Soome 120*161da084SToomas Soome static int read_stage1_from_file(char *, ib_data_t *); 121*161da084SToomas Soome static int read_bootblock_from_file(char *, ib_bootblock_t *); 122*161da084SToomas Soome static int read_bootblock_from_disk(ib_device_t *, ib_bootblock_t *, char **); 1234c1177a4SToomas Soome static void add_bootblock_einfo(ib_bootblock_t *, char *); 1244c1177a4SToomas Soome static int prepare_stage1(ib_data_t *); 1254c1177a4SToomas Soome static int prepare_bootblock(ib_data_t *, char *); 1264c1177a4SToomas Soome static int write_stage1(ib_data_t *); 1274c1177a4SToomas Soome static int write_bootblock(ib_data_t *); 1284c1177a4SToomas Soome static int init_device(ib_device_t *, char *); 1294c1177a4SToomas Soome static void cleanup_device(ib_device_t *); 1304c1177a4SToomas Soome static int commit_to_disk(ib_data_t *, char *); 1314c1177a4SToomas Soome static int handle_install(char *, char **); 1324c1177a4SToomas Soome static int handle_getinfo(char *, char **); 1334c1177a4SToomas Soome static int handle_mirror(char *, char **); 1344c1177a4SToomas Soome static boolean_t is_update_necessary(ib_data_t *, char *); 1354c1177a4SToomas Soome static int propagate_bootblock(ib_data_t *, ib_data_t *, char *); 1364c1177a4SToomas Soome static void usage(char *); 1374c1177a4SToomas Soome 1384c1177a4SToomas Soome static int 1394c1177a4SToomas Soome read_stage1_from_file(char *path, ib_data_t *dest) 1404c1177a4SToomas Soome { 1414c1177a4SToomas Soome int fd; 1424c1177a4SToomas Soome 1434c1177a4SToomas Soome assert(dest != NULL); 1444c1177a4SToomas Soome 1454c1177a4SToomas Soome /* read the stage1 file from filesystem */ 1464c1177a4SToomas Soome fd = open(path, O_RDONLY); 1474c1177a4SToomas Soome if (fd == -1 || 1484c1177a4SToomas Soome read(fd, dest->stage1, SECTOR_SIZE) != SECTOR_SIZE) { 1494c1177a4SToomas Soome (void) fprintf(stderr, gettext("cannot read stage1 file %s\n"), 1504c1177a4SToomas Soome path); 1514c1177a4SToomas Soome return (BC_ERROR); 1524c1177a4SToomas Soome } 1534c1177a4SToomas Soome (void) close(fd); 1544c1177a4SToomas Soome return (BC_SUCCESS); 1554c1177a4SToomas Soome } 1564c1177a4SToomas Soome 1574c1177a4SToomas Soome static int 158*161da084SToomas Soome read_bootblock_from_file(char *file, ib_bootblock_t *bblock) 1594c1177a4SToomas Soome { 1604c1177a4SToomas Soome struct stat sb; 1614c1177a4SToomas Soome uint32_t buf_size; 1624c1177a4SToomas Soome uint32_t mboot_off; 1634c1177a4SToomas Soome int fd = -1; 1644c1177a4SToomas Soome int retval = BC_ERROR; 1654c1177a4SToomas Soome 166*161da084SToomas Soome assert(bblock != NULL); 1674c1177a4SToomas Soome assert(file != NULL); 1684c1177a4SToomas Soome 1694c1177a4SToomas Soome fd = open(file, O_RDONLY); 1704c1177a4SToomas Soome if (fd == -1) { 1714c1177a4SToomas Soome BOOT_DEBUG("Error opening %s\n", file); 1724c1177a4SToomas Soome perror("open"); 1734c1177a4SToomas Soome goto out; 1744c1177a4SToomas Soome } 1754c1177a4SToomas Soome 1764c1177a4SToomas Soome if (fstat(fd, &sb) == -1) { 1774c1177a4SToomas Soome BOOT_DEBUG("Error getting information (stat) about %s", file); 1784c1177a4SToomas Soome perror("stat"); 1794c1177a4SToomas Soome goto outfd; 1804c1177a4SToomas Soome } 1814c1177a4SToomas Soome 1824c1177a4SToomas Soome /* loader bootblock has version built in */ 1834c1177a4SToomas Soome buf_size = sb.st_size; 1844c1177a4SToomas Soome 1854c1177a4SToomas Soome bblock->buf_size = buf_size; 1864c1177a4SToomas Soome BOOT_DEBUG("bootblock in-memory buffer size is %d\n", 1874c1177a4SToomas Soome bblock->buf_size); 1884c1177a4SToomas Soome 1894c1177a4SToomas Soome bblock->buf = malloc(buf_size); 1904c1177a4SToomas Soome if (bblock->buf == NULL) { 1914c1177a4SToomas Soome perror(gettext("Memory allocation failure")); 1924c1177a4SToomas Soome goto outbuf; 1934c1177a4SToomas Soome } 1944c1177a4SToomas Soome bblock->file = bblock->buf; 1954c1177a4SToomas Soome 1964c1177a4SToomas Soome if (read(fd, bblock->file, bblock->buf_size) != bblock->buf_size) { 1974c1177a4SToomas Soome BOOT_DEBUG("Read from %s failed\n", file); 1984c1177a4SToomas Soome perror("read"); 1994c1177a4SToomas Soome goto outfd; 2004c1177a4SToomas Soome } 2014c1177a4SToomas Soome 2024c1177a4SToomas Soome if (find_multiboot(bblock->file, MBOOT_SCAN_SIZE, &mboot_off) 2034c1177a4SToomas Soome != BC_SUCCESS) { 2044c1177a4SToomas Soome (void) fprintf(stderr, 2054c1177a4SToomas Soome gettext("Unable to find multiboot header\n")); 2064c1177a4SToomas Soome goto outfd; 2074c1177a4SToomas Soome } 2084c1177a4SToomas Soome 2094c1177a4SToomas Soome bblock->mboot = (multiboot_header_t *)(bblock->file + mboot_off); 2104c1177a4SToomas Soome bblock->mboot_off = mboot_off; 2114c1177a4SToomas Soome 2124c1177a4SToomas Soome bblock->file_size = 2134c1177a4SToomas Soome bblock->mboot->load_end_addr - bblock->mboot->load_addr; 2144c1177a4SToomas Soome BOOT_DEBUG("bootblock file size is %d\n", bblock->file_size); 2154c1177a4SToomas Soome 2164c1177a4SToomas Soome bblock->extra = bblock->buf + P2ROUNDUP(bblock->file_size, 8); 2174c1177a4SToomas Soome bblock->extra_size = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8); 2184c1177a4SToomas Soome 2194c1177a4SToomas Soome BOOT_DEBUG("mboot at %p offset %d, extra at %p size %d, buf=%p " 2204c1177a4SToomas Soome "(size=%d)\n", bblock->mboot, bblock->mboot_off, bblock->extra, 2214c1177a4SToomas Soome bblock->extra_size, bblock->buf, bblock->buf_size); 2224c1177a4SToomas Soome 2234c1177a4SToomas Soome (void) close(fd); 2244c1177a4SToomas Soome return (BC_SUCCESS); 2254c1177a4SToomas Soome 2264c1177a4SToomas Soome outbuf: 2274c1177a4SToomas Soome (void) free(bblock->buf); 2284c1177a4SToomas Soome bblock->buf = NULL; 2294c1177a4SToomas Soome outfd: 2304c1177a4SToomas Soome (void) close(fd); 2314c1177a4SToomas Soome out: 2324c1177a4SToomas Soome return (retval); 2334c1177a4SToomas Soome } 2344c1177a4SToomas Soome 2354c1177a4SToomas Soome static int 2364c1177a4SToomas Soome read_bootblock_from_disk(ib_device_t *device, ib_bootblock_t *bblock, 2374c1177a4SToomas Soome char **path) 2384c1177a4SToomas Soome { 2394c1177a4SToomas Soome int dev_fd; 2404c1177a4SToomas Soome uint32_t size, offset; 2414c1177a4SToomas Soome uint32_t buf_size; 2424c1177a4SToomas Soome uint32_t mboot_off; 2434c1177a4SToomas Soome multiboot_header_t *mboot; 2444c1177a4SToomas Soome 2454c1177a4SToomas Soome assert(device != NULL); 2464c1177a4SToomas Soome assert(bblock != NULL); 2474c1177a4SToomas Soome 2484c1177a4SToomas Soome if (device->target.fstype == IG_FS_ZFS) { 2494c1177a4SToomas Soome dev_fd = device->target.fd; 2504c1177a4SToomas Soome offset = BBLK_ZFS_BLK_OFF * SECTOR_SIZE; 2514c1177a4SToomas Soome *path = device->target.path; 2524c1177a4SToomas Soome } else { 2534c1177a4SToomas Soome dev_fd = device->stage.fd; 2544c1177a4SToomas Soome offset = device->stage.offset * SECTOR_SIZE; 2554c1177a4SToomas Soome *path = device->stage.path; 2564c1177a4SToomas Soome } 2574c1177a4SToomas Soome 2584c1177a4SToomas Soome if (read_in(dev_fd, mboot_scan, sizeof (mboot_scan), offset) 2594c1177a4SToomas Soome != BC_SUCCESS) { 2604c1177a4SToomas Soome BOOT_DEBUG("Error reading bootblock area\n"); 2614c1177a4SToomas Soome perror("read"); 2624c1177a4SToomas Soome return (BC_ERROR); 2634c1177a4SToomas Soome } 2644c1177a4SToomas Soome 2654c1177a4SToomas Soome /* No multiboot means no chance of knowing bootblock size */ 2664c1177a4SToomas Soome if (find_multiboot(mboot_scan, sizeof (mboot_scan), &mboot_off) 2674c1177a4SToomas Soome != BC_SUCCESS) { 2684c1177a4SToomas Soome BOOT_DEBUG("Unable to find multiboot header\n"); 2694c1177a4SToomas Soome return (BC_NOEXTRA); 2704c1177a4SToomas Soome } 2714c1177a4SToomas Soome mboot = (multiboot_header_t *)(mboot_scan + mboot_off); 2724c1177a4SToomas Soome 2734c1177a4SToomas Soome /* 2744c1177a4SToomas Soome * make sure mboot has sane values 2754c1177a4SToomas Soome */ 2764c1177a4SToomas Soome if (mboot->load_end_addr == 0 || 2774c1177a4SToomas Soome mboot->load_end_addr < mboot->load_addr) 2784c1177a4SToomas Soome return (BC_NOEXTRA); 2794c1177a4SToomas Soome 2804c1177a4SToomas Soome /* 2814c1177a4SToomas Soome * Currently, the amount of space reserved for extra information 2824c1177a4SToomas Soome * is "fixed". We may have to scan for the terminating extra payload 2834c1177a4SToomas Soome * in the future. 2844c1177a4SToomas Soome */ 2854c1177a4SToomas Soome size = mboot->load_end_addr - mboot->load_addr; 2864c1177a4SToomas Soome buf_size = P2ROUNDUP(size + SECTOR_SIZE, SECTOR_SIZE); 2874c1177a4SToomas Soome bblock->file_size = size; 2884c1177a4SToomas Soome 2894c1177a4SToomas Soome bblock->buf = malloc(buf_size); 2904c1177a4SToomas Soome if (bblock->buf == NULL) { 2914c1177a4SToomas Soome BOOT_DEBUG("Unable to allocate enough memory to read" 2924c1177a4SToomas Soome " the extra bootblock from the disk\n"); 2934c1177a4SToomas Soome perror(gettext("Memory allocation failure")); 2944c1177a4SToomas Soome return (BC_ERROR); 2954c1177a4SToomas Soome } 2964c1177a4SToomas Soome bblock->buf_size = buf_size; 2974c1177a4SToomas Soome 2984c1177a4SToomas Soome if (read_in(dev_fd, bblock->buf, buf_size, offset) != BC_SUCCESS) { 2994c1177a4SToomas Soome BOOT_DEBUG("Error reading the bootblock\n"); 3004c1177a4SToomas Soome (void) free(bblock->buf); 3014c1177a4SToomas Soome bblock->buf = NULL; 3024c1177a4SToomas Soome return (BC_ERROR); 3034c1177a4SToomas Soome } 3044c1177a4SToomas Soome 3054c1177a4SToomas Soome /* Update pointers. */ 3064c1177a4SToomas Soome bblock->file = bblock->buf; 3074c1177a4SToomas Soome bblock->mboot_off = mboot_off; 3084c1177a4SToomas Soome bblock->mboot = (multiboot_header_t *)(bblock->buf + bblock->mboot_off); 3094c1177a4SToomas Soome bblock->extra = bblock->buf + P2ROUNDUP(bblock->file_size, 8); 3104c1177a4SToomas Soome bblock->extra_size = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8); 3114c1177a4SToomas Soome 3124c1177a4SToomas Soome BOOT_DEBUG("mboot at %p offset %d, extra at %p size %d, buf=%p " 3134c1177a4SToomas Soome "(size=%d)\n", bblock->mboot, bblock->mboot_off, bblock->extra, 3144c1177a4SToomas Soome bblock->extra_size, bblock->buf, bblock->buf_size); 3154c1177a4SToomas Soome 3164c1177a4SToomas Soome return (BC_SUCCESS); 3174c1177a4SToomas Soome } 3184c1177a4SToomas Soome 3194c1177a4SToomas Soome static boolean_t 3204c1177a4SToomas Soome is_update_necessary(ib_data_t *data, char *updt_str) 3214c1177a4SToomas Soome { 3224c1177a4SToomas Soome bblk_einfo_t *einfo; 3234c1177a4SToomas Soome bblk_einfo_t *einfo_file; 3244c1177a4SToomas Soome bblk_hs_t bblock_hs; 3254c1177a4SToomas Soome ib_bootblock_t bblock_disk; 3264c1177a4SToomas Soome ib_bootblock_t *bblock_file = &data->bootblock; 3274c1177a4SToomas Soome ib_device_t *device = &data->device; 3284c1177a4SToomas Soome int ret; 3294c1177a4SToomas Soome char *path; 3304c1177a4SToomas Soome 3314c1177a4SToomas Soome assert(data != NULL); 3324c1177a4SToomas Soome 3334c1177a4SToomas Soome bzero(&bblock_disk, sizeof (ib_bootblock_t)); 3344c1177a4SToomas Soome 3354c1177a4SToomas Soome ret = read_bootblock_from_disk(device, &bblock_disk, &path); 3364c1177a4SToomas Soome if (ret != BC_SUCCESS) { 3374c1177a4SToomas Soome BOOT_DEBUG("Unable to read bootblock from %s\n", path); 3384c1177a4SToomas Soome return (B_TRUE); 3394c1177a4SToomas Soome } 3404c1177a4SToomas Soome 3414c1177a4SToomas Soome einfo = find_einfo(bblock_disk.extra, bblock_disk.extra_size); 3424c1177a4SToomas Soome if (einfo == NULL) { 3434c1177a4SToomas Soome BOOT_DEBUG("No extended information available on disk\n"); 3444c1177a4SToomas Soome return (B_TRUE); 3454c1177a4SToomas Soome } 3464c1177a4SToomas Soome 3474c1177a4SToomas Soome einfo_file = find_einfo(bblock_file->extra, bblock_file->extra_size); 3484c1177a4SToomas Soome if (einfo_file == NULL) { 3494c1177a4SToomas Soome /* 3504c1177a4SToomas Soome * loader bootblock is versioned. missing version means 3514c1177a4SToomas Soome * probably incompatible block. installboot can not install 3524c1177a4SToomas Soome * grub, for example. 3534c1177a4SToomas Soome */ 3544c1177a4SToomas Soome (void) fprintf(stderr, 3554c1177a4SToomas Soome gettext("ERROR: non versioned bootblock in file\n")); 3564c1177a4SToomas Soome return (B_FALSE); 3574c1177a4SToomas Soome } else { 3584c1177a4SToomas Soome if (updt_str == NULL) { 3594c1177a4SToomas Soome updt_str = einfo_get_string(einfo_file); 3604c1177a4SToomas Soome do_version = B_TRUE; 3614c1177a4SToomas Soome } 3624c1177a4SToomas Soome } 3634c1177a4SToomas Soome 3644c1177a4SToomas Soome if (!do_version || updt_str == NULL) { 3654c1177a4SToomas Soome (void) fprintf(stderr, 3664c1177a4SToomas Soome gettext("WARNING: target device %s has a " 3674c1177a4SToomas Soome "versioned bootblock that is going to be overwritten by a " 3684c1177a4SToomas Soome "non versioned one\n"), device->path); 3694c1177a4SToomas Soome return (B_TRUE); 3704c1177a4SToomas Soome } 3714c1177a4SToomas Soome 3724c1177a4SToomas Soome if (force_update) { 3734c1177a4SToomas Soome BOOT_DEBUG("Forcing update of %s bootblock\n", device->path); 3744c1177a4SToomas Soome return (B_TRUE); 3754c1177a4SToomas Soome } 3764c1177a4SToomas Soome 3774c1177a4SToomas Soome BOOT_DEBUG("Ready to check installed version vs %s\n", updt_str); 3784c1177a4SToomas Soome 3794c1177a4SToomas Soome bblock_hs.src_buf = (unsigned char *)bblock_file->file; 3804c1177a4SToomas Soome bblock_hs.src_size = bblock_file->file_size; 3814c1177a4SToomas Soome 3824c1177a4SToomas Soome return (einfo_should_update(einfo, &bblock_hs, updt_str)); 3834c1177a4SToomas Soome } 3844c1177a4SToomas Soome 3854c1177a4SToomas Soome static void 3864c1177a4SToomas Soome add_bootblock_einfo(ib_bootblock_t *bblock, char *updt_str) 3874c1177a4SToomas Soome { 3884c1177a4SToomas Soome bblk_hs_t hs; 3894c1177a4SToomas Soome uint32_t avail_space; 3904c1177a4SToomas Soome 3914c1177a4SToomas Soome assert(bblock != NULL); 3924c1177a4SToomas Soome 3934c1177a4SToomas Soome if (updt_str == NULL) { 3944c1177a4SToomas Soome BOOT_DEBUG("WARNING: no update string passed to " 3954c1177a4SToomas Soome "add_bootblock_einfo()\n"); 3964c1177a4SToomas Soome return; 3974c1177a4SToomas Soome } 3984c1177a4SToomas Soome 3994c1177a4SToomas Soome /* Fill bootblock hashing source information. */ 4004c1177a4SToomas Soome hs.src_buf = (unsigned char *)bblock->file; 4014c1177a4SToomas Soome hs.src_size = bblock->file_size; 4024c1177a4SToomas Soome /* How much space for the extended information structure? */ 4034c1177a4SToomas Soome avail_space = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8); 4044c1177a4SToomas Soome /* Place the extended information structure. */ 4054c1177a4SToomas Soome add_einfo(bblock->extra, updt_str, &hs, avail_space); 4064c1177a4SToomas Soome } 4074c1177a4SToomas Soome 4084c1177a4SToomas Soome /* 4094c1177a4SToomas Soome * set up data for case stage1 is installed as MBR 4104c1177a4SToomas Soome * set up location and size of bootblock 4114c1177a4SToomas Soome * set disk guid to provide unique information for biosdev command 4124c1177a4SToomas Soome */ 4134c1177a4SToomas Soome static int 4144c1177a4SToomas Soome prepare_stage1(ib_data_t *data) 4154c1177a4SToomas Soome { 4164c1177a4SToomas Soome ib_device_t *device; 4174c1177a4SToomas Soome 4184c1177a4SToomas Soome assert(data != NULL); 4194c1177a4SToomas Soome device = &data->device; 4204c1177a4SToomas Soome 4214c1177a4SToomas Soome /* copy BPB */ 4224c1177a4SToomas Soome bcopy(device->mbr + STAGE1_BPB_OFFSET, 4234c1177a4SToomas Soome data->stage1 + STAGE1_BPB_OFFSET, STAGE1_BPB_SIZE); 4244c1177a4SToomas Soome 4254c1177a4SToomas Soome 4264c1177a4SToomas Soome /* copy MBR, note STAGE1_SIG == BOOTSZ */ 4274c1177a4SToomas Soome bcopy(device->mbr + STAGE1_SIG, data->stage1 + STAGE1_SIG, 4284c1177a4SToomas Soome SECTOR_SIZE - STAGE1_SIG); 4294c1177a4SToomas Soome 4304c1177a4SToomas Soome /* set stage2 size */ 4314c1177a4SToomas Soome *((uint16_t *)(data->stage1 + STAGE1_STAGE2_SIZE)) = 4324c1177a4SToomas Soome (uint16_t)(data->bootblock.buf_size / SECTOR_SIZE); 4334c1177a4SToomas Soome 4344c1177a4SToomas Soome /* 4354c1177a4SToomas Soome * set stage2 location. 4364c1177a4SToomas Soome * for zfs always use zfs embedding, for ufs/pcfs use partition_start 4374c1177a4SToomas Soome * as base for stage2 location, for ufs/pcfs in MBR partition, use 4384c1177a4SToomas Soome * free space after MBR record. 4394c1177a4SToomas Soome */ 4404c1177a4SToomas Soome if (device->target.fstype == IG_FS_ZFS) 4414c1177a4SToomas Soome *((uint64_t *)(data->stage1 + STAGE1_STAGE2_LBA)) = 4424c1177a4SToomas Soome device->target.start + device->target.offset; 4434c1177a4SToomas Soome else { 4444c1177a4SToomas Soome *((uint64_t *)(data->stage1 + STAGE1_STAGE2_LBA)) = 4454c1177a4SToomas Soome device->stage.start + device->stage.offset; 4464c1177a4SToomas Soome } 4474c1177a4SToomas Soome 4484c1177a4SToomas Soome /* 4494c1177a4SToomas Soome * set disk uuid. we only need reasonable amount of uniqueness 4504c1177a4SToomas Soome * to allow biosdev to identify disk based on mbr differences. 4514c1177a4SToomas Soome */ 4524c1177a4SToomas Soome uuid_generate(data->stage1 + STAGE1_STAGE2_UUID); 4534c1177a4SToomas Soome 4544c1177a4SToomas Soome return (BC_SUCCESS); 4554c1177a4SToomas Soome } 4564c1177a4SToomas Soome 4574c1177a4SToomas Soome static int 4584c1177a4SToomas Soome prepare_bootblock(ib_data_t *data, char *updt_str) 4594c1177a4SToomas Soome { 4604c1177a4SToomas Soome ib_bootblock_t *bblock; 4614c1177a4SToomas Soome ib_device_t *device; 4624c1177a4SToomas Soome uint64_t *ptr; 4634c1177a4SToomas Soome 4644c1177a4SToomas Soome assert(data != NULL); 4654c1177a4SToomas Soome 4664c1177a4SToomas Soome bblock = &data->bootblock; 4674c1177a4SToomas Soome device = &data->device; 4684c1177a4SToomas Soome 4694c1177a4SToomas Soome ptr = (uint64_t *)(&bblock->mboot->bss_end_addr); 4704c1177a4SToomas Soome *ptr = device->target.start; 4714c1177a4SToomas Soome 4724c1177a4SToomas Soome /* 4734c1177a4SToomas Soome * the loader bootblock has built in version, if custom 4744c1177a4SToomas Soome * version was provided, update it. 4754c1177a4SToomas Soome */ 4764c1177a4SToomas Soome if (do_version) 4774c1177a4SToomas Soome add_bootblock_einfo(bblock, updt_str); 4784c1177a4SToomas Soome 4794c1177a4SToomas Soome return (BC_SUCCESS); 4804c1177a4SToomas Soome } 4814c1177a4SToomas Soome 4824c1177a4SToomas Soome static int 4834c1177a4SToomas Soome write_bootblock(ib_data_t *data) 4844c1177a4SToomas Soome { 4854c1177a4SToomas Soome ib_device_t *device = &data->device; 4864c1177a4SToomas Soome ib_bootblock_t *bblock = &data->bootblock; 4874c1177a4SToomas Soome uint64_t abs; 4884c1177a4SToomas Soome int dev_fd, ret; 4894c1177a4SToomas Soome off_t offset; 4904c1177a4SToomas Soome char *path; 4914c1177a4SToomas Soome 4924c1177a4SToomas Soome assert(data != NULL); 4934c1177a4SToomas Soome 4944c1177a4SToomas Soome /* 4954c1177a4SToomas Soome * ZFS bootblock area is 3.5MB, make sure we can fit. 4964c1177a4SToomas Soome * buf_size is size of bootblk+EINFO. 4974c1177a4SToomas Soome */ 4984c1177a4SToomas Soome if (bblock->buf_size > BBLK_ZFS_BLK_SIZE) { 4994c1177a4SToomas Soome (void) fprintf(stderr, gettext("bootblock is too large\n")); 5004c1177a4SToomas Soome return (BC_ERROR); 5014c1177a4SToomas Soome } 5024c1177a4SToomas Soome 5034c1177a4SToomas Soome if (device->target.fstype == IG_FS_ZFS) { 5044c1177a4SToomas Soome dev_fd = device->target.fd; 5054c1177a4SToomas Soome abs = device->target.start + device->target.offset; 5064c1177a4SToomas Soome offset = BBLK_ZFS_BLK_OFF * SECTOR_SIZE; 5074c1177a4SToomas Soome path = device->target.path; 5084c1177a4SToomas Soome } else { 5094c1177a4SToomas Soome dev_fd = device->stage.fd; 5104c1177a4SToomas Soome abs = device->stage.start + device->stage.offset; 5114c1177a4SToomas Soome offset = device->stage.offset * SECTOR_SIZE; 5124c1177a4SToomas Soome path = device->stage.path; 5134c1177a4SToomas Soome if (bblock->buf_size > 5144c1177a4SToomas Soome (device->stage.size - device->stage.offset) * SECTOR_SIZE) { 5154c1177a4SToomas Soome (void) fprintf(stderr, gettext("Device %s is " 5164c1177a4SToomas Soome "too small to fit the stage2\n"), path); 5174c1177a4SToomas Soome return (BC_ERROR); 5184c1177a4SToomas Soome } 5194c1177a4SToomas Soome } 5204c1177a4SToomas Soome ret = write_out(dev_fd, bblock->buf, bblock->buf_size, offset); 5214c1177a4SToomas Soome if (ret != BC_SUCCESS) { 5224c1177a4SToomas Soome BOOT_DEBUG("Error writing the ZFS bootblock " 5234c1177a4SToomas Soome "to %s at offset %d\n", path, offset); 5244c1177a4SToomas Soome return (BC_ERROR); 5254c1177a4SToomas Soome } 5264c1177a4SToomas Soome 5274c1177a4SToomas Soome (void) fprintf(stdout, gettext("bootblock written for %s," 5284c1177a4SToomas Soome " %d sectors starting at %d (abs %lld)\n"), path, 5294c1177a4SToomas Soome (bblock->buf_size / SECTOR_SIZE) + 1, offset / SECTOR_SIZE, abs); 5304c1177a4SToomas Soome 5314c1177a4SToomas Soome return (BC_SUCCESS); 5324c1177a4SToomas Soome } 5334c1177a4SToomas Soome 534ed24e3c9SToomas Soome /* 535ed24e3c9SToomas Soome * Partition boot block or volume boot record (VBR). The VBR is 536ed24e3c9SToomas Soome * stored on partition relative sector 0 and allows chainloading 537ed24e3c9SToomas Soome * to read boot program from partition. 538ed24e3c9SToomas Soome * 539ed24e3c9SToomas Soome * As the VBR will use the first sector of the partition, 540ed24e3c9SToomas Soome * this means, we need to be sure the space is not used. 541ed24e3c9SToomas Soome * We do support three partitioning chemes: 542ed24e3c9SToomas Soome * 1. GPT: zfs and ufs have reserved space for first 8KB, but 543ed24e3c9SToomas Soome * only zfs does have space for boot2. The pcfs has support 544ed24e3c9SToomas Soome * for VBR, but no space for boot2. So with GPT, to support 545ed24e3c9SToomas Soome * ufs or pcfs boot, we must have separate dedicated boot 546ed24e3c9SToomas Soome * partition and we will store VBR on it. 547ed24e3c9SToomas Soome * 2. MBR: we have almost the same situation as with GPT, except that 548ed24e3c9SToomas Soome * if the partitions start from cylinder 1, we will have space 549ed24e3c9SToomas Soome * between MBR and cylinder 0. If so, we do not require separate 550ed24e3c9SToomas Soome * boot partition. 551ed24e3c9SToomas Soome * 3. MBR+VTOC: with this combination we store VBR in sector 0 of the 552ed24e3c9SToomas Soome * solaris2 MBR partition. The slice 0 will start from cylinder 1, 553ed24e3c9SToomas Soome * and we do have space for boot2, so we do not require separate 554ed24e3c9SToomas Soome * boot partition. 555ed24e3c9SToomas Soome */ 5564c1177a4SToomas Soome static int 5574c1177a4SToomas Soome write_stage1(ib_data_t *data) 5584c1177a4SToomas Soome { 5594c1177a4SToomas Soome ib_device_t *device = &data->device; 560ed24e3c9SToomas Soome uint64_t start = 0; 5614c1177a4SToomas Soome 5624c1177a4SToomas Soome assert(data != NULL); 5634c1177a4SToomas Soome 5644c1177a4SToomas Soome /* 565ed24e3c9SToomas Soome * We have separate partition for boot programs and the stage1 566ed24e3c9SToomas Soome * location is not absolute sector 0. 567ed24e3c9SToomas Soome * We will write VBR and trigger MBR to read 1 sector from VBR. 568ed24e3c9SToomas Soome * This case does also cover MBR+VTOC case, as the solaris 2 partition 569ed24e3c9SToomas Soome * name and the root file system slice names are different. 5704c1177a4SToomas Soome */ 5714c1177a4SToomas Soome if (device->stage.start != 0 && 5724c1177a4SToomas Soome strcmp(device->target.path, device->stage.path)) { 5734c1177a4SToomas Soome /* we got separate stage area, use it */ 5744c1177a4SToomas Soome if (write_out(device->stage.fd, data->stage1, 5754c1177a4SToomas Soome sizeof (data->stage1), 0) != BC_SUCCESS) { 5764c1177a4SToomas Soome (void) fprintf(stdout, gettext("cannot write " 5774c1177a4SToomas Soome "partition boot sector\n")); 5784c1177a4SToomas Soome perror("write"); 5794c1177a4SToomas Soome return (BC_ERROR); 5804c1177a4SToomas Soome } 5814c1177a4SToomas Soome 5824c1177a4SToomas Soome (void) fprintf(stdout, gettext("stage1 written to " 5834c1177a4SToomas Soome "%s %d sector 0 (abs %d)\n"), 5844c1177a4SToomas Soome device->devtype == IG_DEV_MBR? "partition":"slice", 5854c1177a4SToomas Soome device->stage.id, device->stage.start); 586ed24e3c9SToomas Soome start = device->stage.start; 5874c1177a4SToomas Soome } 5884c1177a4SToomas Soome 5894c1177a4SToomas Soome /* 590ed24e3c9SToomas Soome * We have either GPT or MBR (without VTOC) and if the root 591ed24e3c9SToomas Soome * file system is not pcfs, we can store VBR. Also trigger 592ed24e3c9SToomas Soome * MBR to read 1 sector from VBR. 5934c1177a4SToomas Soome */ 5944c1177a4SToomas Soome if (device->devtype != IG_DEV_VTOC && 5954c1177a4SToomas Soome device->target.fstype != IG_FS_PCFS) { 5964c1177a4SToomas Soome if (write_out(device->target.fd, data->stage1, 5974c1177a4SToomas Soome sizeof (data->stage1), 0) != BC_SUCCESS) { 5984c1177a4SToomas Soome (void) fprintf(stdout, gettext("cannot write " 5994c1177a4SToomas Soome "partition boot sector\n")); 6004c1177a4SToomas Soome perror("write"); 6014c1177a4SToomas Soome return (BC_ERROR); 6024c1177a4SToomas Soome } 6034c1177a4SToomas Soome 6044c1177a4SToomas Soome (void) fprintf(stdout, gettext("stage1 written to " 6054c1177a4SToomas Soome "%s %d sector 0 (abs %d)\n"), 6064c1177a4SToomas Soome device->devtype == IG_DEV_MBR? "partition":"slice", 6074c1177a4SToomas Soome device->target.id, device->target.start); 608ed24e3c9SToomas Soome start = device->target.start; 6094c1177a4SToomas Soome } 6104c1177a4SToomas Soome 6114c1177a4SToomas Soome if (write_mbr) { 612ed24e3c9SToomas Soome /* 613ed24e3c9SToomas Soome * If we did write partition boot block, update MBR to 614ed24e3c9SToomas Soome * read partition boot block, not boot2. 615ed24e3c9SToomas Soome */ 616ed24e3c9SToomas Soome if (start != 0) { 617ed24e3c9SToomas Soome *((uint16_t *)(data->stage1 + STAGE1_STAGE2_SIZE)) = 1; 618ed24e3c9SToomas Soome *((uint64_t *)(data->stage1 + STAGE1_STAGE2_LBA)) = 619ed24e3c9SToomas Soome start; 620ed24e3c9SToomas Soome } 6214c1177a4SToomas Soome if (write_out(device->fd, data->stage1, 6224c1177a4SToomas Soome sizeof (data->stage1), 0) != BC_SUCCESS) { 6234c1177a4SToomas Soome (void) fprintf(stdout, 6244c1177a4SToomas Soome gettext("cannot write master boot sector\n")); 6254c1177a4SToomas Soome perror("write"); 6264c1177a4SToomas Soome return (BC_ERROR); 6274c1177a4SToomas Soome } 6284c1177a4SToomas Soome (void) fprintf(stdout, 6294c1177a4SToomas Soome gettext("stage1 written to master boot sector\n")); 6304c1177a4SToomas Soome } 6314c1177a4SToomas Soome 6324c1177a4SToomas Soome return (BC_SUCCESS); 6334c1177a4SToomas Soome } 6344c1177a4SToomas Soome 6354c1177a4SToomas Soome /* 6364c1177a4SToomas Soome * find partition/slice start sector. will be recorded in stage2 and used 6374c1177a4SToomas Soome * by stage2 to identify partition with boot file system. 6384c1177a4SToomas Soome */ 6394c1177a4SToomas Soome static int 6404c1177a4SToomas Soome get_start_sector(ib_device_t *device) 6414c1177a4SToomas Soome { 6424c1177a4SToomas Soome uint32_t secnum = 0, numsec = 0; 6434c1177a4SToomas Soome int i, pno, rval, log_part = 0; 6444c1177a4SToomas Soome struct mboot *mboot; 6454c1177a4SToomas Soome struct ipart *part = NULL; 6464c1177a4SToomas Soome ext_part_t *epp; 6474c1177a4SToomas Soome struct part_info dkpi; 6484c1177a4SToomas Soome struct extpart_info edkpi; 6494c1177a4SToomas Soome 6504c1177a4SToomas Soome if (device->devtype == IG_DEV_EFI) { 6514c1177a4SToomas Soome struct dk_gpt *vtoc; 6524c1177a4SToomas Soome 6534c1177a4SToomas Soome if (efi_alloc_and_read(device->fd, &vtoc) < 0) 6544c1177a4SToomas Soome return (BC_ERROR); 6554c1177a4SToomas Soome 6564c1177a4SToomas Soome if (device->stage.start == 0) { 6574c1177a4SToomas Soome /* zero size means the fstype must be zfs */ 6584c1177a4SToomas Soome assert(device->target.fstype == IG_FS_ZFS); 6594c1177a4SToomas Soome 6604c1177a4SToomas Soome device->stage.start = 6614c1177a4SToomas Soome vtoc->efi_parts[device->stage.id].p_start; 6624c1177a4SToomas Soome device->stage.size = 6634c1177a4SToomas Soome vtoc->efi_parts[device->stage.id].p_size; 6644c1177a4SToomas Soome device->stage.offset = BBLK_ZFS_BLK_OFF; 6654c1177a4SToomas Soome device->target.offset = BBLK_ZFS_BLK_OFF; 6664c1177a4SToomas Soome } 6674c1177a4SToomas Soome 6684c1177a4SToomas Soome device->target.start = 6694c1177a4SToomas Soome vtoc->efi_parts[device->target.id].p_start; 6704c1177a4SToomas Soome device->target.size = 6714c1177a4SToomas Soome vtoc->efi_parts[device->target.id].p_size; 6724c1177a4SToomas Soome 6734c1177a4SToomas Soome /* with pcfs we always write MBR */ 6744c1177a4SToomas Soome if (device->target.fstype == IG_FS_PCFS) { 6754c1177a4SToomas Soome force_mbr = 1; 6764c1177a4SToomas Soome write_mbr = 1; 6774c1177a4SToomas Soome } 6784c1177a4SToomas Soome 6794c1177a4SToomas Soome efi_free(vtoc); 6804c1177a4SToomas Soome goto found_part; 6814c1177a4SToomas Soome } 6824c1177a4SToomas Soome 6834c1177a4SToomas Soome mboot = (struct mboot *)device->mbr; 6844c1177a4SToomas Soome 6854c1177a4SToomas Soome /* For MBR we have device->stage filled already. */ 6864c1177a4SToomas Soome if (device->devtype == IG_DEV_MBR) { 6874c1177a4SToomas Soome /* MBR partition starts from 0 */ 6884c1177a4SToomas Soome pno = device->target.id - 1; 6894c1177a4SToomas Soome part = (struct ipart *)mboot->parts + pno; 6904c1177a4SToomas Soome 6914c1177a4SToomas Soome if (part->relsect == 0) { 6924c1177a4SToomas Soome (void) fprintf(stderr, gettext("Partition %d of the " 6934c1177a4SToomas Soome "disk has an incorrect offset\n"), 6944c1177a4SToomas Soome device->target.id); 6954c1177a4SToomas Soome return (BC_ERROR); 6964c1177a4SToomas Soome } 6974c1177a4SToomas Soome device->target.start = part->relsect; 6984c1177a4SToomas Soome device->target.size = part->numsect; 6994c1177a4SToomas Soome 7004c1177a4SToomas Soome /* with pcfs we always write MBR */ 7014c1177a4SToomas Soome if (device->target.fstype == IG_FS_PCFS) { 7024c1177a4SToomas Soome force_mbr = 1; 7034c1177a4SToomas Soome write_mbr = 1; 7044c1177a4SToomas Soome } 7054c1177a4SToomas Soome if (device->target.fstype == IG_FS_ZFS) 7064c1177a4SToomas Soome device->target.offset = BBLK_ZFS_BLK_OFF; 7074c1177a4SToomas Soome 7084c1177a4SToomas Soome goto found_part; 7094c1177a4SToomas Soome } 7104c1177a4SToomas Soome 7114c1177a4SToomas Soome /* 7124c1177a4SToomas Soome * Search for Solaris fdisk partition 7134c1177a4SToomas Soome * Get the solaris partition information from the device 7144c1177a4SToomas Soome * and compare the offset of S2 with offset of solaris partition 7154c1177a4SToomas Soome * from fdisk partition table. 7164c1177a4SToomas Soome */ 7174c1177a4SToomas Soome if (ioctl(device->target.fd, DKIOCEXTPARTINFO, &edkpi) < 0) { 7184c1177a4SToomas Soome if (ioctl(device->target.fd, DKIOCPARTINFO, &dkpi) < 0) { 7194c1177a4SToomas Soome (void) fprintf(stderr, gettext("cannot get the " 7204c1177a4SToomas Soome "slice information of the disk\n")); 7214c1177a4SToomas Soome return (BC_ERROR); 7224c1177a4SToomas Soome } else { 7234c1177a4SToomas Soome edkpi.p_start = dkpi.p_start; 7244c1177a4SToomas Soome edkpi.p_length = dkpi.p_length; 7254c1177a4SToomas Soome } 7264c1177a4SToomas Soome } 7274c1177a4SToomas Soome 7284c1177a4SToomas Soome device->target.start = edkpi.p_start; 7294c1177a4SToomas Soome device->target.size = edkpi.p_length; 7304c1177a4SToomas Soome if (device->target.fstype == IG_FS_ZFS) 7314c1177a4SToomas Soome device->target.offset = BBLK_ZFS_BLK_OFF; 7324c1177a4SToomas Soome 7334c1177a4SToomas Soome for (i = 0; i < FD_NUMPART; i++) { 7344c1177a4SToomas Soome part = (struct ipart *)mboot->parts + i; 7354c1177a4SToomas Soome 7364c1177a4SToomas Soome if (part->relsect == 0) { 7374c1177a4SToomas Soome (void) fprintf(stderr, gettext("Partition %d of the " 7384c1177a4SToomas Soome "disk has an incorrect offset\n"), i+1); 7394c1177a4SToomas Soome return (BC_ERROR); 7404c1177a4SToomas Soome } 7414c1177a4SToomas Soome 7424c1177a4SToomas Soome if (edkpi.p_start >= part->relsect && 7434c1177a4SToomas Soome edkpi.p_start < (part->relsect + part->numsect)) { 7444c1177a4SToomas Soome /* Found the partition */ 7454c1177a4SToomas Soome break; 7464c1177a4SToomas Soome } 7474c1177a4SToomas Soome } 7484c1177a4SToomas Soome 7494c1177a4SToomas Soome if (i == FD_NUMPART) { 7504c1177a4SToomas Soome /* No solaris fdisk partitions (primary or logical) */ 7514c1177a4SToomas Soome (void) fprintf(stderr, gettext("Solaris partition not found. " 7524c1177a4SToomas Soome "Aborting operation.\n")); 7534c1177a4SToomas Soome return (BC_ERROR); 7544c1177a4SToomas Soome } 7554c1177a4SToomas Soome 7564c1177a4SToomas Soome /* 7574c1177a4SToomas Soome * We have found a Solaris fdisk partition (primary or extended) 7584c1177a4SToomas Soome * Handle the simple case first: Solaris in a primary partition 7594c1177a4SToomas Soome */ 7604c1177a4SToomas Soome if (!fdisk_is_dos_extended(part->systid)) { 7614c1177a4SToomas Soome device->stage.start = part->relsect; 7624c1177a4SToomas Soome device->stage.size = part->numsect; 7634c1177a4SToomas Soome if (device->target.fstype == IG_FS_ZFS) 7644c1177a4SToomas Soome device->stage.offset = BBLK_ZFS_BLK_OFF; 7654c1177a4SToomas Soome else 7664c1177a4SToomas Soome device->stage.offset = BBLK_BLKLIST_OFF; 7674c1177a4SToomas Soome device->stage.id = i + 1; 7684c1177a4SToomas Soome goto found_part; 7694c1177a4SToomas Soome } 7704c1177a4SToomas Soome 7714c1177a4SToomas Soome /* 7724c1177a4SToomas Soome * Solaris in a logical partition. Find that partition in the 7734c1177a4SToomas Soome * extended part. 7744c1177a4SToomas Soome */ 7754c1177a4SToomas Soome 7764c1177a4SToomas Soome if ((rval = libfdisk_init(&epp, device->path, NULL, FDISK_READ_DISK)) 7774c1177a4SToomas Soome != FDISK_SUCCESS) { 7784c1177a4SToomas Soome switch (rval) { 7794c1177a4SToomas Soome /* 7804c1177a4SToomas Soome * The first 3 cases are not an error per-se, just that 7814c1177a4SToomas Soome * there is no Solaris logical partition 7824c1177a4SToomas Soome */ 7834c1177a4SToomas Soome case FDISK_EBADLOGDRIVE: 7844c1177a4SToomas Soome case FDISK_ENOLOGDRIVE: 7854c1177a4SToomas Soome case FDISK_EBADMAGIC: 7864c1177a4SToomas Soome (void) fprintf(stderr, gettext("Solaris " 7874c1177a4SToomas Soome "partition not found. " 7884c1177a4SToomas Soome "Aborting operation.\n")); 7894c1177a4SToomas Soome return (BC_ERROR); 7904c1177a4SToomas Soome case FDISK_ENOVGEOM: 7914c1177a4SToomas Soome (void) fprintf(stderr, gettext("Could not get " 7924c1177a4SToomas Soome "virtual geometry\n")); 7934c1177a4SToomas Soome return (BC_ERROR); 7944c1177a4SToomas Soome case FDISK_ENOPGEOM: 7954c1177a4SToomas Soome (void) fprintf(stderr, gettext("Could not get " 7964c1177a4SToomas Soome "physical geometry\n")); 7974c1177a4SToomas Soome return (BC_ERROR); 7984c1177a4SToomas Soome case FDISK_ENOLGEOM: 7994c1177a4SToomas Soome (void) fprintf(stderr, gettext("Could not get " 8004c1177a4SToomas Soome "label geometry\n")); 8014c1177a4SToomas Soome return (BC_ERROR); 8024c1177a4SToomas Soome default: 8034c1177a4SToomas Soome (void) fprintf(stderr, gettext("Failed to " 8044c1177a4SToomas Soome "initialize libfdisk.\n")); 8054c1177a4SToomas Soome return (BC_ERROR); 8064c1177a4SToomas Soome } 8074c1177a4SToomas Soome } 8084c1177a4SToomas Soome 8094c1177a4SToomas Soome rval = fdisk_get_solaris_part(epp, &pno, &secnum, &numsec); 8104c1177a4SToomas Soome libfdisk_fini(&epp); 8114c1177a4SToomas Soome if (rval != FDISK_SUCCESS) { 8124c1177a4SToomas Soome /* No solaris logical partition */ 8134c1177a4SToomas Soome (void) fprintf(stderr, gettext("Solaris partition not found. " 8144c1177a4SToomas Soome "Aborting operation.\n")); 8154c1177a4SToomas Soome return (BC_ERROR); 8164c1177a4SToomas Soome } 8174c1177a4SToomas Soome 8184c1177a4SToomas Soome device->stage.start = secnum; 8194c1177a4SToomas Soome device->stage.size = numsec; 8204c1177a4SToomas Soome device->stage.id = pno; 8214c1177a4SToomas Soome log_part = 1; 8224c1177a4SToomas Soome 8234c1177a4SToomas Soome found_part: 8244c1177a4SToomas Soome /* get confirmation for -m */ 8254c1177a4SToomas Soome if (write_mbr && !force_mbr) { 8264c1177a4SToomas Soome (void) fprintf(stdout, gettext("Updating master boot sector " 8274c1177a4SToomas Soome "destroys existing boot managers (if any).\n" 8284c1177a4SToomas Soome "continue (y/n)? ")); 8294c1177a4SToomas Soome if (!yes()) { 8304c1177a4SToomas Soome write_mbr = 0; 8314c1177a4SToomas Soome (void) fprintf(stdout, gettext("master boot sector " 8324c1177a4SToomas Soome "not updated\n")); 8334c1177a4SToomas Soome return (BC_ERROR); 8344c1177a4SToomas Soome } 8354c1177a4SToomas Soome } 8364c1177a4SToomas Soome 8374c1177a4SToomas Soome /* 8384c1177a4SToomas Soome * warn, if illumos in primary partition and loader not in MBR and 8394c1177a4SToomas Soome * partition is not active 8404c1177a4SToomas Soome */ 8414c1177a4SToomas Soome if (device->devtype != IG_DEV_EFI) { 8424c1177a4SToomas Soome if (!log_part && part->bootid != 128 && !write_mbr) { 8434c1177a4SToomas Soome (void) fprintf(stdout, gettext("Solaris fdisk " 8444c1177a4SToomas Soome "partition is inactive.\n"), device->stage.id); 8454c1177a4SToomas Soome } 8464c1177a4SToomas Soome } 8474c1177a4SToomas Soome 8484c1177a4SToomas Soome return (BC_SUCCESS); 8494c1177a4SToomas Soome } 8504c1177a4SToomas Soome 8514c1177a4SToomas Soome static int 8524c1177a4SToomas Soome open_device(char *path) 8534c1177a4SToomas Soome { 8544c1177a4SToomas Soome struct stat statbuf = {0}; 8554c1177a4SToomas Soome int fd = -1; 8564c1177a4SToomas Soome 8574c1177a4SToomas Soome if (nowrite) 8584c1177a4SToomas Soome fd = open(path, O_RDONLY); 8594c1177a4SToomas Soome else 8604c1177a4SToomas Soome fd = open(path, O_RDWR); 8614c1177a4SToomas Soome 8624c1177a4SToomas Soome if (fd == -1) { 8634c1177a4SToomas Soome BOOT_DEBUG("Unable to open %s\n", path); 8644c1177a4SToomas Soome perror("open"); 8654c1177a4SToomas Soome return (-1); 8664c1177a4SToomas Soome } 8674c1177a4SToomas Soome 8684c1177a4SToomas Soome if (fstat(fd, &statbuf) != 0) { 8694c1177a4SToomas Soome BOOT_DEBUG("Unable to stat %s\n", path); 8704c1177a4SToomas Soome perror("stat"); 8714c1177a4SToomas Soome (void) close(fd); 8724c1177a4SToomas Soome return (-1); 8734c1177a4SToomas Soome } 8744c1177a4SToomas Soome 8754c1177a4SToomas Soome if (S_ISCHR(statbuf.st_mode) == 0) { 8764c1177a4SToomas Soome (void) fprintf(stderr, gettext("%s: Not a character device\n"), 8774c1177a4SToomas Soome path); 8784c1177a4SToomas Soome (void) close(fd); 8794c1177a4SToomas Soome return (-1); 8804c1177a4SToomas Soome } 8814c1177a4SToomas Soome 8824c1177a4SToomas Soome return (fd); 8834c1177a4SToomas Soome } 8844c1177a4SToomas Soome 8854c1177a4SToomas Soome static int 8864c1177a4SToomas Soome get_boot_partition(ib_device_t *device, struct mboot *mbr) 8874c1177a4SToomas Soome { 8884c1177a4SToomas Soome struct ipart *part; 8894c1177a4SToomas Soome char *path, *ptr; 8904c1177a4SToomas Soome int i; 8914c1177a4SToomas Soome 8924c1177a4SToomas Soome part = (struct ipart *)mbr->parts; 8934c1177a4SToomas Soome for (i = 0; i < FD_NUMPART; i++) { 8944c1177a4SToomas Soome if (part[i].systid == X86BOOT) 8954c1177a4SToomas Soome break; 8964c1177a4SToomas Soome } 8974c1177a4SToomas Soome 8984c1177a4SToomas Soome /* no X86BOOT, try to use space between MBR and first partition */ 8994c1177a4SToomas Soome if (i == FD_NUMPART) { 9004c1177a4SToomas Soome device->stage.path = strdup(device->path); 9014c1177a4SToomas Soome if (device->stage.path == NULL) { 9024c1177a4SToomas Soome perror(gettext("Memory allocation failure")); 9034c1177a4SToomas Soome return (BC_ERROR); 9044c1177a4SToomas Soome } 9054c1177a4SToomas Soome device->stage.fd = dup(device->fd); 9064c1177a4SToomas Soome device->stage.id = 0; 9074c1177a4SToomas Soome device->stage.devtype = IG_DEV_MBR; 9084c1177a4SToomas Soome device->stage.fstype = IG_FS_NONE; 9094c1177a4SToomas Soome device->stage.start = 0; 9104c1177a4SToomas Soome device->stage.size = part[0].relsect; 9114c1177a4SToomas Soome device->stage.offset = BBLK_BLKLIST_OFF; 9124c1177a4SToomas Soome return (BC_SUCCESS); 9134c1177a4SToomas Soome } 9144c1177a4SToomas Soome 9154c1177a4SToomas Soome if ((path = strdup(device->path)) == NULL) { 9164c1177a4SToomas Soome perror(gettext("Memory allocation failure")); 9174c1177a4SToomas Soome return (BC_ERROR); 9184c1177a4SToomas Soome } 9194c1177a4SToomas Soome 9204c1177a4SToomas Soome ptr = strrchr(path, 'p'); 9214c1177a4SToomas Soome ptr++; 9224c1177a4SToomas Soome *ptr = '\0'; 9234c1177a4SToomas Soome (void) asprintf(&ptr, "%s%d", path, i+1); /* partitions are p1..p4 */ 9244c1177a4SToomas Soome free(path); 9254c1177a4SToomas Soome if (ptr == NULL) { 9264c1177a4SToomas Soome perror(gettext("Memory allocation failure")); 9274c1177a4SToomas Soome return (BC_ERROR); 9284c1177a4SToomas Soome } 9294c1177a4SToomas Soome device->stage.path = ptr; 9304c1177a4SToomas Soome device->stage.fd = open_device(ptr); 9314c1177a4SToomas Soome device->stage.id = i + 1; 9324c1177a4SToomas Soome device->stage.devtype = IG_DEV_MBR; 9334c1177a4SToomas Soome device->stage.fstype = IG_FS_NONE; 9344c1177a4SToomas Soome device->stage.start = part[i].relsect; 9354c1177a4SToomas Soome device->stage.size = part[i].numsect; 9364c1177a4SToomas Soome device->stage.offset = 1; /* leave sector 0 for VBR */ 9374c1177a4SToomas Soome return (BC_SUCCESS); 9384c1177a4SToomas Soome } 9394c1177a4SToomas Soome 9404c1177a4SToomas Soome static int 9414c1177a4SToomas Soome get_boot_slice(ib_device_t *device, struct dk_gpt *vtoc) 9424c1177a4SToomas Soome { 9434c1177a4SToomas Soome uint_t i; 9444c1177a4SToomas Soome char *path, *ptr; 9454c1177a4SToomas Soome 9464c1177a4SToomas Soome for (i = 0; i < vtoc->efi_nparts; i++) { 9474c1177a4SToomas Soome if (vtoc->efi_parts[i].p_tag == V_BOOT) { 9484c1177a4SToomas Soome if ((path = strdup(device->target.path)) == NULL) { 9494c1177a4SToomas Soome perror(gettext("Memory allocation failure")); 9504c1177a4SToomas Soome return (BC_ERROR); 9514c1177a4SToomas Soome } 9524c1177a4SToomas Soome ptr = strrchr(path, 's'); 9534c1177a4SToomas Soome ptr++; 9544c1177a4SToomas Soome *ptr = '\0'; 9554c1177a4SToomas Soome (void) asprintf(&ptr, "%s%d", path, i); 9564c1177a4SToomas Soome free(path); 9574c1177a4SToomas Soome if (ptr == NULL) { 9584c1177a4SToomas Soome perror(gettext("Memory allocation failure")); 9594c1177a4SToomas Soome return (BC_ERROR); 9604c1177a4SToomas Soome } 9614c1177a4SToomas Soome device->stage.path = ptr; 9624c1177a4SToomas Soome device->stage.fd = open_device(ptr); 9634c1177a4SToomas Soome device->stage.id = i; 9644c1177a4SToomas Soome device->stage.devtype = IG_DEV_EFI; 9654c1177a4SToomas Soome device->stage.fstype = IG_FS_NONE; 9664c1177a4SToomas Soome device->stage.start = vtoc->efi_parts[i].p_start; 9674c1177a4SToomas Soome device->stage.size = vtoc->efi_parts[i].p_size; 9684c1177a4SToomas Soome device->stage.offset = 1; /* leave sector 0 for VBR */ 9694c1177a4SToomas Soome return (BC_SUCCESS); 9704c1177a4SToomas Soome } 9714c1177a4SToomas Soome } 9724c1177a4SToomas Soome return (BC_SUCCESS); 9734c1177a4SToomas Soome } 9744c1177a4SToomas Soome 9754c1177a4SToomas Soome static int 9764c1177a4SToomas Soome init_device(ib_device_t *device, char *path) 9774c1177a4SToomas Soome { 9784c1177a4SToomas Soome struct dk_gpt *vtoc; 9794c1177a4SToomas Soome fstyp_handle_t fhdl; 9804c1177a4SToomas Soome const char *fident; 9814c1177a4SToomas Soome char *p; 9824c1177a4SToomas Soome int pathlen = strlen(path); 9834c1177a4SToomas Soome int ret; 9844c1177a4SToomas Soome 9854c1177a4SToomas Soome bzero(device, sizeof (*device)); 9864c1177a4SToomas Soome device->fd = -1; /* whole disk fd */ 9874c1177a4SToomas Soome device->stage.fd = -1; /* bootblock partition fd */ 9884c1177a4SToomas Soome device->target.fd = -1; /* target fs partition fd */ 9894c1177a4SToomas Soome 9904c1177a4SToomas Soome /* basic check, whole disk is not allowed */ 9914c1177a4SToomas Soome if ((p = strrchr(path, '/')) == NULL) 9924c1177a4SToomas Soome p = path; 9934c1177a4SToomas Soome if ((strrchr(p, 'p') == NULL && strrchr(p, 's') == NULL) || 9944c1177a4SToomas Soome (path[pathlen-2] == 'p' && path[pathlen-1] == '0')) { 9954c1177a4SToomas Soome (void) fprintf(stderr, gettext("installing loader to " 9964c1177a4SToomas Soome "whole disk device is not supported\n")); 9974c1177a4SToomas Soome } 9984c1177a4SToomas Soome 9994c1177a4SToomas Soome device->target.path = strdup(path); 10004c1177a4SToomas Soome if (device->target.path == NULL) { 10014c1177a4SToomas Soome perror(gettext("Memory allocation failure")); 10024c1177a4SToomas Soome return (BC_ERROR); 10034c1177a4SToomas Soome } 10044c1177a4SToomas Soome device->path = strdup(path); 10054c1177a4SToomas Soome if (device->path == NULL) { 10064c1177a4SToomas Soome perror(gettext("Memory allocation failure")); 10074c1177a4SToomas Soome return (BC_ERROR); 10084c1177a4SToomas Soome } 10094c1177a4SToomas Soome 10104c1177a4SToomas Soome /* change device name to p0 */ 10114c1177a4SToomas Soome device->path[pathlen - 2] = 'p'; 10124c1177a4SToomas Soome device->path[pathlen - 1] = '0'; 10134c1177a4SToomas Soome 10144c1177a4SToomas Soome if (strstr(device->target.path, "diskette")) { 10154c1177a4SToomas Soome (void) fprintf(stderr, gettext("installing loader to a floppy " 10164c1177a4SToomas Soome "disk is not supported\n")); 10174c1177a4SToomas Soome return (BC_ERROR); 10184c1177a4SToomas Soome } 10194c1177a4SToomas Soome 10204c1177a4SToomas Soome /* Detect if the target device is a pcfs partition. */ 10214c1177a4SToomas Soome if (strstr(device->target.path, "p0:boot")) { 10224c1177a4SToomas Soome (void) fprintf(stderr, gettext("installing loader to x86 boot " 10234c1177a4SToomas Soome "partition is not supported\n")); 10244c1177a4SToomas Soome return (BC_ERROR); 10254c1177a4SToomas Soome } 10264c1177a4SToomas Soome 10274c1177a4SToomas Soome if ((device->fd = open_device(device->path)) == -1) 10284c1177a4SToomas Soome return (BC_ERROR); 10294c1177a4SToomas Soome 10304c1177a4SToomas Soome /* read in the device boot sector. */ 10314c1177a4SToomas Soome if (read(device->fd, device->mbr, SECTOR_SIZE) != SECTOR_SIZE) { 10324c1177a4SToomas Soome (void) fprintf(stderr, gettext("Error reading boot sector\n")); 10334c1177a4SToomas Soome perror("read"); 10344c1177a4SToomas Soome return (BC_ERROR); 10354c1177a4SToomas Soome } 10364c1177a4SToomas Soome 10374c1177a4SToomas Soome device->devtype = IG_DEV_VTOC; 10384c1177a4SToomas Soome if (efi_alloc_and_read(device->fd, &vtoc) >= 0) { 10394c1177a4SToomas Soome ret = get_boot_slice(device, vtoc); 10404c1177a4SToomas Soome device->devtype = IG_DEV_EFI; 10414c1177a4SToomas Soome efi_free(vtoc); 10424c1177a4SToomas Soome if (ret == BC_ERROR) 10434c1177a4SToomas Soome return (BC_ERROR); 10444c1177a4SToomas Soome } else if (device->target.path[pathlen - 2] == 'p') { 10454c1177a4SToomas Soome device->devtype = IG_DEV_MBR; 10464c1177a4SToomas Soome ret = get_boot_partition(device, (struct mboot *)device->mbr); 10474c1177a4SToomas Soome if (ret == BC_ERROR) 10484c1177a4SToomas Soome return (BC_ERROR); 10494c1177a4SToomas Soome } else if (device->target.path[pathlen - 1] == '2') { 10504c1177a4SToomas Soome /* 10514c1177a4SToomas Soome * NOTE: we could relax there and allow zfs boot on 10524c1177a4SToomas Soome * slice 2 for instance, but lets keep traditional limits. 10534c1177a4SToomas Soome */ 10544c1177a4SToomas Soome (void) fprintf(stderr, 10554c1177a4SToomas Soome gettext("raw device must be a root slice (not s2)\n")); 10564c1177a4SToomas Soome return (BC_ERROR); 10574c1177a4SToomas Soome } 10584c1177a4SToomas Soome 10594c1177a4SToomas Soome /* fill stage partition for case there is no boot partition */ 10604c1177a4SToomas Soome if (device->stage.path == NULL) { 10614c1177a4SToomas Soome if ((device->stage.path = strdup(path)) == NULL) { 10624c1177a4SToomas Soome perror(gettext("Memory allocation failure")); 10634c1177a4SToomas Soome return (BC_ERROR); 10644c1177a4SToomas Soome } 10654c1177a4SToomas Soome if (device->devtype == IG_DEV_VTOC) { 10664c1177a4SToomas Soome /* use slice 2 */ 10674c1177a4SToomas Soome device->stage.path[pathlen - 2] = 's'; 10684c1177a4SToomas Soome device->stage.path[pathlen - 1] = '2'; 10694c1177a4SToomas Soome device->stage.id = 2; 10704c1177a4SToomas Soome } else { 10714c1177a4SToomas Soome p = strrchr(device->stage.path, 'p'); 10724c1177a4SToomas Soome if (p == NULL) 10734c1177a4SToomas Soome p = strrchr(device->stage.path, 's'); 10744c1177a4SToomas Soome device->stage.id = atoi(++p); 10754c1177a4SToomas Soome } 10764c1177a4SToomas Soome device->stage.devtype = device->devtype; 10774c1177a4SToomas Soome device->stage.fd = open_device(device->stage.path); 10784c1177a4SToomas Soome } 10794c1177a4SToomas Soome 10804c1177a4SToomas Soome p = strrchr(device->target.path, 'p'); 10814c1177a4SToomas Soome if (p == NULL) 10824c1177a4SToomas Soome p = strrchr(device->target.path, 's'); 10834c1177a4SToomas Soome device->target.id = atoi(++p); 10844c1177a4SToomas Soome 10854c1177a4SToomas Soome if (strcmp(device->stage.path, device->target.path) == 0) 10864c1177a4SToomas Soome device->target.fd = dup(device->stage.fd); 10874c1177a4SToomas Soome else 10884c1177a4SToomas Soome device->target.fd = open_device(device->target.path); 10894c1177a4SToomas Soome 10904c1177a4SToomas Soome if (fstyp_init(device->target.fd, 0, NULL, &fhdl) != 0) 10914c1177a4SToomas Soome return (BC_ERROR); 10924c1177a4SToomas Soome 10934c1177a4SToomas Soome if (fstyp_ident(fhdl, NULL, &fident) != 0) { 10944c1177a4SToomas Soome fstyp_fini(fhdl); 10954c1177a4SToomas Soome (void) fprintf(stderr, gettext("Failed to detect file " 10964c1177a4SToomas Soome "system type\n")); 10974c1177a4SToomas Soome return (BC_ERROR); 10984c1177a4SToomas Soome } 10994c1177a4SToomas Soome 11004c1177a4SToomas Soome /* at this moment non-boot partition has no size set, use this fact */ 11014c1177a4SToomas Soome if (device->devtype == IG_DEV_EFI && strcmp(fident, "zfs") && 11024c1177a4SToomas Soome device->stage.size == 0) { 11034c1177a4SToomas Soome fstyp_fini(fhdl); 11044c1177a4SToomas Soome (void) fprintf(stderr, gettext("Booting %s of EFI labeled " 11054c1177a4SToomas Soome "disks requires the boot partition.\n"), fident); 11064c1177a4SToomas Soome return (BC_ERROR); 11074c1177a4SToomas Soome } 11084c1177a4SToomas Soome if (strcmp(fident, "zfs") == 0) 11094c1177a4SToomas Soome device->target.fstype = IG_FS_ZFS; 11104c1177a4SToomas Soome else if (strcmp(fident, "ufs") == 0) { 11114c1177a4SToomas Soome device->target.fstype = IG_FS_UFS; 11124c1177a4SToomas Soome } else if (strcmp(fident, "pcfs") == 0) { 11134c1177a4SToomas Soome device->target.fstype = IG_FS_PCFS; 11144c1177a4SToomas Soome } else { 11154c1177a4SToomas Soome (void) fprintf(stderr, gettext("File system %s is not " 11164c1177a4SToomas Soome "supported by loader\n"), fident); 11174c1177a4SToomas Soome fstyp_fini(fhdl); 11184c1177a4SToomas Soome return (BC_ERROR); 11194c1177a4SToomas Soome } 11204c1177a4SToomas Soome fstyp_fini(fhdl); 11214c1177a4SToomas Soome 11224c1177a4SToomas Soome /* check for boot partition content */ 11234c1177a4SToomas Soome if (device->stage.size) { 11244c1177a4SToomas Soome if (fstyp_init(device->stage.fd, 0, NULL, &fhdl) != 0) 11254c1177a4SToomas Soome return (BC_ERROR); 11264c1177a4SToomas Soome 11274c1177a4SToomas Soome if (fstyp_ident(fhdl, NULL, &fident) == 0) { 11284c1177a4SToomas Soome (void) fprintf(stderr, gettext("Unexpected %s file " 11294c1177a4SToomas Soome "system on boot partition\n"), fident); 11304c1177a4SToomas Soome fstyp_fini(fhdl); 11314c1177a4SToomas Soome return (BC_ERROR); 11324c1177a4SToomas Soome } 11334c1177a4SToomas Soome fstyp_fini(fhdl); 11344c1177a4SToomas Soome } 11354c1177a4SToomas Soome return (get_start_sector(device)); 11364c1177a4SToomas Soome } 11374c1177a4SToomas Soome 11384c1177a4SToomas Soome static void 11394c1177a4SToomas Soome cleanup_device(ib_device_t *device) 11404c1177a4SToomas Soome { 11414c1177a4SToomas Soome if (device->path) 11424c1177a4SToomas Soome free(device->path); 11434c1177a4SToomas Soome if (device->stage.path) 11444c1177a4SToomas Soome free(device->stage.path); 11454c1177a4SToomas Soome if (device->target.path) 11464c1177a4SToomas Soome free(device->target.path); 11474c1177a4SToomas Soome 11484c1177a4SToomas Soome if (device->fd != -1) 11494c1177a4SToomas Soome (void) close(device->fd); 11504c1177a4SToomas Soome if (device->stage.fd != -1) 11514c1177a4SToomas Soome (void) close(device->stage.fd); 11524c1177a4SToomas Soome if (device->target.fd != -1) 11534c1177a4SToomas Soome (void) close(device->target.fd); 11544c1177a4SToomas Soome bzero(device, sizeof (*device)); 11554c1177a4SToomas Soome } 11564c1177a4SToomas Soome 11574c1177a4SToomas Soome static void 11584c1177a4SToomas Soome cleanup_bootblock(ib_bootblock_t *bblock) 11594c1177a4SToomas Soome { 11604c1177a4SToomas Soome free(bblock->buf); 11614c1177a4SToomas Soome bzero(bblock, sizeof (ib_bootblock_t)); 11624c1177a4SToomas Soome } 11634c1177a4SToomas Soome 11644c1177a4SToomas Soome /* 11654c1177a4SToomas Soome * Propagate the bootblock on the source disk to the destination disk and 11664c1177a4SToomas Soome * version it with 'updt_str' in the process. Since we cannot trust any data 11674c1177a4SToomas Soome * on the attaching disk, we do not perform any specific check on a potential 11684c1177a4SToomas Soome * target extended information structure and we just blindly update. 11694c1177a4SToomas Soome */ 11704c1177a4SToomas Soome static int 11714c1177a4SToomas Soome propagate_bootblock(ib_data_t *src, ib_data_t *dest, char *updt_str) 11724c1177a4SToomas Soome { 11734c1177a4SToomas Soome ib_bootblock_t *src_bblock = &src->bootblock; 11744c1177a4SToomas Soome ib_bootblock_t *dest_bblock = &dest->bootblock; 11754c1177a4SToomas Soome 11764c1177a4SToomas Soome assert(src != NULL); 11774c1177a4SToomas Soome assert(dest != NULL); 11784c1177a4SToomas Soome 11794c1177a4SToomas Soome /* read the stage1 file from source disk */ 11804c1177a4SToomas Soome if (read(src->device.fd, dest->stage1, SECTOR_SIZE) != SECTOR_SIZE) { 11814c1177a4SToomas Soome (void) fprintf(stderr, gettext("cannot read stage1 from %s\n"), 11824c1177a4SToomas Soome src->device.path); 11834c1177a4SToomas Soome return (BC_ERROR); 11844c1177a4SToomas Soome } 11854c1177a4SToomas Soome 11864c1177a4SToomas Soome cleanup_bootblock(dest_bblock); 11874c1177a4SToomas Soome 11884c1177a4SToomas Soome dest_bblock->buf_size = src_bblock->buf_size; 11894c1177a4SToomas Soome dest_bblock->buf = malloc(dest_bblock->buf_size); 11904c1177a4SToomas Soome if (dest_bblock->buf == NULL) { 11914c1177a4SToomas Soome perror(gettext("Memory Allocation Failure")); 11924c1177a4SToomas Soome return (BC_ERROR); 11934c1177a4SToomas Soome } 11944c1177a4SToomas Soome dest_bblock->file = dest_bblock->buf; 11954c1177a4SToomas Soome dest_bblock->file_size = src_bblock->file_size; 11964c1177a4SToomas Soome (void) memcpy(dest_bblock->buf, src_bblock->buf, 11974c1177a4SToomas Soome dest_bblock->buf_size); 11984c1177a4SToomas Soome 11994c1177a4SToomas Soome dest_bblock->mboot = (multiboot_header_t *)(dest_bblock->file + 12004c1177a4SToomas Soome src_bblock->mboot_off); 12014c1177a4SToomas Soome dest_bblock->mboot_off = src_bblock->mboot_off; 12024c1177a4SToomas Soome dest_bblock->extra = (char *)dest_bblock->file + 12034c1177a4SToomas Soome P2ROUNDUP(dest_bblock->file_size, 8); 12044c1177a4SToomas Soome dest_bblock->extra_size = src_bblock->extra_size; 12054c1177a4SToomas Soome 12064c1177a4SToomas Soome (void) fprintf(stdout, gettext("Propagating %s bootblock to %s\n"), 12074c1177a4SToomas Soome src->device.path, dest->device.path); 12084c1177a4SToomas Soome 12094c1177a4SToomas Soome return (commit_to_disk(dest, updt_str)); 12104c1177a4SToomas Soome } 12114c1177a4SToomas Soome 12124c1177a4SToomas Soome static int 12134c1177a4SToomas Soome commit_to_disk(ib_data_t *data, char *update_str) 12144c1177a4SToomas Soome { 12154c1177a4SToomas Soome assert(data != NULL); 12164c1177a4SToomas Soome 12174c1177a4SToomas Soome if (prepare_bootblock(data, update_str) != BC_SUCCESS) { 12184c1177a4SToomas Soome (void) fprintf(stderr, gettext("Error updating the bootblock " 12194c1177a4SToomas Soome "image\n")); 12204c1177a4SToomas Soome return (BC_ERROR); 12214c1177a4SToomas Soome } 12224c1177a4SToomas Soome 12234c1177a4SToomas Soome if (prepare_stage1(data) != BC_SUCCESS) { 12244c1177a4SToomas Soome (void) fprintf(stderr, gettext("Error updating the stage1 " 12254c1177a4SToomas Soome "image\n")); 12264c1177a4SToomas Soome return (BC_ERROR); 12274c1177a4SToomas Soome } 12284c1177a4SToomas Soome 12294c1177a4SToomas Soome if (write_bootblock(data) != BC_SUCCESS) { 12304c1177a4SToomas Soome (void) fprintf(stderr, gettext("Error writing bootblock to " 12314c1177a4SToomas Soome "disk\n")); 12324c1177a4SToomas Soome return (BC_ERROR); 12334c1177a4SToomas Soome } 12344c1177a4SToomas Soome 12354c1177a4SToomas Soome return (write_stage1(data)); 12364c1177a4SToomas Soome } 12374c1177a4SToomas Soome 12384c1177a4SToomas Soome /* 12394c1177a4SToomas Soome * Install a new bootblock on the given device. handle_install() expects argv 12404c1177a4SToomas Soome * to contain 3 parameters (the target device path and the path to the 12414c1177a4SToomas Soome * bootblock. 12424c1177a4SToomas Soome * 12434c1177a4SToomas Soome * Returns: BC_SUCCESS - if the installation is successful 12444c1177a4SToomas Soome * BC_ERROR - if the installation failed 12454c1177a4SToomas Soome * BC_NOUPDT - if no installation was performed because the 12464c1177a4SToomas Soome * version currently installed is more recent than the 12474c1177a4SToomas Soome * supplied one. 12484c1177a4SToomas Soome * 12494c1177a4SToomas Soome */ 12504c1177a4SToomas Soome static int 12514c1177a4SToomas Soome handle_install(char *progname, char **argv) 12524c1177a4SToomas Soome { 12534c1177a4SToomas Soome ib_data_t install_data; 1254*161da084SToomas Soome ib_bootblock_t *bblock = &install_data.bootblock; 12554c1177a4SToomas Soome char *stage1 = NULL; 12564c1177a4SToomas Soome char *bootblock = NULL; 12574c1177a4SToomas Soome char *device_path = NULL; 12584c1177a4SToomas Soome int ret = BC_ERROR; 12594c1177a4SToomas Soome 12604c1177a4SToomas Soome stage1 = strdup(argv[0]); 12614c1177a4SToomas Soome bootblock = strdup(argv[1]); 12624c1177a4SToomas Soome device_path = strdup(argv[2]); 12634c1177a4SToomas Soome 12644c1177a4SToomas Soome if (!device_path || !bootblock || !stage1) { 12654c1177a4SToomas Soome (void) fprintf(stderr, gettext("Missing parameter")); 12664c1177a4SToomas Soome usage(progname); 12674c1177a4SToomas Soome goto out; 12684c1177a4SToomas Soome } 12694c1177a4SToomas Soome 12704c1177a4SToomas Soome BOOT_DEBUG("device path: %s, stage1 path: %s bootblock path: %s\n", 12714c1177a4SToomas Soome device_path, stage1, bootblock); 12724c1177a4SToomas Soome bzero(&install_data, sizeof (ib_data_t)); 12734c1177a4SToomas Soome 12744c1177a4SToomas Soome if (init_device(&install_data.device, device_path) != BC_SUCCESS) { 12754c1177a4SToomas Soome (void) fprintf(stderr, gettext("Unable to open device %s\n"), 12764c1177a4SToomas Soome device_path); 12774c1177a4SToomas Soome goto out; 12784c1177a4SToomas Soome } 12794c1177a4SToomas Soome 12804c1177a4SToomas Soome if (read_stage1_from_file(stage1, &install_data) != BC_SUCCESS) { 12814c1177a4SToomas Soome (void) fprintf(stderr, gettext("Error opening %s\n"), stage1); 12824c1177a4SToomas Soome goto out_dev; 12834c1177a4SToomas Soome } 12844c1177a4SToomas Soome 1285*161da084SToomas Soome if (read_bootblock_from_file(bootblock, bblock) != BC_SUCCESS) { 12864c1177a4SToomas Soome (void) fprintf(stderr, gettext("Error reading %s\n"), 12874c1177a4SToomas Soome bootblock); 12884c1177a4SToomas Soome goto out_dev; 12894c1177a4SToomas Soome } 12904c1177a4SToomas Soome 12914c1177a4SToomas Soome /* 12924c1177a4SToomas Soome * is_update_necessary() will take care of checking if versioning and/or 12934c1177a4SToomas Soome * forcing the update have been specified. It will also emit a warning 12944c1177a4SToomas Soome * if a non-versioned update is attempted over a versioned bootblock. 12954c1177a4SToomas Soome */ 12964c1177a4SToomas Soome if (!is_update_necessary(&install_data, update_str)) { 12974c1177a4SToomas Soome (void) fprintf(stderr, gettext("bootblock version installed " 12984c1177a4SToomas Soome "on %s is more recent or identical\n" 12994c1177a4SToomas Soome "Use -F to override or install without the -u option\n"), 13004c1177a4SToomas Soome device_path); 13014c1177a4SToomas Soome ret = BC_NOUPDT; 13024c1177a4SToomas Soome goto out_dev; 13034c1177a4SToomas Soome } 13044c1177a4SToomas Soome 13054c1177a4SToomas Soome BOOT_DEBUG("Ready to commit to disk\n"); 13064c1177a4SToomas Soome ret = commit_to_disk(&install_data, update_str); 13074c1177a4SToomas Soome 13084c1177a4SToomas Soome out_dev: 13094c1177a4SToomas Soome cleanup_device(&install_data.device); 13104c1177a4SToomas Soome out: 13114c1177a4SToomas Soome free(stage1); 13124c1177a4SToomas Soome free(bootblock); 13134c1177a4SToomas Soome free(device_path); 13144c1177a4SToomas Soome return (ret); 13154c1177a4SToomas Soome } 13164c1177a4SToomas Soome 13174c1177a4SToomas Soome /* 13184c1177a4SToomas Soome * Retrieves from a device the extended information (einfo) associated to the 1319*161da084SToomas Soome * file or installed stage2. 1320*161da084SToomas Soome * Expects one parameter, the device path, in the form: /dev/rdsk/c?[t?]d?s0 1321*161da084SToomas Soome * or file name. 13224c1177a4SToomas Soome * Returns: 13234c1177a4SToomas Soome * - BC_SUCCESS (and prints out einfo contents depending on 'flags') 13244c1177a4SToomas Soome * - BC_ERROR (on error) 13254c1177a4SToomas Soome * - BC_NOEINFO (no extended information available) 13264c1177a4SToomas Soome */ 13274c1177a4SToomas Soome static int 13284c1177a4SToomas Soome handle_getinfo(char *progname, char **argv) 13294c1177a4SToomas Soome { 1330*161da084SToomas Soome struct stat sb; 1331*161da084SToomas Soome ib_bootblock_t bblock; 1332*161da084SToomas Soome ib_device_t device; 13334c1177a4SToomas Soome bblk_einfo_t *einfo; 13344c1177a4SToomas Soome uint8_t flags = 0; 13354c1177a4SToomas Soome char *device_path, *path; 13364c1177a4SToomas Soome int retval = BC_ERROR; 13374c1177a4SToomas Soome int ret; 13384c1177a4SToomas Soome 13394c1177a4SToomas Soome device_path = strdup(argv[0]); 13404c1177a4SToomas Soome if (!device_path) { 13414c1177a4SToomas Soome (void) fprintf(stderr, gettext("Missing parameter")); 13424c1177a4SToomas Soome usage(progname); 13434c1177a4SToomas Soome goto out; 13444c1177a4SToomas Soome } 13454c1177a4SToomas Soome 1346*161da084SToomas Soome if (stat(device_path, &sb) == -1) { 1347*161da084SToomas Soome perror("stat"); 1348*161da084SToomas Soome goto out; 13494c1177a4SToomas Soome } 13504c1177a4SToomas Soome 1351*161da084SToomas Soome bzero(&bblock, sizeof (bblock)); 1352*161da084SToomas Soome bzero(&device, sizeof (device)); 1353*161da084SToomas Soome BOOT_DEBUG("device path: %s\n", device_path); 1354*161da084SToomas Soome 1355*161da084SToomas Soome if (S_ISREG(sb.st_mode) != 0) { 1356*161da084SToomas Soome path = device_path; 1357*161da084SToomas Soome ret = read_bootblock_from_file(device_path, &bblock); 1358*161da084SToomas Soome } else { 1359*161da084SToomas Soome if (init_device(&device, device_path) != BC_SUCCESS) { 1360*161da084SToomas Soome (void) fprintf(stderr, gettext("Unable to gather " 1361*161da084SToomas Soome "device information from %s\n"), device_path); 1362*161da084SToomas Soome goto out_dev; 1363*161da084SToomas Soome } 1364*161da084SToomas Soome ret = read_bootblock_from_disk(&device, &bblock, &path); 1365*161da084SToomas Soome } 1366*161da084SToomas Soome 13674c1177a4SToomas Soome if (ret == BC_ERROR) { 13684c1177a4SToomas Soome (void) fprintf(stderr, gettext("Error reading bootblock from " 13694c1177a4SToomas Soome "%s\n"), path); 13704c1177a4SToomas Soome goto out_dev; 13714c1177a4SToomas Soome } 13724c1177a4SToomas Soome 13734c1177a4SToomas Soome if (ret == BC_NOEXTRA) { 13744c1177a4SToomas Soome BOOT_DEBUG("No multiboot header found on %s, unable " 13754c1177a4SToomas Soome "to locate extra information area (old/non versioned " 13764c1177a4SToomas Soome "bootblock?) \n", device_path); 13774c1177a4SToomas Soome (void) fprintf(stderr, gettext("No extended information " 13784c1177a4SToomas Soome "found\n")); 13794c1177a4SToomas Soome retval = BC_NOEINFO; 13804c1177a4SToomas Soome goto out_dev; 13814c1177a4SToomas Soome } 13824c1177a4SToomas Soome 1383*161da084SToomas Soome einfo = find_einfo(bblock.extra, bblock.extra_size); 13844c1177a4SToomas Soome if (einfo == NULL) { 13854c1177a4SToomas Soome retval = BC_NOEINFO; 13864c1177a4SToomas Soome (void) fprintf(stderr, gettext("No extended information " 13874c1177a4SToomas Soome "found\n")); 13884c1177a4SToomas Soome goto out_dev; 13894c1177a4SToomas Soome } 13904c1177a4SToomas Soome 13914c1177a4SToomas Soome /* Print the extended information. */ 13924c1177a4SToomas Soome if (strip) 13934c1177a4SToomas Soome flags |= EINFO_EASY_PARSE; 13944c1177a4SToomas Soome if (verbose_dump) 13954c1177a4SToomas Soome flags |= EINFO_PRINT_HEADER; 13964c1177a4SToomas Soome 1397*161da084SToomas Soome print_einfo(flags, einfo, bblock.extra_size); 13984c1177a4SToomas Soome retval = BC_SUCCESS; 13994c1177a4SToomas Soome 14004c1177a4SToomas Soome out_dev: 1401*161da084SToomas Soome if (S_ISREG(sb.st_mode) == 0) 1402*161da084SToomas Soome cleanup_device(&device); 14034c1177a4SToomas Soome out: 14044c1177a4SToomas Soome free(device_path); 14054c1177a4SToomas Soome return (retval); 14064c1177a4SToomas Soome } 14074c1177a4SToomas Soome 14084c1177a4SToomas Soome /* 14094c1177a4SToomas Soome * Attempt to mirror (propagate) the current bootblock over the attaching disk. 14104c1177a4SToomas Soome * 14114c1177a4SToomas Soome * Returns: 14124c1177a4SToomas Soome * - BC_SUCCESS (a successful propagation happened) 14134c1177a4SToomas Soome * - BC_ERROR (an error occurred) 14144c1177a4SToomas Soome * - BC_NOEXTRA (it is not possible to dump the current bootblock since 14154c1177a4SToomas Soome * there is no multiboot information) 14164c1177a4SToomas Soome */ 14174c1177a4SToomas Soome static int 14184c1177a4SToomas Soome handle_mirror(char *progname, char **argv) 14194c1177a4SToomas Soome { 14204c1177a4SToomas Soome ib_data_t curr_data; 14214c1177a4SToomas Soome ib_data_t attach_data; 14224c1177a4SToomas Soome ib_device_t *curr_device = &curr_data.device; 14234c1177a4SToomas Soome ib_device_t *attach_device = &attach_data.device; 14244c1177a4SToomas Soome ib_bootblock_t *bblock_curr = &curr_data.bootblock; 14254c1177a4SToomas Soome ib_bootblock_t *bblock_attach = &attach_data.bootblock; 14264c1177a4SToomas Soome bblk_einfo_t *einfo_curr = NULL; 14274c1177a4SToomas Soome char *curr_device_path; 14284c1177a4SToomas Soome char *attach_device_path; 14294c1177a4SToomas Soome char *updt_str = NULL; 14304c1177a4SToomas Soome char *path; 14314c1177a4SToomas Soome int retval = BC_ERROR; 14324c1177a4SToomas Soome int ret; 14334c1177a4SToomas Soome 14344c1177a4SToomas Soome curr_device_path = strdup(argv[0]); 14354c1177a4SToomas Soome attach_device_path = strdup(argv[1]); 14364c1177a4SToomas Soome 14374c1177a4SToomas Soome if (!curr_device_path || !attach_device_path) { 14384c1177a4SToomas Soome (void) fprintf(stderr, gettext("Missing parameter")); 14394c1177a4SToomas Soome usage(progname); 14404c1177a4SToomas Soome goto out; 14414c1177a4SToomas Soome } 14424c1177a4SToomas Soome BOOT_DEBUG("Current device path is: %s, attaching device path is: " 14434c1177a4SToomas Soome " %s\n", curr_device_path, attach_device_path); 14444c1177a4SToomas Soome 14454c1177a4SToomas Soome bzero(&curr_data, sizeof (ib_data_t)); 14464c1177a4SToomas Soome bzero(&attach_data, sizeof (ib_data_t)); 14474c1177a4SToomas Soome 14484c1177a4SToomas Soome if (init_device(curr_device, curr_device_path) != BC_SUCCESS) { 14494c1177a4SToomas Soome (void) fprintf(stderr, gettext("Unable to gather device " 14504c1177a4SToomas Soome "information from %s (current device)\n"), 14514c1177a4SToomas Soome curr_device_path); 14524c1177a4SToomas Soome goto out_currdev; 14534c1177a4SToomas Soome } 14544c1177a4SToomas Soome 14554c1177a4SToomas Soome if (init_device(attach_device, attach_device_path) != BC_SUCCESS) { 14564c1177a4SToomas Soome (void) fprintf(stderr, gettext("Unable to gather device " 14574c1177a4SToomas Soome "information from %s (attaching device)\n"), 14584c1177a4SToomas Soome attach_device_path); 14594c1177a4SToomas Soome goto out_devs; 14604c1177a4SToomas Soome } 14614c1177a4SToomas Soome 14624c1177a4SToomas Soome ret = read_bootblock_from_disk(curr_device, bblock_curr, &path); 14634c1177a4SToomas Soome if (ret == BC_ERROR) { 14644c1177a4SToomas Soome BOOT_DEBUG("Error reading bootblock from %s\n", path); 14654c1177a4SToomas Soome retval = BC_ERROR; 14664c1177a4SToomas Soome goto out_devs; 14674c1177a4SToomas Soome } 14684c1177a4SToomas Soome 14694c1177a4SToomas Soome if (ret == BC_NOEXTRA) { 14704c1177a4SToomas Soome BOOT_DEBUG("No multiboot header found on %s, unable to retrieve" 14714c1177a4SToomas Soome " the bootblock\n", path); 14724c1177a4SToomas Soome retval = BC_NOEXTRA; 14734c1177a4SToomas Soome goto out_devs; 14744c1177a4SToomas Soome } 14754c1177a4SToomas Soome 14764c1177a4SToomas Soome write_mbr = B_TRUE; 14774c1177a4SToomas Soome force_mbr = B_TRUE; 14784c1177a4SToomas Soome einfo_curr = find_einfo(bblock_curr->extra, bblock_curr->extra_size); 14794c1177a4SToomas Soome if (einfo_curr != NULL) 14804c1177a4SToomas Soome updt_str = einfo_get_string(einfo_curr); 14814c1177a4SToomas Soome 14824c1177a4SToomas Soome retval = propagate_bootblock(&curr_data, &attach_data, updt_str); 14834c1177a4SToomas Soome cleanup_bootblock(bblock_curr); 14844c1177a4SToomas Soome cleanup_bootblock(bblock_attach); 14854c1177a4SToomas Soome out_devs: 14864c1177a4SToomas Soome cleanup_device(attach_device); 14874c1177a4SToomas Soome out_currdev: 14884c1177a4SToomas Soome cleanup_device(curr_device); 14894c1177a4SToomas Soome out: 14904c1177a4SToomas Soome free(curr_device_path); 14914c1177a4SToomas Soome free(attach_device_path); 14924c1177a4SToomas Soome return (retval); 14934c1177a4SToomas Soome } 14944c1177a4SToomas Soome 14954c1177a4SToomas Soome #define USAGE_STRING "Usage:\t%s [-h|-m|-f|-n|-F|-u verstr] stage1 stage2 " \ 14964c1177a4SToomas Soome "raw-device\n" \ 14974c1177a4SToomas Soome "\t%s -M [-n] raw-device attach-raw-device\n" \ 1498*161da084SToomas Soome "\t%s [-e|-V] -i raw-device | file\n" 14994c1177a4SToomas Soome 15004c1177a4SToomas Soome #define CANON_USAGE_STR gettext(USAGE_STRING) 15014c1177a4SToomas Soome 15024c1177a4SToomas Soome static void 15034c1177a4SToomas Soome usage(char *progname) 15044c1177a4SToomas Soome { 15054c1177a4SToomas Soome (void) fprintf(stdout, CANON_USAGE_STR, progname, progname, progname); 15064c1177a4SToomas Soome } 15074c1177a4SToomas Soome 15084c1177a4SToomas Soome int 15094c1177a4SToomas Soome main(int argc, char **argv) 15104c1177a4SToomas Soome { 15114c1177a4SToomas Soome int opt; 15124c1177a4SToomas Soome int params = 3; 15134c1177a4SToomas Soome int ret; 15144c1177a4SToomas Soome char *progname; 15154c1177a4SToomas Soome char **handle_args; 15164c1177a4SToomas Soome 15174c1177a4SToomas Soome (void) setlocale(LC_ALL, ""); 15184c1177a4SToomas Soome (void) textdomain(TEXT_DOMAIN); 15194c1177a4SToomas Soome if (init_yes() < 0) { 15204c1177a4SToomas Soome (void) fprintf(stderr, gettext(ERR_MSG_INIT_YES), 15214c1177a4SToomas Soome strerror(errno)); 15224c1177a4SToomas Soome exit(BC_ERROR); 15234c1177a4SToomas Soome } 15244c1177a4SToomas Soome 15254c1177a4SToomas Soome while ((opt = getopt(argc, argv, "deFfhiMmnu:V")) != EOF) { 15264c1177a4SToomas Soome switch (opt) { 15274c1177a4SToomas Soome case 'd': 15284c1177a4SToomas Soome boot_debug = B_TRUE; 15294c1177a4SToomas Soome break; 15304c1177a4SToomas Soome case 'e': 15314c1177a4SToomas Soome strip = B_TRUE; 15324c1177a4SToomas Soome break; 15334c1177a4SToomas Soome case 'F': 15344c1177a4SToomas Soome force_update = B_TRUE; 15354c1177a4SToomas Soome break; 15364c1177a4SToomas Soome case 'f': 15374c1177a4SToomas Soome force_mbr = B_TRUE; 15384c1177a4SToomas Soome break; 15394c1177a4SToomas Soome case 'h': 15404c1177a4SToomas Soome usage(argv[0]); 15414c1177a4SToomas Soome exit(BC_SUCCESS); 15424c1177a4SToomas Soome break; 15434c1177a4SToomas Soome case 'i': 15444c1177a4SToomas Soome do_getinfo = B_TRUE; 15454c1177a4SToomas Soome params = 1; 15464c1177a4SToomas Soome break; 15474c1177a4SToomas Soome case 'M': 15484c1177a4SToomas Soome do_mirror_bblk = B_TRUE; 15494c1177a4SToomas Soome params = 2; 15504c1177a4SToomas Soome break; 15514c1177a4SToomas Soome case 'm': 15524c1177a4SToomas Soome write_mbr = B_TRUE; 15534c1177a4SToomas Soome break; 15544c1177a4SToomas Soome case 'n': 15554c1177a4SToomas Soome nowrite = B_TRUE; 15564c1177a4SToomas Soome break; 15574c1177a4SToomas Soome case 'u': 15584c1177a4SToomas Soome do_version = B_TRUE; 15594c1177a4SToomas Soome 15604c1177a4SToomas Soome update_str = malloc(strlen(optarg) + 1); 15614c1177a4SToomas Soome if (update_str == NULL) { 15624c1177a4SToomas Soome perror(gettext("Memory allocation failure")); 15634c1177a4SToomas Soome exit(BC_ERROR); 15644c1177a4SToomas Soome } 15654c1177a4SToomas Soome (void) strlcpy(update_str, optarg, strlen(optarg) + 1); 15664c1177a4SToomas Soome break; 15674c1177a4SToomas Soome case 'V': 15684c1177a4SToomas Soome verbose_dump = B_TRUE; 15694c1177a4SToomas Soome break; 15704c1177a4SToomas Soome default: 15714c1177a4SToomas Soome /* fall through to process non-optional args */ 15724c1177a4SToomas Soome break; 15734c1177a4SToomas Soome } 15744c1177a4SToomas Soome } 15754c1177a4SToomas Soome 15764c1177a4SToomas Soome /* check arguments */ 15774c1177a4SToomas Soome if (argc != optind + params) { 15784c1177a4SToomas Soome usage(argv[0]); 15794c1177a4SToomas Soome exit(BC_ERROR); 15804c1177a4SToomas Soome } 15814c1177a4SToomas Soome progname = argv[0]; 15824c1177a4SToomas Soome check_options(progname); 15834c1177a4SToomas Soome handle_args = argv + optind; 15844c1177a4SToomas Soome 15854c1177a4SToomas Soome if (nowrite) 15864c1177a4SToomas Soome (void) fprintf(stdout, gettext("Dry run requested. Nothing will" 15874c1177a4SToomas Soome " be written to disk.\n")); 15884c1177a4SToomas Soome 15894c1177a4SToomas Soome if (do_getinfo) { 15904c1177a4SToomas Soome ret = handle_getinfo(progname, handle_args); 15914c1177a4SToomas Soome } else if (do_mirror_bblk) { 15924c1177a4SToomas Soome ret = handle_mirror(progname, handle_args); 15934c1177a4SToomas Soome } else { 15944c1177a4SToomas Soome ret = handle_install(progname, handle_args); 15954c1177a4SToomas Soome } 15964c1177a4SToomas Soome return (ret); 15974c1177a4SToomas Soome } 15984c1177a4SToomas Soome 15994c1177a4SToomas Soome #define MEANINGLESS_OPT gettext("%s specified but meaningless, ignoring\n") 16004c1177a4SToomas Soome static void 16014c1177a4SToomas Soome check_options(char *progname) 16024c1177a4SToomas Soome { 16034c1177a4SToomas Soome if (do_getinfo && do_mirror_bblk) { 16044c1177a4SToomas Soome (void) fprintf(stderr, gettext("Only one of -M and -i can be " 16054c1177a4SToomas Soome "specified at the same time\n")); 16064c1177a4SToomas Soome usage(progname); 16074c1177a4SToomas Soome exit(BC_ERROR); 16084c1177a4SToomas Soome } 16094c1177a4SToomas Soome 16104c1177a4SToomas Soome if (do_mirror_bblk) { 16114c1177a4SToomas Soome /* 16124c1177a4SToomas Soome * -u and -F may actually reflect a user intent that is not 16134c1177a4SToomas Soome * correct with this command (mirror can be interpreted 16144c1177a4SToomas Soome * "similar" to install. Emit a message and continue. 16154c1177a4SToomas Soome * -e and -V have no meaning, be quiet here and only report the 16164c1177a4SToomas Soome * incongruence if a debug output is requested. 16174c1177a4SToomas Soome */ 16184c1177a4SToomas Soome if (do_version) { 16194c1177a4SToomas Soome (void) fprintf(stderr, MEANINGLESS_OPT, "-u"); 16204c1177a4SToomas Soome do_version = B_FALSE; 16214c1177a4SToomas Soome } 16224c1177a4SToomas Soome if (force_update) { 16234c1177a4SToomas Soome (void) fprintf(stderr, MEANINGLESS_OPT, "-F"); 16244c1177a4SToomas Soome force_update = B_FALSE; 16254c1177a4SToomas Soome } 16264c1177a4SToomas Soome if (strip || verbose_dump) { 16274c1177a4SToomas Soome BOOT_DEBUG(MEANINGLESS_OPT, "-e|-V"); 16284c1177a4SToomas Soome strip = B_FALSE; 16294c1177a4SToomas Soome verbose_dump = B_FALSE; 16304c1177a4SToomas Soome } 16314c1177a4SToomas Soome } 16324c1177a4SToomas Soome 16334c1177a4SToomas Soome if (do_getinfo) { 16344c1177a4SToomas Soome if (write_mbr || force_mbr || do_version || force_update) { 16354c1177a4SToomas Soome BOOT_DEBUG(MEANINGLESS_OPT, "-m|-f|-u|-F"); 16364c1177a4SToomas Soome write_mbr = force_mbr = do_version = B_FALSE; 16374c1177a4SToomas Soome force_update = B_FALSE; 16384c1177a4SToomas Soome } 16394c1177a4SToomas Soome } 16404c1177a4SToomas Soome } 1641