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
read_stage1_from_file(char * path,ib_data_t * dest)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
read_bootblock_from_file(char * file,ib_bootblock_t * bblock)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
read_bootblock_from_disk(ib_device_t * device,ib_bootblock_t * bblock,char ** path)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
is_update_necessary(ib_data_t * data,char * updt_str)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
add_bootblock_einfo(ib_bootblock_t * bblock,char * updt_str)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
prepare_stage1(ib_data_t * data)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
prepare_bootblock(ib_data_t * data,char * updt_str)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
write_bootblock(ib_data_t * data)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
write_stage1(ib_data_t * data)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
get_start_sector(ib_device_t * device)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
open_device(char * path)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
get_boot_partition(ib_device_t * device,struct mboot * mbr)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
get_boot_slice(ib_device_t * device,struct dk_gpt * vtoc)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
init_device(ib_device_t * device,char * path)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
cleanup_device(ib_device_t * device)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
cleanup_bootblock(ib_bootblock_t * bblock)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
propagate_bootblock(ib_data_t * src,ib_data_t * dest,char * updt_str)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
commit_to_disk(ib_data_t * data,char * update_str)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
handle_install(char * progname,char ** argv)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
handle_getinfo(char * progname,char ** argv)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
handle_mirror(char * progname,char ** argv)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
usage(char * progname)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
main(int argc,char ** argv)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
check_options(char * progname)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