1*12947SEnrico.Perla@Sun.COM /* 2*12947SEnrico.Perla@Sun.COM * CDDL HEADER START 3*12947SEnrico.Perla@Sun.COM * 4*12947SEnrico.Perla@Sun.COM * The contents of this file are subject to the terms of the 5*12947SEnrico.Perla@Sun.COM * Common Development and Distribution License (the "License"). 6*12947SEnrico.Perla@Sun.COM * You may not use this file except in compliance with the License. 7*12947SEnrico.Perla@Sun.COM * 8*12947SEnrico.Perla@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*12947SEnrico.Perla@Sun.COM * or http://www.opensolaris.org/os/licensing. 10*12947SEnrico.Perla@Sun.COM * See the License for the specific language governing permissions 11*12947SEnrico.Perla@Sun.COM * and limitations under the License. 12*12947SEnrico.Perla@Sun.COM * 13*12947SEnrico.Perla@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each 14*12947SEnrico.Perla@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*12947SEnrico.Perla@Sun.COM * If applicable, add the following below this CDDL HEADER, with the 16*12947SEnrico.Perla@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying 17*12947SEnrico.Perla@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner] 18*12947SEnrico.Perla@Sun.COM * 19*12947SEnrico.Perla@Sun.COM * CDDL HEADER END 20*12947SEnrico.Perla@Sun.COM */ 21*12947SEnrico.Perla@Sun.COM /* 22*12947SEnrico.Perla@Sun.COM * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 23*12947SEnrico.Perla@Sun.COM */ 24*12947SEnrico.Perla@Sun.COM 25*12947SEnrico.Perla@Sun.COM #include <stdio.h> 26*12947SEnrico.Perla@Sun.COM #include <errno.h> 27*12947SEnrico.Perla@Sun.COM #include <unistd.h> 28*12947SEnrico.Perla@Sun.COM #include <fcntl.h> 29*12947SEnrico.Perla@Sun.COM #include <assert.h> 30*12947SEnrico.Perla@Sun.COM #include <locale.h> 31*12947SEnrico.Perla@Sun.COM #include <strings.h> 32*12947SEnrico.Perla@Sun.COM #include <sys/types.h> 33*12947SEnrico.Perla@Sun.COM #include <sys/stat.h> 34*12947SEnrico.Perla@Sun.COM #include <sys/multiboot.h> 35*12947SEnrico.Perla@Sun.COM #include <sys/sysmacros.h> 36*12947SEnrico.Perla@Sun.COM 37*12947SEnrico.Perla@Sun.COM #include "installboot.h" 38*12947SEnrico.Perla@Sun.COM #include "./../common/bblk_einfo.h" 39*12947SEnrico.Perla@Sun.COM #include "./../common/boot_utils.h" 40*12947SEnrico.Perla@Sun.COM #include "./../common/mboot_extra.h" 41*12947SEnrico.Perla@Sun.COM 42*12947SEnrico.Perla@Sun.COM #ifndef TEXT_DOMAIN 43*12947SEnrico.Perla@Sun.COM #define TEXT_DOMAIN "SUNW_OST_OSCMD" 44*12947SEnrico.Perla@Sun.COM #endif 45*12947SEnrico.Perla@Sun.COM 46*12947SEnrico.Perla@Sun.COM /* 47*12947SEnrico.Perla@Sun.COM * SPARC bootblock installation: 48*12947SEnrico.Perla@Sun.COM * 49*12947SEnrico.Perla@Sun.COM * The bootblock resides in blocks 1 to 15 (disk label is at block 0). 50*12947SEnrico.Perla@Sun.COM * The ZFS boot block is larger than what will fit into these first 7.5K so we 51*12947SEnrico.Perla@Sun.COM * break it up and write the remaining portion into the ZFS provided boot block 52*12947SEnrico.Perla@Sun.COM * region at offset 512K. If versioning is requested, we add a multiboot 53*12947SEnrico.Perla@Sun.COM * header at the end of the bootblock, followed by the extra payload area and 54*12947SEnrico.Perla@Sun.COM * place the extended information structure within the latter. 55*12947SEnrico.Perla@Sun.COM */ 56*12947SEnrico.Perla@Sun.COM 57*12947SEnrico.Perla@Sun.COM static boolean_t force_update = B_FALSE; 58*12947SEnrico.Perla@Sun.COM static boolean_t do_getinfo = B_FALSE; 59*12947SEnrico.Perla@Sun.COM static boolean_t do_version = B_FALSE; 60*12947SEnrico.Perla@Sun.COM static boolean_t do_mirror_bblk = B_FALSE; 61*12947SEnrico.Perla@Sun.COM static boolean_t strip = B_FALSE; 62*12947SEnrico.Perla@Sun.COM static boolean_t verbose_dump = B_FALSE; 63*12947SEnrico.Perla@Sun.COM 64*12947SEnrico.Perla@Sun.COM static char *update_str; 65*12947SEnrico.Perla@Sun.COM static int tgt_fs_type = TARGET_IS_UFS; 66*12947SEnrico.Perla@Sun.COM char mboot_scan[MBOOT_SCAN_SIZE]; 67*12947SEnrico.Perla@Sun.COM 68*12947SEnrico.Perla@Sun.COM /* Function prototypes. */ 69*12947SEnrico.Perla@Sun.COM static int read_bootblock_from_file(char *, ib_data_t *data); 70*12947SEnrico.Perla@Sun.COM static int read_bootblock_from_disk(int, ib_bootblock_t *); 71*12947SEnrico.Perla@Sun.COM static void add_bootblock_einfo(ib_bootblock_t *, char *); 72*12947SEnrico.Perla@Sun.COM static int prepare_bootblock(ib_data_t *, char *); 73*12947SEnrico.Perla@Sun.COM static int write_zfs_bootblock(ib_data_t *); 74*12947SEnrico.Perla@Sun.COM static int write_bootblock(ib_data_t *); 75*12947SEnrico.Perla@Sun.COM static int open_device(ib_device_t *); 76*12947SEnrico.Perla@Sun.COM static int init_device(ib_device_t *, char *); 77*12947SEnrico.Perla@Sun.COM static void cleanup_device(ib_device_t *); 78*12947SEnrico.Perla@Sun.COM static int commit_to_disk(ib_data_t *, char *); 79*12947SEnrico.Perla@Sun.COM static int handle_install(char *, char **); 80*12947SEnrico.Perla@Sun.COM static int handle_getinfo(char *, char **); 81*12947SEnrico.Perla@Sun.COM static int handle_mirror(char *, char **); 82*12947SEnrico.Perla@Sun.COM static boolean_t is_update_necessary(ib_data_t *, char *); 83*12947SEnrico.Perla@Sun.COM static int propagate_bootblock(ib_data_t *, ib_data_t *, char *); 84*12947SEnrico.Perla@Sun.COM static void usage(char *); 85*12947SEnrico.Perla@Sun.COM 86*12947SEnrico.Perla@Sun.COM static int 87*12947SEnrico.Perla@Sun.COM read_bootblock_from_file(char *file, ib_data_t *data) 88*12947SEnrico.Perla@Sun.COM { 89*12947SEnrico.Perla@Sun.COM ib_device_t *device = &data->device; 90*12947SEnrico.Perla@Sun.COM ib_bootblock_t *bblock = &data->bootblock; 91*12947SEnrico.Perla@Sun.COM struct stat sb; 92*12947SEnrico.Perla@Sun.COM uint32_t buf_size; 93*12947SEnrico.Perla@Sun.COM int fd = -1; 94*12947SEnrico.Perla@Sun.COM int retval = BC_ERROR; 95*12947SEnrico.Perla@Sun.COM 96*12947SEnrico.Perla@Sun.COM assert(data != NULL); 97*12947SEnrico.Perla@Sun.COM assert(file != NULL); 98*12947SEnrico.Perla@Sun.COM 99*12947SEnrico.Perla@Sun.COM fd = open(file, O_RDONLY); 100*12947SEnrico.Perla@Sun.COM if (fd == -1) { 101*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("Error opening %s\n", file); 102*12947SEnrico.Perla@Sun.COM perror("open"); 103*12947SEnrico.Perla@Sun.COM goto out; 104*12947SEnrico.Perla@Sun.COM } 105*12947SEnrico.Perla@Sun.COM 106*12947SEnrico.Perla@Sun.COM if (fstat(fd, &sb) == -1) { 107*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("Error getting information (stat) about %s", file); 108*12947SEnrico.Perla@Sun.COM perror("stat"); 109*12947SEnrico.Perla@Sun.COM goto outfd; 110*12947SEnrico.Perla@Sun.COM } 111*12947SEnrico.Perla@Sun.COM 112*12947SEnrico.Perla@Sun.COM bblock->file_size = sb.st_size; 113*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("bootblock file size is %x\n", bblock->file_size); 114*12947SEnrico.Perla@Sun.COM 115*12947SEnrico.Perla@Sun.COM /* UFS and HSFS bootblocks need to fit in the reserved 7.5K. */ 116*12947SEnrico.Perla@Sun.COM if (!is_zfs(device->type)) { 117*12947SEnrico.Perla@Sun.COM buf_size = P2ROUNDUP(bblock->file_size, SECTOR_SIZE); 118*12947SEnrico.Perla@Sun.COM if (buf_size > BBLK_DATA_RSVD_SIZE) { 119*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("boot block size is bigger than allowed\n"); 120*12947SEnrico.Perla@Sun.COM goto outfd; 121*12947SEnrico.Perla@Sun.COM } 122*12947SEnrico.Perla@Sun.COM } else { 123*12947SEnrico.Perla@Sun.COM buf_size = P2ROUNDUP(bblock->file_size + SECTOR_SIZE, 124*12947SEnrico.Perla@Sun.COM SECTOR_SIZE); 125*12947SEnrico.Perla@Sun.COM if (buf_size > BBLK_DATA_RSVD_SIZE + MBOOT_SCAN_SIZE) { 126*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("WARNING, bootblock size" 127*12947SEnrico.Perla@Sun.COM " does not allow to place extended versioning " 128*12947SEnrico.Perla@Sun.COM "information.. skipping\n")); 129*12947SEnrico.Perla@Sun.COM do_version = B_FALSE; 130*12947SEnrico.Perla@Sun.COM } 131*12947SEnrico.Perla@Sun.COM } 132*12947SEnrico.Perla@Sun.COM 133*12947SEnrico.Perla@Sun.COM bblock->buf_size = buf_size; 134*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("bootblock in-memory buffer size is %x\n", 135*12947SEnrico.Perla@Sun.COM bblock->buf_size); 136*12947SEnrico.Perla@Sun.COM 137*12947SEnrico.Perla@Sun.COM bblock->buf = malloc(buf_size); 138*12947SEnrico.Perla@Sun.COM if (bblock->buf == NULL) { 139*12947SEnrico.Perla@Sun.COM perror(gettext("Memory allocation failure")); 140*12947SEnrico.Perla@Sun.COM goto outbuf; 141*12947SEnrico.Perla@Sun.COM } 142*12947SEnrico.Perla@Sun.COM bblock->file = bblock->buf; 143*12947SEnrico.Perla@Sun.COM 144*12947SEnrico.Perla@Sun.COM if (read(fd, bblock->file, bblock->file_size) != bblock->file_size) { 145*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("Read from %s failed\n", file); 146*12947SEnrico.Perla@Sun.COM perror("read"); 147*12947SEnrico.Perla@Sun.COM goto outfd; 148*12947SEnrico.Perla@Sun.COM } 149*12947SEnrico.Perla@Sun.COM 150*12947SEnrico.Perla@Sun.COM /* If not on ZFS, we are done here. */ 151*12947SEnrico.Perla@Sun.COM if (!is_zfs(device->type)) { 152*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("Reading of the bootblock done\n"); 153*12947SEnrico.Perla@Sun.COM retval = BC_SUCCESS; 154*12947SEnrico.Perla@Sun.COM goto outfd; 155*12947SEnrico.Perla@Sun.COM } 156*12947SEnrico.Perla@Sun.COM /* 157*12947SEnrico.Perla@Sun.COM * We place the multiboot header right after the file, followed by 158*12947SEnrico.Perla@Sun.COM * the extended information structure. 159*12947SEnrico.Perla@Sun.COM */ 160*12947SEnrico.Perla@Sun.COM bblock->mboot = (multiboot_header_t *)(bblock->file + 161*12947SEnrico.Perla@Sun.COM P2ROUNDUP(bblock->file_size, 8)); 162*12947SEnrico.Perla@Sun.COM bblock->extra = (char *)bblock->mboot + sizeof (multiboot_header_t); 163*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("mboot at %p, extra at %p, buf=%p (size=%d)\n", 164*12947SEnrico.Perla@Sun.COM bblock->mboot, bblock->extra, bblock->buf, bblock->buf_size); 165*12947SEnrico.Perla@Sun.COM 166*12947SEnrico.Perla@Sun.COM (void) close(fd); 167*12947SEnrico.Perla@Sun.COM return (BC_SUCCESS); 168*12947SEnrico.Perla@Sun.COM 169*12947SEnrico.Perla@Sun.COM outbuf: 170*12947SEnrico.Perla@Sun.COM (void) free(bblock->buf); 171*12947SEnrico.Perla@Sun.COM bblock->buf = NULL; 172*12947SEnrico.Perla@Sun.COM outfd: 173*12947SEnrico.Perla@Sun.COM (void) close(fd); 174*12947SEnrico.Perla@Sun.COM out: 175*12947SEnrico.Perla@Sun.COM return (retval); 176*12947SEnrico.Perla@Sun.COM } 177*12947SEnrico.Perla@Sun.COM 178*12947SEnrico.Perla@Sun.COM static int 179*12947SEnrico.Perla@Sun.COM read_bootblock_from_disk(int dev_fd, ib_bootblock_t *bblock) 180*12947SEnrico.Perla@Sun.COM { 181*12947SEnrico.Perla@Sun.COM char *dest; 182*12947SEnrico.Perla@Sun.COM uint32_t size; 183*12947SEnrico.Perla@Sun.COM uint32_t buf_size; 184*12947SEnrico.Perla@Sun.COM uint32_t mboot_off; 185*12947SEnrico.Perla@Sun.COM multiboot_header_t *mboot; 186*12947SEnrico.Perla@Sun.COM 187*12947SEnrico.Perla@Sun.COM assert(bblock != NULL); 188*12947SEnrico.Perla@Sun.COM assert(dev_fd != -1); 189*12947SEnrico.Perla@Sun.COM 190*12947SEnrico.Perla@Sun.COM /* 191*12947SEnrico.Perla@Sun.COM * The ZFS bootblock is divided in two parts, but the fake multiboot 192*12947SEnrico.Perla@Sun.COM * header can only be in the second part (the one contained in the ZFS 193*12947SEnrico.Perla@Sun.COM * reserved area). 194*12947SEnrico.Perla@Sun.COM */ 195*12947SEnrico.Perla@Sun.COM if (read_in(dev_fd, mboot_scan, sizeof (mboot_scan), 196*12947SEnrico.Perla@Sun.COM BBLK_ZFS_EXTRA_OFF) != BC_SUCCESS) { 197*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("Error reading ZFS reserved area\n"); 198*12947SEnrico.Perla@Sun.COM perror("read"); 199*12947SEnrico.Perla@Sun.COM return (BC_ERROR); 200*12947SEnrico.Perla@Sun.COM } 201*12947SEnrico.Perla@Sun.COM 202*12947SEnrico.Perla@Sun.COM /* No multiboot means no chance of knowing bootblock size */ 203*12947SEnrico.Perla@Sun.COM if (find_multiboot(mboot_scan, sizeof (mboot_scan), &mboot_off) 204*12947SEnrico.Perla@Sun.COM != BC_SUCCESS) { 205*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("Unable to find multiboot header\n"); 206*12947SEnrico.Perla@Sun.COM return (BC_NOEXTRA); 207*12947SEnrico.Perla@Sun.COM } 208*12947SEnrico.Perla@Sun.COM mboot = (multiboot_header_t *)(mboot_scan + mboot_off); 209*12947SEnrico.Perla@Sun.COM 210*12947SEnrico.Perla@Sun.COM /* 211*12947SEnrico.Perla@Sun.COM * Currently, the amount of space reserved for extra information 212*12947SEnrico.Perla@Sun.COM * is "fixed". We may have to scan for the terminating extra payload 213*12947SEnrico.Perla@Sun.COM * in the future. 214*12947SEnrico.Perla@Sun.COM */ 215*12947SEnrico.Perla@Sun.COM size = mboot->load_end_addr - mboot->load_addr; 216*12947SEnrico.Perla@Sun.COM buf_size = P2ROUNDUP(size + SECTOR_SIZE, SECTOR_SIZE); 217*12947SEnrico.Perla@Sun.COM bblock->file_size = size; 218*12947SEnrico.Perla@Sun.COM 219*12947SEnrico.Perla@Sun.COM bblock->buf = malloc(buf_size); 220*12947SEnrico.Perla@Sun.COM if (bblock->buf == NULL) { 221*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("Unable to allocate enough memory to read" 222*12947SEnrico.Perla@Sun.COM " the extra bootblock from the disk\n"); 223*12947SEnrico.Perla@Sun.COM perror(gettext("Memory allocation failure")); 224*12947SEnrico.Perla@Sun.COM return (BC_ERROR); 225*12947SEnrico.Perla@Sun.COM } 226*12947SEnrico.Perla@Sun.COM bblock->buf_size = buf_size; 227*12947SEnrico.Perla@Sun.COM 228*12947SEnrico.Perla@Sun.COM dest = bblock->buf; 229*12947SEnrico.Perla@Sun.COM size = BBLK_DATA_RSVD_SIZE; 230*12947SEnrico.Perla@Sun.COM 231*12947SEnrico.Perla@Sun.COM if (read_in(dev_fd, dest, size, SECTOR_SIZE) != BC_SUCCESS) { 232*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("Error reading first %d bytes of the bootblock\n", 233*12947SEnrico.Perla@Sun.COM size); 234*12947SEnrico.Perla@Sun.COM (void) free(bblock->buf); 235*12947SEnrico.Perla@Sun.COM bblock->buf = NULL; 236*12947SEnrico.Perla@Sun.COM return (BC_ERROR); 237*12947SEnrico.Perla@Sun.COM } 238*12947SEnrico.Perla@Sun.COM 239*12947SEnrico.Perla@Sun.COM dest += BBLK_DATA_RSVD_SIZE; 240*12947SEnrico.Perla@Sun.COM size = bblock->buf_size - BBLK_DATA_RSVD_SIZE; 241*12947SEnrico.Perla@Sun.COM 242*12947SEnrico.Perla@Sun.COM if (read_in(dev_fd, dest, size, BBLK_ZFS_EXTRA_OFF) != BC_SUCCESS) { 243*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("Error reading ZFS reserved area the second time\n"); 244*12947SEnrico.Perla@Sun.COM (void) free(bblock->buf); 245*12947SEnrico.Perla@Sun.COM bblock->buf = NULL; 246*12947SEnrico.Perla@Sun.COM return (BC_ERROR); 247*12947SEnrico.Perla@Sun.COM } 248*12947SEnrico.Perla@Sun.COM 249*12947SEnrico.Perla@Sun.COM /* Update pointers. */ 250*12947SEnrico.Perla@Sun.COM bblock->file = bblock->buf; 251*12947SEnrico.Perla@Sun.COM bblock->mboot_off = mboot_off; 252*12947SEnrico.Perla@Sun.COM bblock->mboot = (multiboot_header_t *)(bblock->buf + bblock->mboot_off 253*12947SEnrico.Perla@Sun.COM + BBLK_DATA_RSVD_SIZE); 254*12947SEnrico.Perla@Sun.COM bblock->extra = (char *)bblock->mboot + sizeof (multiboot_header_t); 255*12947SEnrico.Perla@Sun.COM return (BC_SUCCESS); 256*12947SEnrico.Perla@Sun.COM } 257*12947SEnrico.Perla@Sun.COM 258*12947SEnrico.Perla@Sun.COM static boolean_t 259*12947SEnrico.Perla@Sun.COM is_update_necessary(ib_data_t *data, char *updt_str) 260*12947SEnrico.Perla@Sun.COM { 261*12947SEnrico.Perla@Sun.COM bblk_einfo_t *einfo; 262*12947SEnrico.Perla@Sun.COM bblk_hs_t bblock_hs; 263*12947SEnrico.Perla@Sun.COM ib_bootblock_t bblock_disk; 264*12947SEnrico.Perla@Sun.COM ib_bootblock_t *bblock_file = &data->bootblock; 265*12947SEnrico.Perla@Sun.COM ib_device_t *device = &data->device; 266*12947SEnrico.Perla@Sun.COM int dev_fd = device->fd; 267*12947SEnrico.Perla@Sun.COM 268*12947SEnrico.Perla@Sun.COM assert(data != NULL); 269*12947SEnrico.Perla@Sun.COM assert(device->fd != -1); 270*12947SEnrico.Perla@Sun.COM 271*12947SEnrico.Perla@Sun.COM /* Nothing to do if we are not updating a ZFS bootblock. */ 272*12947SEnrico.Perla@Sun.COM if (!is_zfs(device->type)) 273*12947SEnrico.Perla@Sun.COM return (B_TRUE); 274*12947SEnrico.Perla@Sun.COM 275*12947SEnrico.Perla@Sun.COM bzero(&bblock_disk, sizeof (ib_bootblock_t)); 276*12947SEnrico.Perla@Sun.COM 277*12947SEnrico.Perla@Sun.COM if (read_bootblock_from_disk(dev_fd, &bblock_disk) != BC_SUCCESS) { 278*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("Unable to read bootblock from %s\n", device->path); 279*12947SEnrico.Perla@Sun.COM return (B_TRUE); 280*12947SEnrico.Perla@Sun.COM } 281*12947SEnrico.Perla@Sun.COM 282*12947SEnrico.Perla@Sun.COM einfo = find_einfo(bblock_disk.extra); 283*12947SEnrico.Perla@Sun.COM if (einfo == NULL) { 284*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("No extended information available\n"); 285*12947SEnrico.Perla@Sun.COM return (B_TRUE); 286*12947SEnrico.Perla@Sun.COM } 287*12947SEnrico.Perla@Sun.COM 288*12947SEnrico.Perla@Sun.COM if (!do_version || updt_str == NULL) { 289*12947SEnrico.Perla@Sun.COM (void) fprintf(stdout, "WARNING: target device %s has a " 290*12947SEnrico.Perla@Sun.COM "versioned bootblock that is going to be overwritten by a " 291*12947SEnrico.Perla@Sun.COM "non versioned one\n", device->path); 292*12947SEnrico.Perla@Sun.COM return (B_TRUE); 293*12947SEnrico.Perla@Sun.COM } 294*12947SEnrico.Perla@Sun.COM 295*12947SEnrico.Perla@Sun.COM if (force_update) { 296*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("Forcing update of %s bootblock\n", device->path); 297*12947SEnrico.Perla@Sun.COM return (B_TRUE); 298*12947SEnrico.Perla@Sun.COM } 299*12947SEnrico.Perla@Sun.COM 300*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("Ready to check installed version vs %s\n", updt_str); 301*12947SEnrico.Perla@Sun.COM 302*12947SEnrico.Perla@Sun.COM bblock_hs.src_buf = (unsigned char *)bblock_file->file; 303*12947SEnrico.Perla@Sun.COM bblock_hs.src_size = bblock_file->file_size; 304*12947SEnrico.Perla@Sun.COM 305*12947SEnrico.Perla@Sun.COM return (einfo_should_update(einfo, &bblock_hs, updt_str)); 306*12947SEnrico.Perla@Sun.COM } 307*12947SEnrico.Perla@Sun.COM 308*12947SEnrico.Perla@Sun.COM static void 309*12947SEnrico.Perla@Sun.COM add_bootblock_einfo(ib_bootblock_t *bblock, char *updt_str) 310*12947SEnrico.Perla@Sun.COM { 311*12947SEnrico.Perla@Sun.COM bblk_hs_t hs; 312*12947SEnrico.Perla@Sun.COM uint32_t avail_space; 313*12947SEnrico.Perla@Sun.COM 314*12947SEnrico.Perla@Sun.COM assert(bblock != NULL); 315*12947SEnrico.Perla@Sun.COM 316*12947SEnrico.Perla@Sun.COM if (updt_str == NULL) { 317*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("WARNING: no update string passed to " 318*12947SEnrico.Perla@Sun.COM "add_bootblock_einfo()\n"); 319*12947SEnrico.Perla@Sun.COM return; 320*12947SEnrico.Perla@Sun.COM } 321*12947SEnrico.Perla@Sun.COM 322*12947SEnrico.Perla@Sun.COM /* Fill bootblock hashing source information. */ 323*12947SEnrico.Perla@Sun.COM hs.src_buf = (unsigned char *)bblock->file; 324*12947SEnrico.Perla@Sun.COM hs.src_size = bblock->file_size; 325*12947SEnrico.Perla@Sun.COM /* How much space for the extended information structure? */ 326*12947SEnrico.Perla@Sun.COM avail_space = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8); 327*12947SEnrico.Perla@Sun.COM /* Place the extended information structure. */ 328*12947SEnrico.Perla@Sun.COM add_einfo(bblock->extra, updt_str, &hs, avail_space); 329*12947SEnrico.Perla@Sun.COM } 330*12947SEnrico.Perla@Sun.COM 331*12947SEnrico.Perla@Sun.COM 332*12947SEnrico.Perla@Sun.COM static int 333*12947SEnrico.Perla@Sun.COM prepare_bootblock(ib_data_t *data, char *updt_str) 334*12947SEnrico.Perla@Sun.COM { 335*12947SEnrico.Perla@Sun.COM ib_device_t *device = &data->device; 336*12947SEnrico.Perla@Sun.COM ib_bootblock_t *bblock = &data->bootblock; 337*12947SEnrico.Perla@Sun.COM multiboot_header_t *mboot; 338*12947SEnrico.Perla@Sun.COM 339*12947SEnrico.Perla@Sun.COM assert(data != NULL); 340*12947SEnrico.Perla@Sun.COM 341*12947SEnrico.Perla@Sun.COM /* Nothing to do if we are not on ZFS. */ 342*12947SEnrico.Perla@Sun.COM if (!is_zfs(device->type)) 343*12947SEnrico.Perla@Sun.COM return (BC_SUCCESS); 344*12947SEnrico.Perla@Sun.COM 345*12947SEnrico.Perla@Sun.COM /* 346*12947SEnrico.Perla@Sun.COM * Write the fake multiboot structure followed by the extra information 347*12947SEnrico.Perla@Sun.COM * data. Both mboot and extra pointers have already been filled up to 348*12947SEnrico.Perla@Sun.COM * point to the right location in the buffer. We prepare the fake 349*12947SEnrico.Perla@Sun.COM * multiboot regardless if versioning was requested or not because 350*12947SEnrico.Perla@Sun.COM * we need it for mirroring support. 351*12947SEnrico.Perla@Sun.COM */ 352*12947SEnrico.Perla@Sun.COM assert(bblock->mboot != NULL); 353*12947SEnrico.Perla@Sun.COM assert(bblock->extra != NULL); 354*12947SEnrico.Perla@Sun.COM 355*12947SEnrico.Perla@Sun.COM mboot = bblock->mboot; 356*12947SEnrico.Perla@Sun.COM 357*12947SEnrico.Perla@Sun.COM mboot->magic = MB_HEADER_MAGIC; 358*12947SEnrico.Perla@Sun.COM mboot->flags = MB_HEADER_FLAGS_64; 359*12947SEnrico.Perla@Sun.COM mboot->checksum = -(mboot->flags + mboot->magic); 360*12947SEnrico.Perla@Sun.COM /* 361*12947SEnrico.Perla@Sun.COM * Flags include the AOUT_KLUDGE and we use the extra members to specify 362*12947SEnrico.Perla@Sun.COM * the size of the bootblock. 363*12947SEnrico.Perla@Sun.COM */ 364*12947SEnrico.Perla@Sun.COM mboot->header_addr = bblock->mboot_off; 365*12947SEnrico.Perla@Sun.COM mboot->load_addr = 0; 366*12947SEnrico.Perla@Sun.COM mboot->load_end_addr = bblock->file_size; 367*12947SEnrico.Perla@Sun.COM 368*12947SEnrico.Perla@Sun.COM /* 369*12947SEnrico.Perla@Sun.COM * Now that we have the mboot header in place, we can add the extended 370*12947SEnrico.Perla@Sun.COM * versioning information. Since the multiboot header has been placed 371*12947SEnrico.Perla@Sun.COM * after the file image, the hashing will still reflect the one of the 372*12947SEnrico.Perla@Sun.COM * file on the disk. 373*12947SEnrico.Perla@Sun.COM */ 374*12947SEnrico.Perla@Sun.COM if (do_version) 375*12947SEnrico.Perla@Sun.COM add_bootblock_einfo(bblock, updt_str); 376*12947SEnrico.Perla@Sun.COM 377*12947SEnrico.Perla@Sun.COM return (BC_SUCCESS); 378*12947SEnrico.Perla@Sun.COM } 379*12947SEnrico.Perla@Sun.COM 380*12947SEnrico.Perla@Sun.COM static int 381*12947SEnrico.Perla@Sun.COM write_zfs_bootblock(ib_data_t *data) 382*12947SEnrico.Perla@Sun.COM { 383*12947SEnrico.Perla@Sun.COM ib_device_t *device = &data->device; 384*12947SEnrico.Perla@Sun.COM ib_bootblock_t *bblock = &data->bootblock; 385*12947SEnrico.Perla@Sun.COM char *bufptr; 386*12947SEnrico.Perla@Sun.COM uint32_t size; 387*12947SEnrico.Perla@Sun.COM 388*12947SEnrico.Perla@Sun.COM assert(data != NULL); 389*12947SEnrico.Perla@Sun.COM assert(device->fd != -1); 390*12947SEnrico.Perla@Sun.COM 391*12947SEnrico.Perla@Sun.COM /* 392*12947SEnrico.Perla@Sun.COM * In the ZFS case we actually perform two different steps: 393*12947SEnrico.Perla@Sun.COM * - write the first 15 blocks of the bootblock to the reserved disk 394*12947SEnrico.Perla@Sun.COM * blocks. 395*12947SEnrico.Perla@Sun.COM * - write the remaining blocks in the ZFS reserved area at offset 396*12947SEnrico.Perla@Sun.COM * 512K. 397*12947SEnrico.Perla@Sun.COM */ 398*12947SEnrico.Perla@Sun.COM bufptr = bblock->buf; 399*12947SEnrico.Perla@Sun.COM size = BBLK_DATA_RSVD_SIZE; 400*12947SEnrico.Perla@Sun.COM 401*12947SEnrico.Perla@Sun.COM if (write_out(device->fd, bufptr, size, SECTOR_SIZE) != BC_SUCCESS) { 402*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("Error writing first 15 blocks of %s\n", 403*12947SEnrico.Perla@Sun.COM device->path); 404*12947SEnrico.Perla@Sun.COM perror("write"); 405*12947SEnrico.Perla@Sun.COM return (BC_ERROR); 406*12947SEnrico.Perla@Sun.COM } 407*12947SEnrico.Perla@Sun.COM 408*12947SEnrico.Perla@Sun.COM bufptr += BBLK_DATA_RSVD_SIZE; 409*12947SEnrico.Perla@Sun.COM size = bblock->buf_size - BBLK_DATA_RSVD_SIZE; 410*12947SEnrico.Perla@Sun.COM 411*12947SEnrico.Perla@Sun.COM if (write_out(device->fd, bufptr, size, BBLK_ZFS_EXTRA_OFF) 412*12947SEnrico.Perla@Sun.COM != BC_SUCCESS) { 413*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("Error writing the second part of ZFS bootblock " 414*12947SEnrico.Perla@Sun.COM "to %s at offset %d\n", device->path, BBLK_ZFS_EXTRA_OFF); 415*12947SEnrico.Perla@Sun.COM return (BC_ERROR); 416*12947SEnrico.Perla@Sun.COM } 417*12947SEnrico.Perla@Sun.COM return (BC_SUCCESS); 418*12947SEnrico.Perla@Sun.COM } 419*12947SEnrico.Perla@Sun.COM 420*12947SEnrico.Perla@Sun.COM static int 421*12947SEnrico.Perla@Sun.COM write_bootblock(ib_data_t *data) 422*12947SEnrico.Perla@Sun.COM { 423*12947SEnrico.Perla@Sun.COM ib_device_t *device = &data->device; 424*12947SEnrico.Perla@Sun.COM ib_bootblock_t *bblock = &data->bootblock; 425*12947SEnrico.Perla@Sun.COM int ret; 426*12947SEnrico.Perla@Sun.COM 427*12947SEnrico.Perla@Sun.COM assert(data != NULL); 428*12947SEnrico.Perla@Sun.COM 429*12947SEnrico.Perla@Sun.COM /* 430*12947SEnrico.Perla@Sun.COM * If we are on UFS or HSFS we simply write out to the reserved 431*12947SEnrico.Perla@Sun.COM * blocks (1 to 15) the boot block. 432*12947SEnrico.Perla@Sun.COM */ 433*12947SEnrico.Perla@Sun.COM if (!is_zfs(device->type)) { 434*12947SEnrico.Perla@Sun.COM if (write_out(device->fd, bblock->buf, bblock->buf_size, 435*12947SEnrico.Perla@Sun.COM SECTOR_SIZE) != BC_SUCCESS) { 436*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("Error writing bootblock to %s\n", 437*12947SEnrico.Perla@Sun.COM device->path); 438*12947SEnrico.Perla@Sun.COM return (BC_ERROR); 439*12947SEnrico.Perla@Sun.COM } else { 440*12947SEnrico.Perla@Sun.COM return (BC_SUCCESS); 441*12947SEnrico.Perla@Sun.COM } 442*12947SEnrico.Perla@Sun.COM } else { 443*12947SEnrico.Perla@Sun.COM ret = write_zfs_bootblock(data); 444*12947SEnrico.Perla@Sun.COM return (ret); 445*12947SEnrico.Perla@Sun.COM } 446*12947SEnrico.Perla@Sun.COM } 447*12947SEnrico.Perla@Sun.COM 448*12947SEnrico.Perla@Sun.COM static int 449*12947SEnrico.Perla@Sun.COM open_device(ib_device_t *device) 450*12947SEnrico.Perla@Sun.COM { 451*12947SEnrico.Perla@Sun.COM struct stat statbuf; 452*12947SEnrico.Perla@Sun.COM 453*12947SEnrico.Perla@Sun.COM device->fd = open(device->path, O_RDWR); 454*12947SEnrico.Perla@Sun.COM if (device->fd == -1) { 455*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("Unable to open %s\n", device->path); 456*12947SEnrico.Perla@Sun.COM perror("open"); 457*12947SEnrico.Perla@Sun.COM return (BC_ERROR); 458*12947SEnrico.Perla@Sun.COM } 459*12947SEnrico.Perla@Sun.COM 460*12947SEnrico.Perla@Sun.COM if (fstat(device->fd, &statbuf) != 0) { 461*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("Unable to stat %s\n", device->path); 462*12947SEnrico.Perla@Sun.COM perror("stat"); 463*12947SEnrico.Perla@Sun.COM (void) close(device->fd); 464*12947SEnrico.Perla@Sun.COM return (BC_ERROR); 465*12947SEnrico.Perla@Sun.COM } 466*12947SEnrico.Perla@Sun.COM 467*12947SEnrico.Perla@Sun.COM if (S_ISCHR(statbuf.st_mode) == 0) { 468*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("%s: Not a character device\n"), 469*12947SEnrico.Perla@Sun.COM device->path); 470*12947SEnrico.Perla@Sun.COM return (BC_ERROR); 471*12947SEnrico.Perla@Sun.COM } 472*12947SEnrico.Perla@Sun.COM 473*12947SEnrico.Perla@Sun.COM return (BC_SUCCESS); 474*12947SEnrico.Perla@Sun.COM } 475*12947SEnrico.Perla@Sun.COM 476*12947SEnrico.Perla@Sun.COM static int 477*12947SEnrico.Perla@Sun.COM init_device(ib_device_t *device, char *path) 478*12947SEnrico.Perla@Sun.COM { 479*12947SEnrico.Perla@Sun.COM bzero(device, sizeof (*device)); 480*12947SEnrico.Perla@Sun.COM device->fd = -1; 481*12947SEnrico.Perla@Sun.COM 482*12947SEnrico.Perla@Sun.COM device->path = strdup(path); 483*12947SEnrico.Perla@Sun.COM if (path == NULL) { 484*12947SEnrico.Perla@Sun.COM perror(gettext("Memory allocation failure")); 485*12947SEnrico.Perla@Sun.COM return (BC_ERROR); 486*12947SEnrico.Perla@Sun.COM } 487*12947SEnrico.Perla@Sun.COM 488*12947SEnrico.Perla@Sun.COM device->type = tgt_fs_type; 489*12947SEnrico.Perla@Sun.COM if (open_device(device) != BC_SUCCESS) 490*12947SEnrico.Perla@Sun.COM return (BC_ERROR); 491*12947SEnrico.Perla@Sun.COM 492*12947SEnrico.Perla@Sun.COM return (BC_SUCCESS); 493*12947SEnrico.Perla@Sun.COM } 494*12947SEnrico.Perla@Sun.COM 495*12947SEnrico.Perla@Sun.COM static void 496*12947SEnrico.Perla@Sun.COM cleanup_device(ib_device_t *device) 497*12947SEnrico.Perla@Sun.COM { 498*12947SEnrico.Perla@Sun.COM free(device->path); 499*12947SEnrico.Perla@Sun.COM bzero(device, sizeof (*device)); 500*12947SEnrico.Perla@Sun.COM 501*12947SEnrico.Perla@Sun.COM if (device->fd != -1) 502*12947SEnrico.Perla@Sun.COM (void) close(device->fd); 503*12947SEnrico.Perla@Sun.COM } 504*12947SEnrico.Perla@Sun.COM 505*12947SEnrico.Perla@Sun.COM static void 506*12947SEnrico.Perla@Sun.COM cleanup_bootblock(ib_bootblock_t *bblock) 507*12947SEnrico.Perla@Sun.COM { 508*12947SEnrico.Perla@Sun.COM free(bblock->buf); 509*12947SEnrico.Perla@Sun.COM bzero(bblock, sizeof (ib_bootblock_t)); 510*12947SEnrico.Perla@Sun.COM } 511*12947SEnrico.Perla@Sun.COM 512*12947SEnrico.Perla@Sun.COM /* 513*12947SEnrico.Perla@Sun.COM * Propagate the bootblock on the source disk to the destination disk and 514*12947SEnrico.Perla@Sun.COM * version it with 'updt_str' in the process. Since we cannot trust any data 515*12947SEnrico.Perla@Sun.COM * on the attaching disk, we do not perform any specific check on a potential 516*12947SEnrico.Perla@Sun.COM * target extended information structure and we just blindly update. 517*12947SEnrico.Perla@Sun.COM */ 518*12947SEnrico.Perla@Sun.COM static int 519*12947SEnrico.Perla@Sun.COM propagate_bootblock(ib_data_t *src, ib_data_t *dest, char *updt_str) 520*12947SEnrico.Perla@Sun.COM { 521*12947SEnrico.Perla@Sun.COM ib_bootblock_t *src_bblock = &src->bootblock; 522*12947SEnrico.Perla@Sun.COM ib_bootblock_t *dest_bblock = &dest->bootblock; 523*12947SEnrico.Perla@Sun.COM uint32_t buf_size; 524*12947SEnrico.Perla@Sun.COM 525*12947SEnrico.Perla@Sun.COM assert(src != NULL); 526*12947SEnrico.Perla@Sun.COM assert(dest != NULL); 527*12947SEnrico.Perla@Sun.COM 528*12947SEnrico.Perla@Sun.COM cleanup_bootblock(dest_bblock); 529*12947SEnrico.Perla@Sun.COM 530*12947SEnrico.Perla@Sun.COM if (updt_str != NULL) { 531*12947SEnrico.Perla@Sun.COM do_version = B_TRUE; 532*12947SEnrico.Perla@Sun.COM } else { 533*12947SEnrico.Perla@Sun.COM do_version = B_FALSE; 534*12947SEnrico.Perla@Sun.COM } 535*12947SEnrico.Perla@Sun.COM 536*12947SEnrico.Perla@Sun.COM buf_size = src_bblock->file_size + SECTOR_SIZE; 537*12947SEnrico.Perla@Sun.COM 538*12947SEnrico.Perla@Sun.COM dest_bblock->buf_size = P2ROUNDUP(buf_size, SECTOR_SIZE); 539*12947SEnrico.Perla@Sun.COM dest_bblock->buf = malloc(dest_bblock->buf_size); 540*12947SEnrico.Perla@Sun.COM if (dest_bblock->buf == NULL) { 541*12947SEnrico.Perla@Sun.COM perror(gettext("Memory Allocation Failure")); 542*12947SEnrico.Perla@Sun.COM return (BC_ERROR); 543*12947SEnrico.Perla@Sun.COM } 544*12947SEnrico.Perla@Sun.COM dest_bblock->file = dest_bblock->buf; 545*12947SEnrico.Perla@Sun.COM dest_bblock->file_size = src_bblock->file_size; 546*12947SEnrico.Perla@Sun.COM (void) memcpy(dest_bblock->file, src_bblock->file, 547*12947SEnrico.Perla@Sun.COM dest_bblock->file_size); 548*12947SEnrico.Perla@Sun.COM 549*12947SEnrico.Perla@Sun.COM dest_bblock->mboot = (multiboot_header_t *)(dest_bblock->file + 550*12947SEnrico.Perla@Sun.COM P2ROUNDUP(dest_bblock->file_size, 8)); 551*12947SEnrico.Perla@Sun.COM dest_bblock->extra = (char *)dest_bblock->mboot + 552*12947SEnrico.Perla@Sun.COM sizeof (multiboot_header_t); 553*12947SEnrico.Perla@Sun.COM 554*12947SEnrico.Perla@Sun.COM (void) fprintf(stdout, gettext("Propagating %s bootblock to %s\n"), 555*12947SEnrico.Perla@Sun.COM src->device.path, dest->device.path); 556*12947SEnrico.Perla@Sun.COM 557*12947SEnrico.Perla@Sun.COM return (commit_to_disk(dest, updt_str)); 558*12947SEnrico.Perla@Sun.COM } 559*12947SEnrico.Perla@Sun.COM 560*12947SEnrico.Perla@Sun.COM static int 561*12947SEnrico.Perla@Sun.COM commit_to_disk(ib_data_t *data, char *update_str) 562*12947SEnrico.Perla@Sun.COM { 563*12947SEnrico.Perla@Sun.COM assert(data != NULL); 564*12947SEnrico.Perla@Sun.COM 565*12947SEnrico.Perla@Sun.COM if (prepare_bootblock(data, update_str) != BC_SUCCESS) { 566*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Error updating the bootblock " 567*12947SEnrico.Perla@Sun.COM "image\n")); 568*12947SEnrico.Perla@Sun.COM return (BC_ERROR); 569*12947SEnrico.Perla@Sun.COM } 570*12947SEnrico.Perla@Sun.COM 571*12947SEnrico.Perla@Sun.COM if (write_bootblock(data) != BC_SUCCESS) { 572*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Error writing bootblock to " 573*12947SEnrico.Perla@Sun.COM "disk\n")); 574*12947SEnrico.Perla@Sun.COM return (BC_ERROR); 575*12947SEnrico.Perla@Sun.COM } 576*12947SEnrico.Perla@Sun.COM 577*12947SEnrico.Perla@Sun.COM return (BC_SUCCESS); 578*12947SEnrico.Perla@Sun.COM } 579*12947SEnrico.Perla@Sun.COM 580*12947SEnrico.Perla@Sun.COM 581*12947SEnrico.Perla@Sun.COM /* 582*12947SEnrico.Perla@Sun.COM * Install a new bootblock on the given device. handle_install() expects argv 583*12947SEnrico.Perla@Sun.COM * to contain 2 parameters (the target device path and the path to the 584*12947SEnrico.Perla@Sun.COM * bootblock. 585*12947SEnrico.Perla@Sun.COM * 586*12947SEnrico.Perla@Sun.COM * Returns: BC_SUCCESS - if the installation is successful 587*12947SEnrico.Perla@Sun.COM * BC_ERROR - if the installation failed 588*12947SEnrico.Perla@Sun.COM * BC_NOUPDT - if no installation was performed because the 589*12947SEnrico.Perla@Sun.COM * version currently installed is more recent than the 590*12947SEnrico.Perla@Sun.COM * supplied one. 591*12947SEnrico.Perla@Sun.COM * 592*12947SEnrico.Perla@Sun.COM */ 593*12947SEnrico.Perla@Sun.COM static int 594*12947SEnrico.Perla@Sun.COM handle_install(char *progname, char **argv) 595*12947SEnrico.Perla@Sun.COM { 596*12947SEnrico.Perla@Sun.COM ib_data_t install_data; 597*12947SEnrico.Perla@Sun.COM char *bootblock = NULL; 598*12947SEnrico.Perla@Sun.COM char *device_path = NULL; 599*12947SEnrico.Perla@Sun.COM int ret = BC_ERROR; 600*12947SEnrico.Perla@Sun.COM 601*12947SEnrico.Perla@Sun.COM bootblock = strdup(argv[0]); 602*12947SEnrico.Perla@Sun.COM device_path = strdup(argv[1]); 603*12947SEnrico.Perla@Sun.COM 604*12947SEnrico.Perla@Sun.COM if (!device_path || !bootblock) { 605*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Missing parameter")); 606*12947SEnrico.Perla@Sun.COM usage(progname); 607*12947SEnrico.Perla@Sun.COM goto out; 608*12947SEnrico.Perla@Sun.COM } 609*12947SEnrico.Perla@Sun.COM 610*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("device path: %s, bootblock file path: %s\n", device_path, 611*12947SEnrico.Perla@Sun.COM bootblock); 612*12947SEnrico.Perla@Sun.COM bzero(&install_data, sizeof (ib_data_t)); 613*12947SEnrico.Perla@Sun.COM 614*12947SEnrico.Perla@Sun.COM if (init_device(&install_data.device, device_path) != BC_SUCCESS) { 615*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Unable to open device %s\n"), 616*12947SEnrico.Perla@Sun.COM device_path); 617*12947SEnrico.Perla@Sun.COM goto out; 618*12947SEnrico.Perla@Sun.COM } 619*12947SEnrico.Perla@Sun.COM 620*12947SEnrico.Perla@Sun.COM if (read_bootblock_from_file(bootblock, &install_data) != BC_SUCCESS) { 621*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Error reading %s\n"), 622*12947SEnrico.Perla@Sun.COM bootblock); 623*12947SEnrico.Perla@Sun.COM goto out_dev; 624*12947SEnrico.Perla@Sun.COM } 625*12947SEnrico.Perla@Sun.COM /* Versioning is only supported for the ZFS bootblock. */ 626*12947SEnrico.Perla@Sun.COM if (do_version && !is_zfs(install_data.device.type)) { 627*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Versioning is only supported on" 628*12947SEnrico.Perla@Sun.COM " ZFS... skipping.\n")); 629*12947SEnrico.Perla@Sun.COM do_version = B_FALSE; 630*12947SEnrico.Perla@Sun.COM } 631*12947SEnrico.Perla@Sun.COM 632*12947SEnrico.Perla@Sun.COM /* 633*12947SEnrico.Perla@Sun.COM * is_update_necessary() will take care of checking if versioning and/or 634*12947SEnrico.Perla@Sun.COM * forcing the update have been specified. It will also emit a warning 635*12947SEnrico.Perla@Sun.COM * if a non-versioned update is attempted over a versioned bootblock. 636*12947SEnrico.Perla@Sun.COM */ 637*12947SEnrico.Perla@Sun.COM if (!is_update_necessary(&install_data, update_str)) { 638*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("bootblock version installed " 639*12947SEnrico.Perla@Sun.COM "on %s is more recent or identical\n" 640*12947SEnrico.Perla@Sun.COM "Use -F to override or install without the -u option\n"), 641*12947SEnrico.Perla@Sun.COM device_path); 642*12947SEnrico.Perla@Sun.COM ret = BC_NOUPDT; 643*12947SEnrico.Perla@Sun.COM goto out_dev; 644*12947SEnrico.Perla@Sun.COM } 645*12947SEnrico.Perla@Sun.COM 646*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("Ready to commit to disk\n"); 647*12947SEnrico.Perla@Sun.COM ret = commit_to_disk(&install_data, update_str); 648*12947SEnrico.Perla@Sun.COM 649*12947SEnrico.Perla@Sun.COM out_dev: 650*12947SEnrico.Perla@Sun.COM cleanup_device(&install_data.device); 651*12947SEnrico.Perla@Sun.COM out: 652*12947SEnrico.Perla@Sun.COM free(bootblock); 653*12947SEnrico.Perla@Sun.COM free(device_path); 654*12947SEnrico.Perla@Sun.COM return (ret); 655*12947SEnrico.Perla@Sun.COM } 656*12947SEnrico.Perla@Sun.COM 657*12947SEnrico.Perla@Sun.COM /* 658*12947SEnrico.Perla@Sun.COM * Retrieves from a device the extended information (einfo) associated to the 659*12947SEnrico.Perla@Sun.COM * installed bootblock. 660*12947SEnrico.Perla@Sun.COM * Expects one parameter, the device path, in the form: /dev/rdsk/c?[t?]d?s0. 661*12947SEnrico.Perla@Sun.COM * Returns: 662*12947SEnrico.Perla@Sun.COM * - BC_SUCCESS (and prints out einfo contents depending on 'flags') 663*12947SEnrico.Perla@Sun.COM * - BC_ERROR (on error) 664*12947SEnrico.Perla@Sun.COM * - BC_NOEINFO (no extended information available) 665*12947SEnrico.Perla@Sun.COM */ 666*12947SEnrico.Perla@Sun.COM static int 667*12947SEnrico.Perla@Sun.COM handle_getinfo(char *progname, char **argv) 668*12947SEnrico.Perla@Sun.COM { 669*12947SEnrico.Perla@Sun.COM 670*12947SEnrico.Perla@Sun.COM ib_data_t data; 671*12947SEnrico.Perla@Sun.COM ib_bootblock_t *bblock = &data.bootblock; 672*12947SEnrico.Perla@Sun.COM ib_device_t *device = &data.device; 673*12947SEnrico.Perla@Sun.COM bblk_einfo_t *einfo; 674*12947SEnrico.Perla@Sun.COM uint8_t flags = 0; 675*12947SEnrico.Perla@Sun.COM uint32_t size; 676*12947SEnrico.Perla@Sun.COM char *device_path; 677*12947SEnrico.Perla@Sun.COM int retval = BC_ERROR; 678*12947SEnrico.Perla@Sun.COM int ret; 679*12947SEnrico.Perla@Sun.COM 680*12947SEnrico.Perla@Sun.COM device_path = strdup(argv[0]); 681*12947SEnrico.Perla@Sun.COM if (!device_path) { 682*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Missing parameter")); 683*12947SEnrico.Perla@Sun.COM usage(progname); 684*12947SEnrico.Perla@Sun.COM goto out; 685*12947SEnrico.Perla@Sun.COM } 686*12947SEnrico.Perla@Sun.COM 687*12947SEnrico.Perla@Sun.COM bzero(&data, sizeof (ib_data_t)); 688*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("device path: %s\n", device_path); 689*12947SEnrico.Perla@Sun.COM 690*12947SEnrico.Perla@Sun.COM if (init_device(device, device_path) != BC_SUCCESS) { 691*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Unable to gather device " 692*12947SEnrico.Perla@Sun.COM "information from %s\n"), device_path); 693*12947SEnrico.Perla@Sun.COM goto out_dev; 694*12947SEnrico.Perla@Sun.COM } 695*12947SEnrico.Perla@Sun.COM 696*12947SEnrico.Perla@Sun.COM if (!is_zfs(device->type)) { 697*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Versioning only supported on " 698*12947SEnrico.Perla@Sun.COM "ZFS\n")); 699*12947SEnrico.Perla@Sun.COM goto out_dev; 700*12947SEnrico.Perla@Sun.COM } 701*12947SEnrico.Perla@Sun.COM 702*12947SEnrico.Perla@Sun.COM ret = read_bootblock_from_disk(device->fd, bblock); 703*12947SEnrico.Perla@Sun.COM if (ret == BC_ERROR) { 704*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Error reading bootblock from " 705*12947SEnrico.Perla@Sun.COM "%s\n"), device_path); 706*12947SEnrico.Perla@Sun.COM goto out_dev; 707*12947SEnrico.Perla@Sun.COM } 708*12947SEnrico.Perla@Sun.COM 709*12947SEnrico.Perla@Sun.COM if (ret == BC_NOEXTRA) { 710*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("No multiboot header found on %s, unable " 711*12947SEnrico.Perla@Sun.COM "to locate extra information area (old/non versioned " 712*12947SEnrico.Perla@Sun.COM "bootblock?) \n", device_path); 713*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("No extended information " 714*12947SEnrico.Perla@Sun.COM "found\n")); 715*12947SEnrico.Perla@Sun.COM retval = BC_NOEINFO; 716*12947SEnrico.Perla@Sun.COM goto out_dev; 717*12947SEnrico.Perla@Sun.COM } 718*12947SEnrico.Perla@Sun.COM 719*12947SEnrico.Perla@Sun.COM einfo = find_einfo(bblock->extra); 720*12947SEnrico.Perla@Sun.COM if (einfo == NULL) { 721*12947SEnrico.Perla@Sun.COM retval = BC_NOEINFO; 722*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("No extended information " 723*12947SEnrico.Perla@Sun.COM "found\n")); 724*12947SEnrico.Perla@Sun.COM goto out_dev; 725*12947SEnrico.Perla@Sun.COM } 726*12947SEnrico.Perla@Sun.COM 727*12947SEnrico.Perla@Sun.COM /* Print the extended information. */ 728*12947SEnrico.Perla@Sun.COM if (strip) 729*12947SEnrico.Perla@Sun.COM flags |= EINFO_EASY_PARSE; 730*12947SEnrico.Perla@Sun.COM if (verbose_dump) 731*12947SEnrico.Perla@Sun.COM flags |= EINFO_PRINT_HEADER; 732*12947SEnrico.Perla@Sun.COM 733*12947SEnrico.Perla@Sun.COM size = bblock->buf_size - P2ROUNDUP(bblock->file_size, 8) - 734*12947SEnrico.Perla@Sun.COM sizeof (multiboot_header_t); 735*12947SEnrico.Perla@Sun.COM print_einfo(flags, einfo, size); 736*12947SEnrico.Perla@Sun.COM retval = BC_SUCCESS; 737*12947SEnrico.Perla@Sun.COM 738*12947SEnrico.Perla@Sun.COM out_dev: 739*12947SEnrico.Perla@Sun.COM cleanup_device(&data.device); 740*12947SEnrico.Perla@Sun.COM out: 741*12947SEnrico.Perla@Sun.COM free(device_path); 742*12947SEnrico.Perla@Sun.COM return (retval); 743*12947SEnrico.Perla@Sun.COM 744*12947SEnrico.Perla@Sun.COM } 745*12947SEnrico.Perla@Sun.COM 746*12947SEnrico.Perla@Sun.COM /* 747*12947SEnrico.Perla@Sun.COM * Attempt to mirror (propagate) the current bootblock over the attaching disk. 748*12947SEnrico.Perla@Sun.COM * 749*12947SEnrico.Perla@Sun.COM * Returns: 750*12947SEnrico.Perla@Sun.COM * - BC_SUCCESS (a successful propagation happened) 751*12947SEnrico.Perla@Sun.COM * - BC_ERROR (an error occurred) 752*12947SEnrico.Perla@Sun.COM * - BC_NOEXTRA (it is not possible to dump the current bootblock since 753*12947SEnrico.Perla@Sun.COM * there is no multiboot information) 754*12947SEnrico.Perla@Sun.COM */ 755*12947SEnrico.Perla@Sun.COM static int 756*12947SEnrico.Perla@Sun.COM handle_mirror(char *progname, char **argv) 757*12947SEnrico.Perla@Sun.COM { 758*12947SEnrico.Perla@Sun.COM ib_data_t curr_data; 759*12947SEnrico.Perla@Sun.COM ib_data_t attach_data; 760*12947SEnrico.Perla@Sun.COM ib_device_t *curr_device = &curr_data.device; 761*12947SEnrico.Perla@Sun.COM ib_device_t *attach_device = &attach_data.device; 762*12947SEnrico.Perla@Sun.COM ib_bootblock_t *bblock_curr = &curr_data.bootblock; 763*12947SEnrico.Perla@Sun.COM ib_bootblock_t *bblock_attach = &attach_data.bootblock; 764*12947SEnrico.Perla@Sun.COM bblk_einfo_t *einfo_curr = NULL; 765*12947SEnrico.Perla@Sun.COM char *curr_device_path; 766*12947SEnrico.Perla@Sun.COM char *attach_device_path; 767*12947SEnrico.Perla@Sun.COM char *updt_str = NULL; 768*12947SEnrico.Perla@Sun.COM int retval = BC_ERROR; 769*12947SEnrico.Perla@Sun.COM int ret; 770*12947SEnrico.Perla@Sun.COM 771*12947SEnrico.Perla@Sun.COM curr_device_path = strdup(argv[0]); 772*12947SEnrico.Perla@Sun.COM attach_device_path = strdup(argv[1]); 773*12947SEnrico.Perla@Sun.COM 774*12947SEnrico.Perla@Sun.COM if (!curr_device_path || !attach_device_path) { 775*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Missing parameter")); 776*12947SEnrico.Perla@Sun.COM usage(progname); 777*12947SEnrico.Perla@Sun.COM goto out; 778*12947SEnrico.Perla@Sun.COM } 779*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("Current device path is: %s, attaching device path is: " 780*12947SEnrico.Perla@Sun.COM " %s\n", curr_device_path, attach_device_path); 781*12947SEnrico.Perla@Sun.COM 782*12947SEnrico.Perla@Sun.COM bzero(&curr_data, sizeof (ib_data_t)); 783*12947SEnrico.Perla@Sun.COM bzero(&attach_data, sizeof (ib_data_t)); 784*12947SEnrico.Perla@Sun.COM 785*12947SEnrico.Perla@Sun.COM if (tgt_fs_type != TARGET_IS_ZFS) { 786*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Mirroring is only supported on " 787*12947SEnrico.Perla@Sun.COM "ZFS\n")); 788*12947SEnrico.Perla@Sun.COM return (BC_ERROR); 789*12947SEnrico.Perla@Sun.COM } 790*12947SEnrico.Perla@Sun.COM 791*12947SEnrico.Perla@Sun.COM if (init_device(curr_device, curr_device_path) != BC_SUCCESS) { 792*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Unable to gather device " 793*12947SEnrico.Perla@Sun.COM "information from %s (current device)\n"), 794*12947SEnrico.Perla@Sun.COM curr_device_path); 795*12947SEnrico.Perla@Sun.COM goto out_currdev; 796*12947SEnrico.Perla@Sun.COM } 797*12947SEnrico.Perla@Sun.COM 798*12947SEnrico.Perla@Sun.COM if (init_device(attach_device, attach_device_path) != BC_SUCCESS) { 799*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Unable to gather device " 800*12947SEnrico.Perla@Sun.COM "information from %s (attaching device)\n"), 801*12947SEnrico.Perla@Sun.COM attach_device_path); 802*12947SEnrico.Perla@Sun.COM goto out_devs; 803*12947SEnrico.Perla@Sun.COM } 804*12947SEnrico.Perla@Sun.COM 805*12947SEnrico.Perla@Sun.COM ret = read_bootblock_from_disk(curr_device->fd, bblock_curr); 806*12947SEnrico.Perla@Sun.COM if (ret == BC_ERROR) { 807*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("Error reading bootblock from %s\n", 808*12947SEnrico.Perla@Sun.COM curr_device->path); 809*12947SEnrico.Perla@Sun.COM retval = BC_ERROR; 810*12947SEnrico.Perla@Sun.COM goto out_devs; 811*12947SEnrico.Perla@Sun.COM } 812*12947SEnrico.Perla@Sun.COM 813*12947SEnrico.Perla@Sun.COM if (ret == BC_NOEXTRA) { 814*12947SEnrico.Perla@Sun.COM BOOT_DEBUG("No multiboot header found on %s, unable to retrieve" 815*12947SEnrico.Perla@Sun.COM " the bootblock\n", curr_device->path); 816*12947SEnrico.Perla@Sun.COM retval = BC_NOEXTRA; 817*12947SEnrico.Perla@Sun.COM goto out_devs; 818*12947SEnrico.Perla@Sun.COM } 819*12947SEnrico.Perla@Sun.COM 820*12947SEnrico.Perla@Sun.COM einfo_curr = find_einfo(bblock_curr->extra); 821*12947SEnrico.Perla@Sun.COM if (einfo_curr != NULL) 822*12947SEnrico.Perla@Sun.COM updt_str = einfo_get_string(einfo_curr); 823*12947SEnrico.Perla@Sun.COM 824*12947SEnrico.Perla@Sun.COM retval = propagate_bootblock(&curr_data, &attach_data, updt_str); 825*12947SEnrico.Perla@Sun.COM cleanup_bootblock(bblock_curr); 826*12947SEnrico.Perla@Sun.COM cleanup_bootblock(bblock_attach); 827*12947SEnrico.Perla@Sun.COM out_devs: 828*12947SEnrico.Perla@Sun.COM cleanup_device(attach_device); 829*12947SEnrico.Perla@Sun.COM out_currdev: 830*12947SEnrico.Perla@Sun.COM cleanup_device(curr_device); 831*12947SEnrico.Perla@Sun.COM out: 832*12947SEnrico.Perla@Sun.COM free(curr_device_path); 833*12947SEnrico.Perla@Sun.COM free(attach_device_path); 834*12947SEnrico.Perla@Sun.COM return (retval); 835*12947SEnrico.Perla@Sun.COM } 836*12947SEnrico.Perla@Sun.COM 837*12947SEnrico.Perla@Sun.COM #define USAGE_STRING "Usage: %s [-h|-f|-F fstype|-u verstr] bootblk " \ 838*12947SEnrico.Perla@Sun.COM "raw-device\n" \ 839*12947SEnrico.Perla@Sun.COM "\t%s [-e|-V] -i -F zfs raw-device\n" \ 840*12947SEnrico.Perla@Sun.COM "\t%s -M -F zfs raw-device attach-raw-device\n" \ 841*12947SEnrico.Perla@Sun.COM "\tfstype is one of: 'ufs', 'hsfs' or 'zfs'\n" 842*12947SEnrico.Perla@Sun.COM 843*12947SEnrico.Perla@Sun.COM #define CANON_USAGE_STR gettext(USAGE_STRING) 844*12947SEnrico.Perla@Sun.COM 845*12947SEnrico.Perla@Sun.COM static void 846*12947SEnrico.Perla@Sun.COM usage(char *progname) 847*12947SEnrico.Perla@Sun.COM { 848*12947SEnrico.Perla@Sun.COM (void) fprintf(stdout, CANON_USAGE_STR, progname, progname, progname); 849*12947SEnrico.Perla@Sun.COM } 850*12947SEnrico.Perla@Sun.COM 851*12947SEnrico.Perla@Sun.COM int 852*12947SEnrico.Perla@Sun.COM main(int argc, char **argv) 853*12947SEnrico.Perla@Sun.COM { 854*12947SEnrico.Perla@Sun.COM int opt; 855*12947SEnrico.Perla@Sun.COM int params = 2; 856*12947SEnrico.Perla@Sun.COM int ret; 857*12947SEnrico.Perla@Sun.COM char *progname; 858*12947SEnrico.Perla@Sun.COM char **handle_args; 859*12947SEnrico.Perla@Sun.COM 860*12947SEnrico.Perla@Sun.COM (void) setlocale(LC_ALL, ""); 861*12947SEnrico.Perla@Sun.COM (void) textdomain(TEXT_DOMAIN); 862*12947SEnrico.Perla@Sun.COM 863*12947SEnrico.Perla@Sun.COM while ((opt = getopt(argc, argv, "F:efiVMndhu:")) != EOF) { 864*12947SEnrico.Perla@Sun.COM switch (opt) { 865*12947SEnrico.Perla@Sun.COM case 'F': 866*12947SEnrico.Perla@Sun.COM if (strcmp(optarg, "ufs") == 0) { 867*12947SEnrico.Perla@Sun.COM tgt_fs_type = TARGET_IS_UFS; 868*12947SEnrico.Perla@Sun.COM } else if (strcmp(optarg, "hsfs") == 0) { 869*12947SEnrico.Perla@Sun.COM tgt_fs_type = TARGET_IS_HSFS; 870*12947SEnrico.Perla@Sun.COM } else if (strcmp(optarg, "zfs") == 0) { 871*12947SEnrico.Perla@Sun.COM tgt_fs_type = TARGET_IS_ZFS; 872*12947SEnrico.Perla@Sun.COM } else { 873*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Wrong " 874*12947SEnrico.Perla@Sun.COM "filesystem specified\n\n")); 875*12947SEnrico.Perla@Sun.COM usage(argv[0]); 876*12947SEnrico.Perla@Sun.COM exit(BC_ERROR); 877*12947SEnrico.Perla@Sun.COM } 878*12947SEnrico.Perla@Sun.COM break; 879*12947SEnrico.Perla@Sun.COM case 'e': 880*12947SEnrico.Perla@Sun.COM strip = B_TRUE; 881*12947SEnrico.Perla@Sun.COM break; 882*12947SEnrico.Perla@Sun.COM case 'f': 883*12947SEnrico.Perla@Sun.COM force_update = B_TRUE; 884*12947SEnrico.Perla@Sun.COM break; 885*12947SEnrico.Perla@Sun.COM case 'V': 886*12947SEnrico.Perla@Sun.COM verbose_dump = B_TRUE; 887*12947SEnrico.Perla@Sun.COM break; 888*12947SEnrico.Perla@Sun.COM case 'i': 889*12947SEnrico.Perla@Sun.COM do_getinfo = B_TRUE; 890*12947SEnrico.Perla@Sun.COM params = 1; 891*12947SEnrico.Perla@Sun.COM break; 892*12947SEnrico.Perla@Sun.COM case 'u': 893*12947SEnrico.Perla@Sun.COM do_version = B_TRUE; 894*12947SEnrico.Perla@Sun.COM 895*12947SEnrico.Perla@Sun.COM update_str = malloc(strlen(optarg) + 1); 896*12947SEnrico.Perla@Sun.COM if (update_str == NULL) { 897*12947SEnrico.Perla@Sun.COM perror(gettext("Memory allocation failure")); 898*12947SEnrico.Perla@Sun.COM exit(BC_ERROR); 899*12947SEnrico.Perla@Sun.COM } 900*12947SEnrico.Perla@Sun.COM (void) strlcpy(update_str, optarg, strlen(optarg) + 1); 901*12947SEnrico.Perla@Sun.COM break; 902*12947SEnrico.Perla@Sun.COM case 'M': 903*12947SEnrico.Perla@Sun.COM do_mirror_bblk = B_TRUE; 904*12947SEnrico.Perla@Sun.COM break; 905*12947SEnrico.Perla@Sun.COM case 'h': 906*12947SEnrico.Perla@Sun.COM usage(argv[0]); 907*12947SEnrico.Perla@Sun.COM exit(BC_SUCCESS); 908*12947SEnrico.Perla@Sun.COM break; 909*12947SEnrico.Perla@Sun.COM case 'd': 910*12947SEnrico.Perla@Sun.COM boot_debug = B_TRUE; 911*12947SEnrico.Perla@Sun.COM break; 912*12947SEnrico.Perla@Sun.COM case 'n': 913*12947SEnrico.Perla@Sun.COM nowrite = B_TRUE; 914*12947SEnrico.Perla@Sun.COM break; 915*12947SEnrico.Perla@Sun.COM default: 916*12947SEnrico.Perla@Sun.COM /* fall through to process non-optional args */ 917*12947SEnrico.Perla@Sun.COM break; 918*12947SEnrico.Perla@Sun.COM } 919*12947SEnrico.Perla@Sun.COM } 920*12947SEnrico.Perla@Sun.COM 921*12947SEnrico.Perla@Sun.COM /* check arguments */ 922*12947SEnrico.Perla@Sun.COM if (argc != optind + params) { 923*12947SEnrico.Perla@Sun.COM usage(argv[0]); 924*12947SEnrico.Perla@Sun.COM exit(BC_ERROR); 925*12947SEnrico.Perla@Sun.COM } 926*12947SEnrico.Perla@Sun.COM progname = argv[0]; 927*12947SEnrico.Perla@Sun.COM handle_args = argv + optind; 928*12947SEnrico.Perla@Sun.COM 929*12947SEnrico.Perla@Sun.COM /* check options. */ 930*12947SEnrico.Perla@Sun.COM if (do_getinfo && do_mirror_bblk) { 931*12947SEnrico.Perla@Sun.COM (void) fprintf(stderr, gettext("Only one of -M and -i can be " 932*12947SEnrico.Perla@Sun.COM "specified at the same time\n")); 933*12947SEnrico.Perla@Sun.COM usage(progname); 934*12947SEnrico.Perla@Sun.COM exit(BC_ERROR); 935*12947SEnrico.Perla@Sun.COM } 936*12947SEnrico.Perla@Sun.COM 937*12947SEnrico.Perla@Sun.COM if (nowrite) 938*12947SEnrico.Perla@Sun.COM (void) fprintf(stdout, gettext("Dry run requested. Nothing will" 939*12947SEnrico.Perla@Sun.COM " be written to disk.\n")); 940*12947SEnrico.Perla@Sun.COM 941*12947SEnrico.Perla@Sun.COM if (do_getinfo) { 942*12947SEnrico.Perla@Sun.COM ret = handle_getinfo(progname, handle_args); 943*12947SEnrico.Perla@Sun.COM } else if (do_mirror_bblk) { 944*12947SEnrico.Perla@Sun.COM ret = handle_mirror(progname, handle_args); 945*12947SEnrico.Perla@Sun.COM } else { 946*12947SEnrico.Perla@Sun.COM ret = handle_install(progname, handle_args); 947*12947SEnrico.Perla@Sun.COM } 948*12947SEnrico.Perla@Sun.COM return (ret); 949*12947SEnrico.Perla@Sun.COM } 950