1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright (c) 1999,2001 by Sun Microsystems, Inc. 24*0Sstevel@tonic-gate * All rights reserved. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * fsck_pcfs -- common.c 31*0Sstevel@tonic-gate * All the routines in this file are being swiped directly from 32*0Sstevel@tonic-gate * mkfs_pcfs. Eventually this file should only exist in one place 33*0Sstevel@tonic-gate * and be part of a library that both mkfs and fsck link against. 34*0Sstevel@tonic-gate */ 35*0Sstevel@tonic-gate #include <stdio.h> 36*0Sstevel@tonic-gate #include <string.h> 37*0Sstevel@tonic-gate #include <unistd.h> 38*0Sstevel@tonic-gate #include <stdlib.h> 39*0Sstevel@tonic-gate #include <libintl.h> 40*0Sstevel@tonic-gate #include <sys/isa_defs.h> 41*0Sstevel@tonic-gate #include <sys/types.h> 42*0Sstevel@tonic-gate #include <sys/stat.h> 43*0Sstevel@tonic-gate #include <sys/fcntl.h> 44*0Sstevel@tonic-gate #include <sys/dktp/fdisk.h> 45*0Sstevel@tonic-gate #include <sys/fs/pc_fs.h> 46*0Sstevel@tonic-gate #include <sys/fs/pc_dir.h> 47*0Sstevel@tonic-gate #include <sys/fs/pc_label.h> 48*0Sstevel@tonic-gate #include "fsck_pcfs.h" 49*0Sstevel@tonic-gate #include "pcfs_common.h" 50*0Sstevel@tonic-gate #include "pcfs_bpb.h" 51*0Sstevel@tonic-gate 52*0Sstevel@tonic-gate /* 53*0Sstevel@tonic-gate * The assumption here is that _BIG_ENDIAN implies sparc, and 54*0Sstevel@tonic-gate * so in addition to swapping bytes we also have to construct 55*0Sstevel@tonic-gate * packed structures by hand to avoid bus errors due to improperly 56*0Sstevel@tonic-gate * aligned pointers. 57*0Sstevel@tonic-gate */ 58*0Sstevel@tonic-gate #ifdef _BIG_ENDIAN 59*0Sstevel@tonic-gate void swap_pack_grab32bpb(bpb_t *wbpb, struct _boot_sector *bsp); 60*0Sstevel@tonic-gate void swap_pack_grabbpb(bpb_t *wbpb, struct _boot_sector *bsp); 61*0Sstevel@tonic-gate #endif /* _BIG_ENDIAN */ 62*0Sstevel@tonic-gate 63*0Sstevel@tonic-gate /* 64*0Sstevel@tonic-gate * Global variables related to input questions 65*0Sstevel@tonic-gate */ 66*0Sstevel@tonic-gate extern int AlwaysYes; 67*0Sstevel@tonic-gate extern int AlwaysNo; 68*0Sstevel@tonic-gate 69*0Sstevel@tonic-gate int 70*0Sstevel@tonic-gate is_z_a_power_of_x_le_y(int x, int y, int z) 71*0Sstevel@tonic-gate { 72*0Sstevel@tonic-gate int ispower = 0; 73*0Sstevel@tonic-gate int pow = 1; 74*0Sstevel@tonic-gate 75*0Sstevel@tonic-gate do { 76*0Sstevel@tonic-gate if (pow == z) { 77*0Sstevel@tonic-gate ispower = 1; 78*0Sstevel@tonic-gate break; 79*0Sstevel@tonic-gate } 80*0Sstevel@tonic-gate pow *= x; 81*0Sstevel@tonic-gate } while (pow <= y); 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate return (ispower); 84*0Sstevel@tonic-gate } 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate /* 87*0Sstevel@tonic-gate * store_16_bits 88*0Sstevel@tonic-gate * Save the lower 16 bits of a 32 bit value (v) into the provided 89*0Sstevel@tonic-gate * buffer (pointed at by *bp), and increment the buffer pointer 90*0Sstevel@tonic-gate * as well. This way the routine can be called multiple times in 91*0Sstevel@tonic-gate * succession to fill buffers. The value is stored in little-endian 92*0Sstevel@tonic-gate * order. 93*0Sstevel@tonic-gate */ 94*0Sstevel@tonic-gate void 95*0Sstevel@tonic-gate store_16_bits(uchar_t **bp, uint32_t v) 96*0Sstevel@tonic-gate { 97*0Sstevel@tonic-gate uchar_t *l = *bp; 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate *l++ = v & 0xff; 100*0Sstevel@tonic-gate *l = (v >> 8) & 0xff; 101*0Sstevel@tonic-gate *bp += 2; 102*0Sstevel@tonic-gate } 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate void 105*0Sstevel@tonic-gate read_16_bits(uchar_t *bp, uint32_t *value) 106*0Sstevel@tonic-gate { 107*0Sstevel@tonic-gate *value = *bp++; 108*0Sstevel@tonic-gate *value += *bp << 8; 109*0Sstevel@tonic-gate } 110*0Sstevel@tonic-gate 111*0Sstevel@tonic-gate /* 112*0Sstevel@tonic-gate * store_32_bits 113*0Sstevel@tonic-gate * Save the 32 bit value (v) into the provided buffer (pointed 114*0Sstevel@tonic-gate * at by *bp), and increment the buffer pointer as well. This way 115*0Sstevel@tonic-gate * the routine can be called multiple times in succession to fill 116*0Sstevel@tonic-gate * buffers. The value is stored in little-endian order. 117*0Sstevel@tonic-gate */ 118*0Sstevel@tonic-gate void 119*0Sstevel@tonic-gate store_32_bits(uchar_t **bp, uint32_t v) 120*0Sstevel@tonic-gate { 121*0Sstevel@tonic-gate uchar_t *l = *bp; 122*0Sstevel@tonic-gate int b; 123*0Sstevel@tonic-gate 124*0Sstevel@tonic-gate for (b = 0; b < 4; b++) { 125*0Sstevel@tonic-gate *l++ = v & 0xff; 126*0Sstevel@tonic-gate v = v >> 8; 127*0Sstevel@tonic-gate } 128*0Sstevel@tonic-gate *bp += 4; 129*0Sstevel@tonic-gate } 130*0Sstevel@tonic-gate 131*0Sstevel@tonic-gate void 132*0Sstevel@tonic-gate read_32_bits(uchar_t *bp, uint32_t *value) 133*0Sstevel@tonic-gate { 134*0Sstevel@tonic-gate *value = *bp++; 135*0Sstevel@tonic-gate *value += *bp++ << 8; 136*0Sstevel@tonic-gate *value += *bp++ << 16; 137*0Sstevel@tonic-gate *value += *bp++ << 24; 138*0Sstevel@tonic-gate } 139*0Sstevel@tonic-gate 140*0Sstevel@tonic-gate /* 141*0Sstevel@tonic-gate * dump_bytes -- display bytes as hex numbers. 142*0Sstevel@tonic-gate * b is the pointer to the byte buffer 143*0Sstevel@tonic-gate * n is the number of bytes in the buffer 144*0Sstevel@tonic-gate */ 145*0Sstevel@tonic-gate /* Note: BPL = bytes to display per line */ 146*0Sstevel@tonic-gate #define BPL 16 147*0Sstevel@tonic-gate 148*0Sstevel@tonic-gate void 149*0Sstevel@tonic-gate dump_bytes(uchar_t *buf, int n) 150*0Sstevel@tonic-gate { 151*0Sstevel@tonic-gate int printedCount; 152*0Sstevel@tonic-gate int countdown = n; 153*0Sstevel@tonic-gate int countup = 0; 154*0Sstevel@tonic-gate int offset = 0; 155*0Sstevel@tonic-gate int byte; 156*0Sstevel@tonic-gate 157*0Sstevel@tonic-gate /* Display offset, 16 bytes per line, and printable ascii version */ 158*0Sstevel@tonic-gate while (countdown > 0) { 159*0Sstevel@tonic-gate printedCount = 0; 160*0Sstevel@tonic-gate (void) fprintf(stderr, "\n%06x: ", offset); 161*0Sstevel@tonic-gate /* 162*0Sstevel@tonic-gate * Print Hex value of characters in columns on left 163*0Sstevel@tonic-gate */ 164*0Sstevel@tonic-gate for (byte = 0; byte < BPL; byte++) { 165*0Sstevel@tonic-gate if (countup + byte < n) { 166*0Sstevel@tonic-gate (void) fprintf(stderr, 167*0Sstevel@tonic-gate "%02x ", (buf[countup + byte] & 0xff)); 168*0Sstevel@tonic-gate printedCount++; 169*0Sstevel@tonic-gate } else { 170*0Sstevel@tonic-gate (void) fprintf(stderr, " "); 171*0Sstevel@tonic-gate } 172*0Sstevel@tonic-gate } 173*0Sstevel@tonic-gate /* 174*0Sstevel@tonic-gate * Right side has the printable character or '.' for 175*0Sstevel@tonic-gate * unprintable for each column of the left. 176*0Sstevel@tonic-gate */ 177*0Sstevel@tonic-gate for (byte = 0; byte < BPL; byte++) { 178*0Sstevel@tonic-gate if ((countup + byte < n) && 179*0Sstevel@tonic-gate ((buf[countup + byte] >= ' ') && 180*0Sstevel@tonic-gate (buf[countup + byte] <= '~'))) { 181*0Sstevel@tonic-gate (void) fprintf(stderr, "%c", 182*0Sstevel@tonic-gate buf[countup + byte]); 183*0Sstevel@tonic-gate } else { 184*0Sstevel@tonic-gate (void) fprintf(stderr, "."); 185*0Sstevel@tonic-gate } 186*0Sstevel@tonic-gate } 187*0Sstevel@tonic-gate countup += printedCount; 188*0Sstevel@tonic-gate offset += printedCount; 189*0Sstevel@tonic-gate countdown -= printedCount; 190*0Sstevel@tonic-gate } 191*0Sstevel@tonic-gate (void) fprintf(stderr, "\n\n"); 192*0Sstevel@tonic-gate } 193*0Sstevel@tonic-gate 194*0Sstevel@tonic-gate /* 195*0Sstevel@tonic-gate * header_for_dump -- display simple header over what will be output. 196*0Sstevel@tonic-gate */ 197*0Sstevel@tonic-gate void 198*0Sstevel@tonic-gate header_for_dump(void) 199*0Sstevel@tonic-gate { 200*0Sstevel@tonic-gate int byte; 201*0Sstevel@tonic-gate 202*0Sstevel@tonic-gate (void) fprintf(stderr, "\n "); 203*0Sstevel@tonic-gate for (byte = 0; byte < BPL; byte++) 204*0Sstevel@tonic-gate (void) fprintf(stderr, "%02x ", byte); 205*0Sstevel@tonic-gate (void) fprintf(stderr, "\n "); 206*0Sstevel@tonic-gate byte = 3*BPL; 207*0Sstevel@tonic-gate while (byte-- > 0) 208*0Sstevel@tonic-gate (void) fprintf(stderr, "-"); 209*0Sstevel@tonic-gate } 210*0Sstevel@tonic-gate 211*0Sstevel@tonic-gate /* 212*0Sstevel@tonic-gate * We are basically (incorrectly) assuming that if you aren't running 213*0Sstevel@tonic-gate * on x86 the BPB has to be packed by hand AND that the bytes must 214*0Sstevel@tonic-gate * be swapped. One or both of these assumptions may one day be invalid. 215*0Sstevel@tonic-gate * (if they aren't already :-)) 216*0Sstevel@tonic-gate */ 217*0Sstevel@tonic-gate #ifdef _BIG_ENDIAN 218*0Sstevel@tonic-gate /* 219*0Sstevel@tonic-gate * swap_pack_grab{32}bpb 220*0Sstevel@tonic-gate * If not on an x86 we assume the structures making up the bpb 221*0Sstevel@tonic-gate * were not packed and that longs and shorts need to be byte swapped 222*0Sstevel@tonic-gate * (we've kept everything in host order up until now). A new architecture 223*0Sstevel@tonic-gate * might not need to swap or might not need to pack, in which case 224*0Sstevel@tonic-gate * new routines will have to be written. Of course if an architecture 225*0Sstevel@tonic-gate * supports both packing and little-endian host order, it can follow the 226*0Sstevel@tonic-gate * same path as the x86 code. 227*0Sstevel@tonic-gate */ 228*0Sstevel@tonic-gate void 229*0Sstevel@tonic-gate swap_pack_grabbpb(bpb_t *wbpb, struct _boot_sector *bsp) 230*0Sstevel@tonic-gate { 231*0Sstevel@tonic-gate uchar_t *grabp; 232*0Sstevel@tonic-gate 233*0Sstevel@tonic-gate grabp = (uchar_t *)&(bsp->bs_filler[ORIG_BPB_START_INDEX]); 234*0Sstevel@tonic-gate 235*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb.bytes_per_sector))[1] = *grabp++; 236*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb.bytes_per_sector))[0] = *grabp++; 237*0Sstevel@tonic-gate wbpb->bpb.sectors_per_cluster = *grabp++; 238*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb.resv_sectors))[1] = *grabp++; 239*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb.resv_sectors))[0] = *grabp++; 240*0Sstevel@tonic-gate wbpb->bpb.num_fats = *grabp++; 241*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb.num_root_entries))[1] = *grabp++; 242*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb.num_root_entries))[0] = *grabp++; 243*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb.sectors_in_volume))[1] = *grabp++; 244*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb.sectors_in_volume))[0] = *grabp++; 245*0Sstevel@tonic-gate wbpb->bpb.media = *grabp++; 246*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb.sectors_per_fat))[1] = *grabp++; 247*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb.sectors_per_fat))[0] = *grabp++; 248*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb.sectors_per_track))[1] = *grabp++; 249*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb.sectors_per_track))[0] = *grabp++; 250*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb.heads))[1] = *grabp++; 251*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb.heads))[0] = *grabp++; 252*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb.hidden_sectors))[3] = *grabp++; 253*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb.hidden_sectors))[2] = *grabp++; 254*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb.hidden_sectors))[1] = *grabp++; 255*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb.hidden_sectors))[0] = *grabp++; 256*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb.sectors_in_logical_volume))[3] = *grabp++; 257*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb.sectors_in_logical_volume))[2] = *grabp++; 258*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb.sectors_in_logical_volume))[1] = *grabp++; 259*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb.sectors_in_logical_volume))[0] = *grabp++; 260*0Sstevel@tonic-gate wbpb->ebpb.phys_drive_num = *grabp++; 261*0Sstevel@tonic-gate wbpb->ebpb.reserved = *grabp++; 262*0Sstevel@tonic-gate wbpb->ebpb.ext_signature = *grabp++; 263*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->ebpb.volume_id))[3] = *grabp++; 264*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->ebpb.volume_id))[2] = *grabp++; 265*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->ebpb.volume_id))[1] = *grabp++; 266*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->ebpb.volume_id))[0] = *grabp++; 267*0Sstevel@tonic-gate 268*0Sstevel@tonic-gate (void) strncpy((char *)wbpb->ebpb.volume_label, (char *)grabp, 11); 269*0Sstevel@tonic-gate grabp += 11; 270*0Sstevel@tonic-gate (void) strncpy((char *)wbpb->ebpb.type, (char *)grabp, 8); 271*0Sstevel@tonic-gate } 272*0Sstevel@tonic-gate 273*0Sstevel@tonic-gate void 274*0Sstevel@tonic-gate swap_pack_grab32bpb(bpb_t *wbpb, struct _boot_sector *bsp) 275*0Sstevel@tonic-gate { 276*0Sstevel@tonic-gate uchar_t *grabp; 277*0Sstevel@tonic-gate 278*0Sstevel@tonic-gate grabp = (uchar_t *)&(bsp->bs_filler[BPB_32_START_INDEX]); 279*0Sstevel@tonic-gate 280*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb32.big_sectors_per_fat))[3] = *grabp++; 281*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb32.big_sectors_per_fat))[2] = *grabp++; 282*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb32.big_sectors_per_fat))[1] = *grabp++; 283*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb32.big_sectors_per_fat))[0] = *grabp++; 284*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb32.ext_flags))[1] = *grabp++; 285*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb32.ext_flags))[0] = *grabp++; 286*0Sstevel@tonic-gate wbpb->bpb32.fs_vers_lo = *grabp++; 287*0Sstevel@tonic-gate wbpb->bpb32.fs_vers_hi = *grabp++; 288*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb32.root_dir_clust))[3] = *grabp++; 289*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb32.root_dir_clust))[2] = *grabp++; 290*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb32.root_dir_clust))[1] = *grabp++; 291*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb32.root_dir_clust))[0] = *grabp++; 292*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb32.fsinfosec))[1] = *grabp++; 293*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb32.fsinfosec))[0] = *grabp++; 294*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb32.backupboot))[1] = *grabp++; 295*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb32.backupboot))[0] = *grabp++; 296*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb32.reserved[0]))[1] = *grabp++; 297*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb32.reserved[0]))[0] = *grabp++; 298*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb32.reserved[1]))[1] = *grabp++; 299*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb32.reserved[1]))[0] = *grabp++; 300*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb32.reserved[2]))[1] = *grabp++; 301*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb32.reserved[2]))[0] = *grabp++; 302*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb32.reserved[3]))[1] = *grabp++; 303*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb32.reserved[3]))[0] = *grabp++; 304*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb32.reserved[4]))[1] = *grabp++; 305*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb32.reserved[4]))[0] = *grabp++; 306*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb32.reserved[5]))[1] = *grabp++; 307*0Sstevel@tonic-gate ((uchar_t *)&(wbpb->bpb32.reserved[5]))[0] = *grabp++; 308*0Sstevel@tonic-gate } 309*0Sstevel@tonic-gate #endif /* _BIG_ENDIAN */ 310*0Sstevel@tonic-gate 311*0Sstevel@tonic-gate int 312*0Sstevel@tonic-gate yes(void) 313*0Sstevel@tonic-gate { 314*0Sstevel@tonic-gate char *affirmative = gettext("yY"); 315*0Sstevel@tonic-gate char *a = affirmative; 316*0Sstevel@tonic-gate char input[80]; 317*0Sstevel@tonic-gate 318*0Sstevel@tonic-gate if (AlwaysYes) { 319*0Sstevel@tonic-gate (void) printf("y\n"); 320*0Sstevel@tonic-gate return (1); 321*0Sstevel@tonic-gate } else if (AlwaysNo) { 322*0Sstevel@tonic-gate (void) printf("n\n"); 323*0Sstevel@tonic-gate return (0); 324*0Sstevel@tonic-gate } 325*0Sstevel@tonic-gate if (fgets(input, sizeof (input), stdin) == NULL) { 326*0Sstevel@tonic-gate AlwaysNo = 1; 327*0Sstevel@tonic-gate (void) printf("n\n"); 328*0Sstevel@tonic-gate return (0); 329*0Sstevel@tonic-gate } 330*0Sstevel@tonic-gate while (*a) { 331*0Sstevel@tonic-gate if (input[0] == (int)*a) 332*0Sstevel@tonic-gate break; 333*0Sstevel@tonic-gate a++; 334*0Sstevel@tonic-gate } 335*0Sstevel@tonic-gate return ((int)*a); 336*0Sstevel@tonic-gate } 337*0Sstevel@tonic-gate 338*0Sstevel@tonic-gate char * 339*0Sstevel@tonic-gate stat_actual_disk(char *diskname, struct stat *info, char **suffix) 340*0Sstevel@tonic-gate { 341*0Sstevel@tonic-gate char *actualdisk; 342*0Sstevel@tonic-gate 343*0Sstevel@tonic-gate if (stat(diskname, info)) { 344*0Sstevel@tonic-gate /* 345*0Sstevel@tonic-gate * Device named on command line doesn't exist. That 346*0Sstevel@tonic-gate * probably means there is a partition-specifying 347*0Sstevel@tonic-gate * suffix attached to the actual disk name. 348*0Sstevel@tonic-gate */ 349*0Sstevel@tonic-gate if ((actualdisk = strdup(diskname)) == NULL) { 350*0Sstevel@tonic-gate (void) fprintf(stderr, 351*0Sstevel@tonic-gate gettext("Out of memory for disk name.\n")); 352*0Sstevel@tonic-gate exit(2); 353*0Sstevel@tonic-gate } 354*0Sstevel@tonic-gate if ((*suffix = strchr(actualdisk, ':')) != NULL) { 355*0Sstevel@tonic-gate **suffix = '\0'; 356*0Sstevel@tonic-gate (*suffix)++; 357*0Sstevel@tonic-gate } 358*0Sstevel@tonic-gate 359*0Sstevel@tonic-gate if (stat(actualdisk, info)) { 360*0Sstevel@tonic-gate perror(actualdisk); 361*0Sstevel@tonic-gate exit(2); 362*0Sstevel@tonic-gate } 363*0Sstevel@tonic-gate } else { 364*0Sstevel@tonic-gate if ((actualdisk = strdup(diskname)) == NULL) { 365*0Sstevel@tonic-gate (void) fprintf(stderr, 366*0Sstevel@tonic-gate gettext("Out of memory for disk name.\n")); 367*0Sstevel@tonic-gate exit(2); 368*0Sstevel@tonic-gate } 369*0Sstevel@tonic-gate } 370*0Sstevel@tonic-gate 371*0Sstevel@tonic-gate return (actualdisk); 372*0Sstevel@tonic-gate } 373*0Sstevel@tonic-gate 374*0Sstevel@tonic-gate extern void usage(void); 375*0Sstevel@tonic-gate 376*0Sstevel@tonic-gate void 377*0Sstevel@tonic-gate bad_arg(char *option) 378*0Sstevel@tonic-gate { 379*0Sstevel@tonic-gate (void) fprintf(stderr, 380*0Sstevel@tonic-gate gettext("Unrecognized option -o %s.\n"), option); 381*0Sstevel@tonic-gate usage(); 382*0Sstevel@tonic-gate exit(2); 383*0Sstevel@tonic-gate } 384*0Sstevel@tonic-gate 385*0Sstevel@tonic-gate void 386*0Sstevel@tonic-gate missing_arg(char *option) 387*0Sstevel@tonic-gate { 388*0Sstevel@tonic-gate (void) fprintf(stderr, 389*0Sstevel@tonic-gate gettext("Option %s requires a value.\n"), option); 390*0Sstevel@tonic-gate usage(); 391*0Sstevel@tonic-gate exit(3); 392*0Sstevel@tonic-gate } 393*0Sstevel@tonic-gate 394*0Sstevel@tonic-gate static int 395*0Sstevel@tonic-gate parse_drvnum(char *pn) 396*0Sstevel@tonic-gate { 397*0Sstevel@tonic-gate int drvnum; 398*0Sstevel@tonic-gate 399*0Sstevel@tonic-gate /* 400*0Sstevel@tonic-gate * Determine logical drive to seek after. 401*0Sstevel@tonic-gate */ 402*0Sstevel@tonic-gate if ((strlen(pn) == 1) && ((*pn >= 'c') && (*pn <= 'z'))) { 403*0Sstevel@tonic-gate drvnum = *pn - 'c' + 1; 404*0Sstevel@tonic-gate } else if ((*pn >= '0') && (*pn <= '9')) { 405*0Sstevel@tonic-gate char *d; 406*0Sstevel@tonic-gate int v = 0; 407*0Sstevel@tonic-gate 408*0Sstevel@tonic-gate d = pn; 409*0Sstevel@tonic-gate while ((*d != '\0') && (*d >= '0') && (*d <= '9')) { 410*0Sstevel@tonic-gate v *= 10; 411*0Sstevel@tonic-gate v += *d - '0'; 412*0Sstevel@tonic-gate d++; 413*0Sstevel@tonic-gate } 414*0Sstevel@tonic-gate if ((*d != '\0') || (v > 24)) { 415*0Sstevel@tonic-gate (void) fprintf(stderr, 416*0Sstevel@tonic-gate gettext("%s: bogus logical drive specification.\n"), 417*0Sstevel@tonic-gate pn); 418*0Sstevel@tonic-gate return (-1); 419*0Sstevel@tonic-gate } 420*0Sstevel@tonic-gate drvnum = v; 421*0Sstevel@tonic-gate } else if (strcmp(pn, "boot") == 0) { 422*0Sstevel@tonic-gate drvnum = 99; 423*0Sstevel@tonic-gate } else { 424*0Sstevel@tonic-gate (void) fprintf(stderr, 425*0Sstevel@tonic-gate gettext("%s: bogus logical drive specification.\n"), pn); 426*0Sstevel@tonic-gate return (-1); 427*0Sstevel@tonic-gate } 428*0Sstevel@tonic-gate 429*0Sstevel@tonic-gate return (drvnum); 430*0Sstevel@tonic-gate } 431*0Sstevel@tonic-gate 432*0Sstevel@tonic-gate /* 433*0Sstevel@tonic-gate * isDosDrive() 434*0Sstevel@tonic-gate * Boolean function. Give it the systid field for an fdisk partition 435*0Sstevel@tonic-gate * and it decides if that's a systid that describes a DOS drive. We 436*0Sstevel@tonic-gate * use systid values defined in sys/dktp/fdisk.h. 437*0Sstevel@tonic-gate */ 438*0Sstevel@tonic-gate static int 439*0Sstevel@tonic-gate isDosDrive(uchar_t checkMe) 440*0Sstevel@tonic-gate { 441*0Sstevel@tonic-gate return ((checkMe == DOSOS12) || (checkMe == DOSOS16) || 442*0Sstevel@tonic-gate (checkMe == DOSHUGE) || (checkMe == FDISK_WINDOWS) || 443*0Sstevel@tonic-gate (checkMe == FDISK_EXT_WIN) || (checkMe == FDISK_FAT95) || 444*0Sstevel@tonic-gate (checkMe == DIAGPART)); 445*0Sstevel@tonic-gate } 446*0Sstevel@tonic-gate 447*0Sstevel@tonic-gate /* 448*0Sstevel@tonic-gate * isDosExtended() 449*0Sstevel@tonic-gate * Boolean function. Give it the systid field for an fdisk partition 450*0Sstevel@tonic-gate * and it decides if that's a systid that describes an extended DOS 451*0Sstevel@tonic-gate * partition. 452*0Sstevel@tonic-gate */ 453*0Sstevel@tonic-gate static int 454*0Sstevel@tonic-gate isDosExtended(uchar_t checkMe) 455*0Sstevel@tonic-gate { 456*0Sstevel@tonic-gate return ((checkMe == EXTDOS) || (checkMe == FDISK_EXTLBA)); 457*0Sstevel@tonic-gate } 458*0Sstevel@tonic-gate 459*0Sstevel@tonic-gate /* 460*0Sstevel@tonic-gate * isBootPart() 461*0Sstevel@tonic-gate * Boolean function. Give it the systid field for an fdisk partition 462*0Sstevel@tonic-gate * and it decides if that's a systid that describes a Solaris boot 463*0Sstevel@tonic-gate * partition. 464*0Sstevel@tonic-gate */ 465*0Sstevel@tonic-gate static int 466*0Sstevel@tonic-gate isBootPart(uchar_t checkMe) 467*0Sstevel@tonic-gate { 468*0Sstevel@tonic-gate return (checkMe == X86BOOT); 469*0Sstevel@tonic-gate } 470*0Sstevel@tonic-gate 471*0Sstevel@tonic-gate off64_t 472*0Sstevel@tonic-gate findPartitionOffset(int fd, char *ldrive) 473*0Sstevel@tonic-gate { 474*0Sstevel@tonic-gate struct ipart part[FD_NUMPART]; 475*0Sstevel@tonic-gate struct mboot extmboot; 476*0Sstevel@tonic-gate struct mboot mb; 477*0Sstevel@tonic-gate daddr_t xstartsect; 478*0Sstevel@tonic-gate off64_t nextseek = 0; 479*0Sstevel@tonic-gate off64_t lastseek = 0; 480*0Sstevel@tonic-gate off64_t found = 0; 481*0Sstevel@tonic-gate off64_t error = -1; 482*0Sstevel@tonic-gate int logicalDriveCount = 0; 483*0Sstevel@tonic-gate int extendedPart = -1; 484*0Sstevel@tonic-gate int primaryPart = -1; 485*0Sstevel@tonic-gate int bootPart = -1; 486*0Sstevel@tonic-gate int xnumsect = -1; 487*0Sstevel@tonic-gate int drvnum; 488*0Sstevel@tonic-gate int driveIndex; 489*0Sstevel@tonic-gate int i; 490*0Sstevel@tonic-gate /* 491*0Sstevel@tonic-gate * Count of drives in the current extended partition's 492*0Sstevel@tonic-gate * FDISK table, and indexes of the drives themselves. 493*0Sstevel@tonic-gate */ 494*0Sstevel@tonic-gate int extndDrives[FD_NUMPART]; 495*0Sstevel@tonic-gate int numDrives = 0; 496*0Sstevel@tonic-gate /* 497*0Sstevel@tonic-gate * Count of drives (beyond primary) in master boot record's 498*0Sstevel@tonic-gate * FDISK table, and indexes of the drives themselves. 499*0Sstevel@tonic-gate */ 500*0Sstevel@tonic-gate int extraDrives[FD_NUMPART]; 501*0Sstevel@tonic-gate int numExtraDrives = 0; 502*0Sstevel@tonic-gate 503*0Sstevel@tonic-gate if ((drvnum = parse_drvnum(ldrive)) < 0) 504*0Sstevel@tonic-gate return (error); 505*0Sstevel@tonic-gate 506*0Sstevel@tonic-gate if (read(fd, &mb, sizeof (mb)) != sizeof (mb)) { 507*0Sstevel@tonic-gate (void) fprintf(stderr, 508*0Sstevel@tonic-gate gettext("Couldn't read a Master Boot Record\n")); 509*0Sstevel@tonic-gate return (error); 510*0Sstevel@tonic-gate } 511*0Sstevel@tonic-gate 512*0Sstevel@tonic-gate if (ltohs(mb.signature) != BOOTSECSIG) { 513*0Sstevel@tonic-gate (void) fprintf(stderr, 514*0Sstevel@tonic-gate gettext("Bad signature on master boot record (%x)\n"), 515*0Sstevel@tonic-gate ltohs(mb.signature)); 516*0Sstevel@tonic-gate return (error); 517*0Sstevel@tonic-gate } 518*0Sstevel@tonic-gate 519*0Sstevel@tonic-gate /* 520*0Sstevel@tonic-gate * Copy partition table into memory 521*0Sstevel@tonic-gate */ 522*0Sstevel@tonic-gate (void) memcpy(part, mb.parts, sizeof (part)); 523*0Sstevel@tonic-gate 524*0Sstevel@tonic-gate /* 525*0Sstevel@tonic-gate * Get a summary of what is in the Master FDISK table. 526*0Sstevel@tonic-gate * Normally we expect to find one partition marked as a DOS drive. 527*0Sstevel@tonic-gate * This partition is the one Windows calls the primary dos partition. 528*0Sstevel@tonic-gate * If the machine has any logical drives then we also expect 529*0Sstevel@tonic-gate * to find a partition marked as an extended DOS partition. 530*0Sstevel@tonic-gate * 531*0Sstevel@tonic-gate * Sometimes we'll find multiple partitions marked as DOS drives. 532*0Sstevel@tonic-gate * The Solaris fdisk program allows these partitions 533*0Sstevel@tonic-gate * to be created, but Windows fdisk no longer does. We still need 534*0Sstevel@tonic-gate * to support these, though, since Windows does. We also need to fix 535*0Sstevel@tonic-gate * our fdisk to behave like the Windows version. 536*0Sstevel@tonic-gate * 537*0Sstevel@tonic-gate * It turns out that some off-the-shelf media have *only* an 538*0Sstevel@tonic-gate * Extended partition, so we need to deal with that case as 539*0Sstevel@tonic-gate * well. 540*0Sstevel@tonic-gate * 541*0Sstevel@tonic-gate * Only a single (the first) Extended or Boot Partition will 542*0Sstevel@tonic-gate * be recognized. Any others will be ignored. 543*0Sstevel@tonic-gate */ 544*0Sstevel@tonic-gate for (i = 0; i < FD_NUMPART; i++) { 545*0Sstevel@tonic-gate if (isDosDrive(part[i].systid)) { 546*0Sstevel@tonic-gate if (primaryPart < 0) { 547*0Sstevel@tonic-gate logicalDriveCount++; 548*0Sstevel@tonic-gate primaryPart = i; 549*0Sstevel@tonic-gate } else { 550*0Sstevel@tonic-gate extraDrives[numExtraDrives++] = i; 551*0Sstevel@tonic-gate } 552*0Sstevel@tonic-gate continue; 553*0Sstevel@tonic-gate } 554*0Sstevel@tonic-gate if ((extendedPart < 0) && isDosExtended(part[i].systid)) { 555*0Sstevel@tonic-gate extendedPart = i; 556*0Sstevel@tonic-gate continue; 557*0Sstevel@tonic-gate } 558*0Sstevel@tonic-gate if ((bootPart < 0) && isBootPart(part[i].systid)) { 559*0Sstevel@tonic-gate bootPart = i; 560*0Sstevel@tonic-gate continue; 561*0Sstevel@tonic-gate } 562*0Sstevel@tonic-gate } 563*0Sstevel@tonic-gate 564*0Sstevel@tonic-gate if (drvnum == BOOT_PARTITION_DRIVE) { 565*0Sstevel@tonic-gate if (bootPart < 0) { 566*0Sstevel@tonic-gate (void) fprintf(stderr, 567*0Sstevel@tonic-gate gettext("No boot partition found on drive\n")); 568*0Sstevel@tonic-gate return (error); 569*0Sstevel@tonic-gate } 570*0Sstevel@tonic-gate found = ltohi(part[bootPart].relsect) * BPSEC; 571*0Sstevel@tonic-gate return (found); 572*0Sstevel@tonic-gate } 573*0Sstevel@tonic-gate 574*0Sstevel@tonic-gate if (drvnum == PRIMARY_DOS_DRIVE && primaryPart >= 0) { 575*0Sstevel@tonic-gate found = ltohi(part[primaryPart].relsect) * BPSEC; 576*0Sstevel@tonic-gate return (found); 577*0Sstevel@tonic-gate } 578*0Sstevel@tonic-gate 579*0Sstevel@tonic-gate /* 580*0Sstevel@tonic-gate * We are not looking for the C: drive (or there was no primary 581*0Sstevel@tonic-gate * drive found), so we had better have an extended partition or 582*0Sstevel@tonic-gate * extra drives in the Master FDISK table. 583*0Sstevel@tonic-gate */ 584*0Sstevel@tonic-gate if ((extendedPart < 0) && (numExtraDrives == 0)) { 585*0Sstevel@tonic-gate (void) fprintf(stderr, 586*0Sstevel@tonic-gate gettext("No such logical drive " 587*0Sstevel@tonic-gate "(missing extended partition entry)\n")); 588*0Sstevel@tonic-gate return (error); 589*0Sstevel@tonic-gate } 590*0Sstevel@tonic-gate 591*0Sstevel@tonic-gate if (extendedPart >= 0) { 592*0Sstevel@tonic-gate nextseek = xstartsect = ltohi(part[extendedPart].relsect); 593*0Sstevel@tonic-gate xnumsect = ltohi(part[extendedPart].numsect); 594*0Sstevel@tonic-gate do { 595*0Sstevel@tonic-gate /* 596*0Sstevel@tonic-gate * If the seek would not cause us to change 597*0Sstevel@tonic-gate * position on the drive, then we're out of 598*0Sstevel@tonic-gate * extended partitions to examine. 599*0Sstevel@tonic-gate */ 600*0Sstevel@tonic-gate if (nextseek == lastseek) 601*0Sstevel@tonic-gate break; 602*0Sstevel@tonic-gate logicalDriveCount += numDrives; 603*0Sstevel@tonic-gate /* 604*0Sstevel@tonic-gate * Seek the next extended partition, and find 605*0Sstevel@tonic-gate * logical drives within it. 606*0Sstevel@tonic-gate */ 607*0Sstevel@tonic-gate if (lseek64(fd, nextseek * BPSEC, SEEK_SET) < 0 || 608*0Sstevel@tonic-gate read(fd, &extmboot, sizeof (extmboot)) != 609*0Sstevel@tonic-gate sizeof (extmboot)) { 610*0Sstevel@tonic-gate perror(gettext("Unable to read extended " 611*0Sstevel@tonic-gate "partition record")); 612*0Sstevel@tonic-gate return (error); 613*0Sstevel@tonic-gate } 614*0Sstevel@tonic-gate (void) memcpy(part, extmboot.parts, sizeof (part)); 615*0Sstevel@tonic-gate lastseek = nextseek; 616*0Sstevel@tonic-gate if (ltohs(extmboot.signature) != MBB_MAGIC) { 617*0Sstevel@tonic-gate (void) fprintf(stderr, 618*0Sstevel@tonic-gate gettext("Bad signature on " 619*0Sstevel@tonic-gate "extended partition\n")); 620*0Sstevel@tonic-gate return (error); 621*0Sstevel@tonic-gate } 622*0Sstevel@tonic-gate /* 623*0Sstevel@tonic-gate * Count up drives, and track where the next 624*0Sstevel@tonic-gate * extended partition is in case we need it. We 625*0Sstevel@tonic-gate * are expecting only one extended partition. If 626*0Sstevel@tonic-gate * there is more than one we'll only go to the 627*0Sstevel@tonic-gate * first one we see, but warn about ignoring. 628*0Sstevel@tonic-gate */ 629*0Sstevel@tonic-gate numDrives = 0; 630*0Sstevel@tonic-gate for (i = 0; i < FD_NUMPART; i++) { 631*0Sstevel@tonic-gate if (isDosDrive(part[i].systid)) { 632*0Sstevel@tonic-gate extndDrives[numDrives++] = i; 633*0Sstevel@tonic-gate continue; 634*0Sstevel@tonic-gate } else if (isDosExtended(part[i].systid)) { 635*0Sstevel@tonic-gate if (nextseek != lastseek) { 636*0Sstevel@tonic-gate /* 637*0Sstevel@tonic-gate * Already found an extended 638*0Sstevel@tonic-gate * partition in this table. 639*0Sstevel@tonic-gate */ 640*0Sstevel@tonic-gate (void) fprintf(stderr, 641*0Sstevel@tonic-gate gettext("WARNING: " 642*0Sstevel@tonic-gate "Ignoring unexpected " 643*0Sstevel@tonic-gate "additional extended " 644*0Sstevel@tonic-gate "partition")); 645*0Sstevel@tonic-gate continue; 646*0Sstevel@tonic-gate } 647*0Sstevel@tonic-gate nextseek = xstartsect + 648*0Sstevel@tonic-gate ltohi(part[i].relsect); 649*0Sstevel@tonic-gate continue; 650*0Sstevel@tonic-gate } 651*0Sstevel@tonic-gate } 652*0Sstevel@tonic-gate } while (drvnum > logicalDriveCount + numDrives); 653*0Sstevel@tonic-gate 654*0Sstevel@tonic-gate if (drvnum <= logicalDriveCount + numDrives) { 655*0Sstevel@tonic-gate /* 656*0Sstevel@tonic-gate * The number of logical drives we've found thus 657*0Sstevel@tonic-gate * far is enough to get us to the one we were 658*0Sstevel@tonic-gate * searching for. 659*0Sstevel@tonic-gate */ 660*0Sstevel@tonic-gate driveIndex = logicalDriveCount + numDrives - drvnum; 661*0Sstevel@tonic-gate found = 662*0Sstevel@tonic-gate ltohi(part[extndDrives[driveIndex]].relsect) + 663*0Sstevel@tonic-gate lastseek; 664*0Sstevel@tonic-gate if (found > (xstartsect + xnumsect)) { 665*0Sstevel@tonic-gate (void) fprintf(stderr, 666*0Sstevel@tonic-gate gettext("Logical drive start sector (%d) " 667*0Sstevel@tonic-gate "is not within the partition!\n"), found); 668*0Sstevel@tonic-gate return (error); 669*0Sstevel@tonic-gate } else { 670*0Sstevel@tonic-gate found *= BPSEC; 671*0Sstevel@tonic-gate } 672*0Sstevel@tonic-gate return (found); 673*0Sstevel@tonic-gate } else { 674*0Sstevel@tonic-gate /* 675*0Sstevel@tonic-gate * We ran out of extended dos partition 676*0Sstevel@tonic-gate * drives. The only hope now is to go 677*0Sstevel@tonic-gate * back to extra drives defined in the master 678*0Sstevel@tonic-gate * fdisk table. But we overwrote that table 679*0Sstevel@tonic-gate * already, so we must load it in again. 680*0Sstevel@tonic-gate */ 681*0Sstevel@tonic-gate logicalDriveCount += numDrives; 682*0Sstevel@tonic-gate (void) memcpy(part, mb.parts, sizeof (part)); 683*0Sstevel@tonic-gate } 684*0Sstevel@tonic-gate } 685*0Sstevel@tonic-gate /* 686*0Sstevel@tonic-gate * Still haven't found the drive, is it an extra 687*0Sstevel@tonic-gate * drive defined in the main FDISK table? 688*0Sstevel@tonic-gate */ 689*0Sstevel@tonic-gate if (drvnum <= logicalDriveCount + numExtraDrives) { 690*0Sstevel@tonic-gate driveIndex = logicalDriveCount + numExtraDrives - drvnum; 691*0Sstevel@tonic-gate found = ltohi(part[extraDrives[driveIndex]].relsect) * BPSEC; 692*0Sstevel@tonic-gate return (found); 693*0Sstevel@tonic-gate } 694*0Sstevel@tonic-gate return (error); 695*0Sstevel@tonic-gate } 696