1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright (c) 2011 Gary Mills 23 * 24 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 25 * Use is subject to license terms. 26 */ 27 28 #include <sys/types.h> 29 #include <ctype.h> 30 #include <unistd.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <errno.h> 35 #include <fcntl.h> 36 #include <libintl.h> 37 #include <locale.h> 38 #include <sys/fdio.h> 39 #include <sys/dktp/fdisk.h> 40 #include <sys/dkio.h> 41 #include <sys/vtoc.h> 42 #include <sys/efi_partition.h> 43 #include <sys/sysmacros.h> 44 #include "mkfs_pcfs.h" 45 #include <sys/fs/pc_fs.h> 46 #include <sys/fs/pc_dir.h> 47 #include <sys/fs/pc_label.h> 48 #include <macros.h> 49 50 /* 51 * mkfs (for pcfs) 52 * 53 * Install a boot block, FAT, and (if desired) the first resident 54 * of the new fs. 55 * 56 * XXX -- floppy opens need O_NDELAY? 57 */ 58 #define IN_RANGE(n, x, y) (((n) >= (x)) && ((n) <= (y))) 59 #define DEFAULT_LABEL "NONAME" 60 61 static char *BootBlkFn = NULL; 62 static char *DiskName = NULL; 63 static char *FirstFn = NULL; 64 static char *Label = NULL; 65 static char Firstfileattr = 0x20; 66 static int Outputtofile = 0; 67 static int SunBPBfields = 0; 68 static int GetFsParams = 0; 69 static int Fatentsize = 0; 70 static int Imagesize = 3; 71 static int Notreally = 0; 72 static int Verbose = 0; 73 static int MakeFAT32 = 0; 74 75 /* 76 * If there is an FDISK entry for the device where we're about to 77 * make the file system, we ought to make a file system that has the 78 * same size FAT as the FDISK table claims. We track the size FDISK 79 * thinks in this variable. 80 */ 81 static int FdiskFATsize = 0; 82 83 static int GetSize = 1; /* Unless we're given as arg, must look it up */ 84 static ulong_t TotSize; /* Total size of FS in # of sectors */ 85 static int GetSPC = 1; /* Unless we're given as arg, must calculate */ 86 static ulong_t SecPerClust; /* # of sectors per cluster */ 87 static int GetOffset = 1; /* Unless we're given as arg, must look it up */ 88 static ulong_t RelOffset; /* Relative start sector (hidden sectors) */ 89 static int GetSPT = 1; /* Unless we're given as arg, must look it up */ 90 static ushort_t SecPerTrk; /* # of sectors per track */ 91 static int GetTPC = 1; /* Unless we're given as arg, must look it up */ 92 static ushort_t TrkPerCyl; /* # of tracks per cylinder */ 93 static int GetResrvd = 1; /* Unless we're given as arg, must calculate */ 94 static int Resrvd; /* Number of reserved sectors */ 95 static int GetBPF = 1; /* Unless we're given as arg, must calculate */ 96 static int BitsPerFAT; /* Total size of FS in # of sectors */ 97 98 static ulong_t TotalClusters; /* Computed total number of clusters */ 99 100 /* 101 * Unless we are told otherwise, we should use fdisk table for non-diskettes. 102 */ 103 static int DontUseFdisk = 0; 104 105 /* 106 * Function prototypes 107 */ 108 #ifndef i386 109 static void swap_pack_grabsebpb(bpb_t *wbpb, struct _boot_sector *bsp); 110 static void swap_pack_bpb32cpy(struct _boot_sector32 *bsp, bpb_t *wbpb); 111 static void swap_pack_sebpbcpy(struct _boot_sector *bsp, bpb_t *wbpb); 112 static void swap_pack_grabbpb(bpb_t *wbpb, struct _boot_sector *bsp); 113 static void swap_pack_bpbcpy(struct _boot_sector *bsp, bpb_t *wbpb); 114 #endif 115 116 static uchar_t *build_rootdir(bpb_t *wbpb, char *ffn, int fffd, 117 ulong_t ffsize, pc_cluster32_t ffstart, ulong_t *rdirsize); 118 static uchar_t *build_fat(bpb_t *wbpb, struct fat_od_fsi *fsinfop, 119 ulong_t bootblksize, ulong_t *fatsize, char *ffn, int *fffd, 120 ulong_t *ffsize, pc_cluster32_t *ffstartclust); 121 122 static char *stat_actual_disk(char *diskname, struct stat *info, char **suffix); 123 124 static void compare_existing_with_computed(int fd, char *suffix, 125 bpb_t *wbpb, int *prtsize, int *prtspc, int *prtbpf, int *prtnsect, 126 int *prtntrk, int *prtfdisk, int *prthidden, int *prtrsrvd, 127 int *dashos); 128 static void print_reproducing_command(int fd, char *actualdisk, char *suffix, 129 bpb_t *wbpb); 130 static void compute_file_area_size(bpb_t *wbpb); 131 static void write_fat32_bootstuff(int fd, boot_sector_t *bsp, 132 struct fat_od_fsi *fsinfop, off64_t seekto); 133 static void sanity_check_options(int argc, int optind); 134 static void compute_cluster_size(bpb_t *wbpb); 135 static void find_fixed_details(int fd, bpb_t *wbpb); 136 static void dirent_fname_fill(struct pcdir *dep, char *fn); 137 static void floppy_bpb_fillin(bpb_t *wbpb, 138 int diam, int hds, int spt); 139 static void read_existing_bpb(int fd, bpb_t *wbpb); 140 static void warn_funky_fatsize(void); 141 static void warn_funky_floppy(void); 142 static void dirent_time_fill(struct pcdir *dep); 143 static void parse_suboptions(char *optsstr); 144 static void header_for_dump(void); 145 static void write_bootsects(int fd, boot_sector_t *bsp, bpb_t *wbpb, 146 struct fat_od_fsi *fsinfop, off64_t seekto); 147 static void fill_bpb_sizes(bpb_t *wbpb, struct ipart part[], 148 int partno, off64_t offset); 149 static void set_fat_string(bpb_t *wbpb, int fatsize); 150 static void partn_lecture(char *dn); 151 static void store_16_bits(uchar_t **bp, uint32_t v); 152 static void store_32_bits(uchar_t **bp, uint32_t v); 153 static void lookup_floppy(struct fd_char *fdchar, bpb_t *wbpb); 154 static void label_volume(char *lbl, bpb_t *wbpb); 155 static void mark_cluster(uchar_t *fatp, pc_cluster32_t clustnum, 156 uint32_t value); 157 static void missing_arg(char *option); 158 static void dashm_bail(int fd); 159 static void dump_bytes(uchar_t *, int); 160 static void write_rest(bpb_t *wbpb, char *efn, 161 int dfd, int sfd, int remaining); 162 static void write_fat(int fd, off64_t seekto, char *fn, char *lbl, 163 char *ffn, bpb_t *wbpb); 164 static void bad_arg(char *option); 165 static void usage(void); 166 167 static int prepare_image_file(char *fn, bpb_t *wbpb); 168 static int verify_bootblkfile(char *fn, boot_sector_t *bs, 169 ulong_t *blkfilesize); 170 static int open_and_examine(char *dn, bpb_t *wbpb); 171 static int verify_firstfile(char *fn, ulong_t *filesize); 172 static int lookup_FAT_size(uchar_t partid); 173 static int open_and_seek(char *dn, bpb_t *wbpb, off64_t *seekto); 174 static int warn_mismatch(char *desc, char *src, int expect, int assigned); 175 static int copy_bootblk(char *fn, boot_sector_t *bootsect, 176 ulong_t *bootblksize); 177 static int parse_drvnum(char *pn); 178 static int seek_nofdisk(int fd, bpb_t *wbpb, off64_t *seekto); 179 static int ask_nicely(char *special); 180 static int seek_partn(int fd, char *pn, bpb_t *wbpb, off64_t *seekto); 181 static int yes(void); 182 183 /* 184 * usage 185 * 186 * Display usage message and exit. 187 */ 188 static 189 void 190 usage(void) 191 { 192 (void) fprintf(stderr, 193 gettext("pcfs usage: mkfs [-F FSType] [-V] [-m] " 194 "[-o specific_options] special\n")); 195 196 (void) fprintf(stderr, 197 gettext(" -V: print this command line and return\n" 198 " -m: dump command line used to create a FAT on this media\n" 199 "\t(other options are ignored if this option is chosen).\n" 200 " -o: pcfs_specific_options:\n" 201 "\t'pcfs_specific_options' is a comma separated list\n" 202 "\tincluding one or more of the following options:\n" 203 "\t N,v,r,h,s,b=label,B=filename,i=filename,\n" 204 "\t spc=n,fat=n,nsect=n,ntrack=n,nofdisk,size=n,\n" 205 "\t reserve=n,hidden=n\n\n")); 206 207 (void) fprintf(stderr, 208 gettext("'Special' should specify a raw diskette " 209 "or raw fixed disk device. \"Fixed\"\n" 210 "disks (which include high-capacity removable " 211 "media such as Zip disks)\n" 212 "may be further qualified with a logical " 213 "drive specifier.\n" 214 "Examples are: /dev/rdiskette and " 215 "/dev/rdsk/c0t0d0p0:c\n")); 216 exit(1); 217 } 218 219 static 220 int 221 yes(void) 222 { 223 char *affirmative = gettext("yY"); 224 char *a = affirmative; 225 int b; 226 227 b = getchar(); 228 while (b == '\n' && b != '\0' && b != EOF) 229 b = getchar(); 230 while (*a) { 231 if (b == (int)*a) 232 break; 233 a++; 234 } 235 return (*a); 236 } 237 238 static 239 int 240 ask_nicely(char *special) 241 { 242 /* 243 * 4228473 - No way to non-interactively make a pcfs filesystem 244 * 245 * If we don't have an input TTY, or we aren't really doing 246 * anything, then don't ask questions. Assume a yes answer 247 * to any questions we would ask. 248 */ 249 if (Notreally || !isatty(fileno(stdin))) 250 return (1); 251 252 (void) printf( 253 gettext("Construct a new FAT file system on %s: (y/n)? "), special); 254 (void) fflush(stdout); 255 return (yes()); 256 } 257 258 /* 259 * store_16_bits 260 * Save the lower 16 bits of a 32 bit value (v) into the provided 261 * buffer (pointed at by *bp), and increment the buffer pointer 262 * as well. This way the routine can be called multiple times in 263 * succession to fill buffers. The value is stored in little-endian 264 * order. 265 */ 266 static 267 void 268 store_16_bits(uchar_t **bp, uint32_t v) 269 { 270 uchar_t *l = *bp; 271 272 *l++ = v & 0xff; 273 *l = (v >> 8) & 0xff; 274 *bp += 2; 275 } 276 277 /* 278 * store_32_bits 279 * Save the 32 bit value (v) into the provided buffer (pointed 280 * at by *bp), and increment the buffer pointer as well. This way 281 * the routine can be called multiple times in succession to fill 282 * buffers. The value is stored in little-endian order. 283 */ 284 static 285 void 286 store_32_bits(uchar_t **bp, uint32_t v) 287 { 288 uchar_t *l = *bp; 289 int b; 290 291 for (b = 0; b < 4; b++) { 292 *l++ = v & 0xff; 293 v = v >> 8; 294 } 295 *bp += 4; 296 } 297 298 /* 299 * dump_bytes -- display bytes as hex numbers. 300 * b is the pointer to the byte buffer 301 * n is the number of bytes in the buffer 302 */ 303 /* Note: BPL = bytes to display per line */ 304 #define BPL 16 305 306 static 307 void 308 dump_bytes(uchar_t *b, int n) 309 { 310 int cd = n; 311 int cu = 0; 312 int o = 0; 313 int bl; 314 int ac; 315 316 /* Display offset, 16 bytes per line, and printable ascii version */ 317 while (cd > 0) { 318 ac = 0; 319 (void) printf("\n%06x: ", o); 320 for (bl = 0; bl < BPL; bl++) { 321 if (cu+bl < n) { 322 (void) printf("%02x ", (b[cu+bl] & 0xff)); 323 ac++; 324 } 325 else 326 (void) printf(" "); 327 } 328 for (bl = 0; bl < BPL; bl++) { 329 if ((cu+bl < n) && 330 ((b[cu+bl] >= ' ') && (b[cu+bl] <= '~'))) 331 (void) printf("%c", b[cu+bl]); 332 else 333 (void) printf("."); 334 } 335 cu += ac; o += ac; cd -= ac; 336 } 337 (void) printf("\n\n"); 338 } 339 340 /* 341 * header_for_dump -- display simple header over what will be output. 342 */ 343 static 344 void 345 header_for_dump(void) 346 { 347 int bl; 348 349 (void) printf("\n "); 350 for (bl = 0; bl < BPL; bl++) 351 (void) printf("%02x ", bl); 352 (void) printf("\n "); 353 bl = 3*BPL; 354 while (bl-- > 0) 355 (void) printf("-"); 356 } 357 358 /* 359 * parse_drvnum 360 * Convert a partition name into a drive number. 361 */ 362 static 363 int 364 parse_drvnum(char *pn) 365 { 366 int drvnum; 367 368 /* 369 * Determine logical drive to seek after. 370 */ 371 if (strlen(pn) == 1 && *pn >= 'c' && *pn <= 'z') { 372 drvnum = *pn - 'c' + 1; 373 } else if (*pn >= '0' && *pn <= '9') { 374 char *d; 375 int v, m, c; 376 377 v = 0; 378 d = pn; 379 while (*d && *d >= '0' && *d <= '9') { 380 c = strlen(d); 381 m = 1; 382 while (--c) 383 m *= 10; 384 v += m * (*d - '0'); 385 d++; 386 } 387 388 if (*d || v > 24) { 389 (void) fprintf(stderr, 390 gettext("%s: bogus logical drive specification.\n"), 391 pn); 392 return (-1); 393 } 394 drvnum = v; 395 } else if (strcmp(pn, "boot") == 0) { 396 drvnum = 99; 397 } else { 398 (void) fprintf(stderr, 399 gettext("%s: bogus logical drive specification.\n"), pn); 400 return (-1); 401 } 402 403 return (drvnum); 404 } 405 406 /* 407 * Define some special logical drives we use. 408 */ 409 #define BOOT_PARTITION_DRIVE 99 410 #define PRIMARY_DOS_DRIVE 1 411 412 /* 413 * isDosDrive() 414 * Boolean function. Give it the systid field for an fdisk partition 415 * and it decides if that's a systid that describes a DOS drive. We 416 * use systid values defined in sys/dktp/fdisk.h. 417 */ 418 static int 419 isDosDrive(uchar_t checkMe) 420 { 421 return ((checkMe == DOSOS12) || (checkMe == DOSOS16) || 422 (checkMe == DOSHUGE) || (checkMe == FDISK_WINDOWS) || 423 (checkMe == FDISK_EXT_WIN) || (checkMe == FDISK_FAT95) || 424 (checkMe == DIAGPART)); 425 } 426 427 /* 428 * isDosExtended() 429 * Boolean function. Give it the systid field for an fdisk partition 430 * and it decides if that's a systid that describes an extended DOS 431 * partition. 432 */ 433 static int 434 isDosExtended(uchar_t checkMe) 435 { 436 return ((checkMe == EXTDOS) || (checkMe == FDISK_EXTLBA)); 437 } 438 439 /* 440 * isBootPart() 441 * Boolean function. Give it the systid field for an fdisk partition 442 * and it decides if that's a systid that describes a Solaris boot 443 * partition. 444 */ 445 static int 446 isBootPart(uchar_t checkMe) 447 { 448 return (checkMe == X86BOOT); 449 } 450 451 static 452 int 453 warn_mismatch(char *desc, char *src, int expect, int assigned) 454 { 455 if (expect == assigned) 456 return (assigned); 457 458 /* 459 * 4228473 - No way to non-interactively make a pcfs filesystem 460 * 461 * If we don't have an input TTY, or we aren't really doing 462 * anything, then don't ask questions. Assume a yes answer 463 * to any questions we would ask. 464 */ 465 if (Notreally || !isatty(fileno(stdin))) { 466 (void) printf(gettext("WARNING: User supplied %s is %d," 467 "\nbut value obtained from the %s is %d.\n" 468 "Using user supplied value.\n"), 469 desc, assigned, src, expect); 470 return (assigned); 471 } 472 473 (void) printf(gettext("User supplied %s is %d." 474 "\nThe value obtained from the %s is %d.\n"), 475 desc, assigned, src, expect); 476 477 (void) printf( 478 gettext("Continue with value given on command line (y/n)? ")); 479 (void) fflush(stdout); 480 if (yes()) 481 return (assigned); 482 else 483 exit(2); 484 /*NOTREACHED*/ 485 } 486 487 static 488 void 489 fill_fat32_bpb(bpb_t *wbpb) 490 { 491 /* 492 * ExtFlags means (according to MSDN BPB (FAT32) document) 493 * 494 * Bit 8 indicates info written to the active FAT is written 495 * to all copies of the FAT. (I think they mean bit 7, with 496 * numbering starting at 0) 497 * 498 * Lowest 4 bits of field are the 0 based FAT number of the 499 * Active FAT. (only meaningful if bit 8 is set) 500 * 501 * Field contains combination of these values: 502 * 503 * VALUE DESCRIPTION 504 * BGBPB_F_ActiveFATMsk Mask for low four bits 505 * (0x000F) 506 * BGBPB_F_NoFATMirror If set FAT mirroring disabled. 507 * (0x0080) If clear, FAT mirroring enabled. 508 * 509 * We set the value based on what I've seen on all the FAT32 drives 510 * I've seen created by Windows. 511 * 512 */ 513 wbpb->bpb32.ext_flags = 0x0; 514 /* 515 * No real explanation of the fs_vers file in the BPB doc. The 516 * high byte is supposed to be the major version and the low the 517 * minor version. Again I set according to what I've seen on Windows. 518 */ 519 wbpb->bpb32.fs_vers_lo = '\0'; 520 wbpb->bpb32.fs_vers_hi = '\0'; 521 /* 522 * The convention appears to be to place the fs info sector 523 * immediately after the boot sector, and that the backup boot 524 * sector should be at sector 6. (based on what I see with 525 * Windows) 526 */ 527 wbpb->bpb32.fsinfosec = 1; 528 wbpb->bpb32.backupboot = 6; 529 } 530 531 static 532 void 533 fill_bpb_sizes(bpb_t *wbpb, struct ipart part[], int partno, off64_t offset) 534 { 535 ulong_t usesize; 536 537 if (GetFsParams || GetSize) { 538 usesize = ltohi(part[partno].numsect); 539 if (Verbose) { 540 (void) printf( 541 gettext("Partition size (from FDISK table) " 542 "= %d sectors.\n"), usesize); 543 } 544 } else { 545 usesize = warn_mismatch( 546 gettext("length of partition (in sectors)"), 547 gettext("FDISK table"), 548 ltohi(part[partno].numsect), TotSize); 549 } 550 551 if (GetFsParams) { 552 TotSize = usesize; 553 } else { 554 if (usesize > 0xffff) 555 wbpb->bpb.sectors_in_volume = 0; 556 else 557 wbpb->bpb.sectors_in_volume = usesize; 558 wbpb->bpb.sectors_in_logical_volume = usesize; 559 } 560 561 wbpb->bpb.hidden_sectors = offset; 562 563 if (GetFsParams) { 564 RelOffset = offset; 565 } else { 566 wbpb->sunbpb.bs_offset_high = offset >> 16; 567 wbpb->sunbpb.bs_offset_low = offset & 0xFFFF; 568 } 569 } 570 571 /* 572 * lookup_FAT_size 573 * 574 * Given the FDISK partition file system identifier, return the 575 * expected FAT size for the partition. 576 */ 577 static 578 int 579 lookup_FAT_size(uchar_t partid) 580 { 581 int rval; 582 583 switch (partid) { 584 case DOSOS12: 585 rval = 12; 586 break; 587 case DOSOS16: 588 case DOSHUGE: 589 case FDISK_FAT95: 590 case X86BOOT: 591 rval = 16; 592 break; 593 case FDISK_WINDOWS: 594 case FDISK_EXT_WIN: 595 rval = 32; 596 break; 597 case EXTDOS: 598 case FDISK_EXTLBA: 599 default: 600 rval = -1; 601 break; 602 } 603 604 return (rval); 605 } 606 607 /* 608 * seek_partn 609 * 610 * Seek to the beginning of the partition where we need to install 611 * the new FAT. Zero return for any error, but print error 612 * messages here. 613 */ 614 static 615 int 616 seek_partn(int fd, char *pn, bpb_t *wbpb, off64_t *seekto) 617 { 618 struct ipart part[FD_NUMPART]; 619 struct mboot extmboot; 620 struct mboot mb; 621 diskaddr_t xstartsect; 622 off64_t nextseek = 0; 623 off64_t lastseek = 0; 624 int logicalDriveCount = 0; 625 int extendedPart = -1; 626 int primaryPart = -1; 627 int bootPart = -1; 628 uint32_t xnumsect = 0; 629 int drvnum; 630 int driveIndex; 631 int i; 632 /* 633 * Count of drives in the current extended partition's 634 * FDISK table, and indexes of the drives themselves. 635 */ 636 int extndDrives[FD_NUMPART]; 637 int numDrives = 0; 638 /* 639 * Count of drives (beyond primary) in master boot record's 640 * FDISK table, and indexes of the drives themselves. 641 */ 642 int extraDrives[FD_NUMPART]; 643 int numExtraDrives = 0; 644 645 if ((drvnum = parse_drvnum(pn)) < 0) 646 return (PART_NOT_FOUND); 647 648 if (read(fd, &mb, sizeof (mb)) != sizeof (mb)) { 649 (void) fprintf(stderr, 650 gettext("Couldn't read a Master Boot Record?!\n")); 651 return (PART_NOT_FOUND); 652 } 653 654 if (ltohs(mb.signature) != BOOTSECSIG) { 655 (void) fprintf(stderr, 656 gettext("Bad Sig on master boot record!\n")); 657 return (PART_NOT_FOUND); 658 } 659 660 *seekto = 0; 661 662 /* 663 * Copy partition table into memory 664 */ 665 (void) memcpy(part, mb.parts, sizeof (part)); 666 667 /* 668 * Get a summary of what is in the Master FDISK table. 669 * Normally we expect to find one partition marked as a DOS drive. 670 * This partition is the one Windows calls the primary dos partition. 671 * If the machine has any logical drives then we also expect 672 * to find a partition marked as an extended DOS partition. 673 * 674 * Sometimes we'll find multiple partitions marked as DOS drives. 675 * The Solaris fdisk program allows these partitions 676 * to be created, but Windows fdisk no longer does. We still need 677 * to support these, though, since Windows does. We also need to fix 678 * our fdisk to behave like the Windows version. 679 * 680 * It turns out that some off-the-shelf media have *only* an 681 * Extended partition, so we need to deal with that case as 682 * well. 683 * 684 * Only a single (the first) Extended or Boot Partition will 685 * be recognized. Any others will be ignored. 686 */ 687 for (i = 0; i < FD_NUMPART; i++) { 688 if (isDosDrive(part[i].systid)) { 689 if (primaryPart < 0) { 690 logicalDriveCount++; 691 primaryPart = i; 692 } else { 693 extraDrives[numExtraDrives++] = i; 694 } 695 continue; 696 } 697 if ((extendedPart < 0) && isDosExtended(part[i].systid)) { 698 extendedPart = i; 699 continue; 700 } 701 if ((bootPart < 0) && isBootPart(part[i].systid)) { 702 bootPart = i; 703 continue; 704 } 705 } 706 707 if (drvnum == BOOT_PARTITION_DRIVE) { 708 if (bootPart < 0) { 709 (void) fprintf(stderr, 710 gettext("No boot partition found on drive\n")); 711 return (PART_NOT_FOUND); 712 } 713 if ((*seekto = ltohi(part[bootPart].relsect)) == 0) { 714 (void) fprintf(stderr, gettext("Bogus FDISK entry? " 715 "A boot partition starting\nat sector 0 would " 716 "collide with the FDISK table!\n")); 717 return (PART_NOT_FOUND); 718 } 719 720 fill_bpb_sizes(wbpb, part, bootPart, *seekto); 721 *seekto *= BPSEC; 722 FdiskFATsize = lookup_FAT_size(part[bootPart].systid); 723 if (Verbose) 724 (void) printf(gettext("Boot partition's offset: " 725 "Sector %x.\n"), *seekto/BPSEC); 726 if (lseek64(fd, *seekto, SEEK_SET) < 0) { 727 (void) fprintf(stderr, gettext("Partition %s: "), pn); 728 perror(""); 729 return (PART_NOT_FOUND); 730 } 731 return (PART_FOUND); 732 } 733 734 if (drvnum == PRIMARY_DOS_DRIVE && primaryPart >= 0) { 735 if ((*seekto = ltohi(part[primaryPart].relsect)) == 0) { 736 (void) fprintf(stderr, gettext("Bogus FDISK entry? " 737 "A partition starting\nat sector 0 would " 738 "collide with the FDISK table!\n")); 739 return (PART_NOT_FOUND); 740 } 741 742 fill_bpb_sizes(wbpb, part, primaryPart, *seekto); 743 *seekto *= BPSEC; 744 FdiskFATsize = lookup_FAT_size(part[primaryPart].systid); 745 if (Verbose) 746 (void) printf(gettext("Partition's offset: " 747 "Sector %x.\n"), *seekto/BPSEC); 748 if (lseek64(fd, *seekto, SEEK_SET) < 0) { 749 (void) fprintf(stderr, gettext("Partition %s: "), pn); 750 perror(""); 751 return (PART_NOT_FOUND); 752 } 753 return (PART_FOUND); 754 } 755 756 /* 757 * We are not looking for the C: drive (or there was no primary 758 * drive found), so we had better have an extended partition or 759 * extra drives in the Master FDISK table. 760 */ 761 if ((extendedPart < 0) && (numExtraDrives == 0)) { 762 (void) fprintf(stderr, 763 gettext("No such logical drive " 764 "(missing extended partition entry)\n")); 765 return (PART_NOT_FOUND); 766 } 767 768 if (extendedPart >= 0) { 769 nextseek = xstartsect = ltohi(part[extendedPart].relsect); 770 xnumsect = ltohi(part[extendedPart].numsect); 771 do { 772 /* 773 * If the seek would not cause us to change 774 * position on the drive, then we're out of 775 * extended partitions to examine. 776 */ 777 if (nextseek == lastseek) 778 break; 779 logicalDriveCount += numDrives; 780 /* 781 * Seek the next extended partition, and find 782 * logical drives within it. 783 */ 784 if (lseek64(fd, nextseek * BPSEC, SEEK_SET) < 0 || 785 read(fd, &extmboot, sizeof (extmboot)) != 786 sizeof (extmboot)) { 787 perror(gettext("Unable to read extended " 788 "partition record")); 789 return (PART_NOT_FOUND); 790 } 791 (void) memcpy(part, extmboot.parts, sizeof (part)); 792 lastseek = nextseek; 793 if (ltohs(extmboot.signature) != MBB_MAGIC) { 794 (void) fprintf(stderr, 795 gettext("Bad signature on " 796 "extended partition\n")); 797 return (PART_NOT_FOUND); 798 } 799 /* 800 * Count up drives, and track where the next 801 * extended partition is in case we need it. We 802 * are expecting only one extended partition. If 803 * there is more than one we'll only go to the 804 * first one we see, but warn about ignoring. 805 */ 806 numDrives = 0; 807 for (i = 0; i < FD_NUMPART; i++) { 808 if (isDosDrive(part[i].systid)) { 809 extndDrives[numDrives++] = i; 810 continue; 811 } else if (isDosExtended(part[i].systid)) { 812 if (nextseek != lastseek) { 813 /* 814 * Already found an extended 815 * partition in this table. 816 */ 817 (void) fprintf(stderr, 818 gettext("WARNING: " 819 "Ignoring unexpected " 820 "additional extended " 821 "partition")); 822 continue; 823 } 824 nextseek = xstartsect + 825 ltohi(part[i].relsect); 826 continue; 827 } 828 } 829 } while (drvnum > logicalDriveCount + numDrives); 830 831 if (drvnum <= logicalDriveCount + numDrives) { 832 /* 833 * The number of logical drives we've found thus 834 * far is enough to get us to the one we were 835 * searching for. 836 */ 837 driveIndex = logicalDriveCount + numDrives - drvnum; 838 *seekto = 839 ltohi(part[extndDrives[driveIndex]].relsect) + 840 lastseek; 841 if (*seekto == lastseek) { 842 (void) fprintf(stderr, 843 gettext("Bogus FDISK entry? A logical " 844 "drive starting at\nsector 0x%llx would " 845 "collide with the\nFDISK information in " 846 "that sector.\n"), *seekto); 847 return (PART_NOT_FOUND); 848 } else if (*seekto <= xstartsect || 849 *seekto >= (xstartsect + xnumsect)) { 850 (void) fprintf(stderr, 851 gettext("Bogus FDISK entry? " 852 "Logical drive start sector (0x%llx)\n" 853 "not within extended partition! " 854 "(Expected in range 0x%x - 0x%x)\n"), 855 *seekto, xstartsect + 1, 856 xstartsect + xnumsect - 1); 857 return (PART_NOT_FOUND); 858 } 859 fill_bpb_sizes(wbpb, part, extndDrives[driveIndex], 860 *seekto); 861 *seekto *= BPSEC; 862 FdiskFATsize = lookup_FAT_size( 863 part[extndDrives[driveIndex]].systid); 864 if (Verbose) 865 (void) printf(gettext("Partition's offset: " 866 "Sector 0x%x.\n"), *seekto/BPSEC); 867 if (lseek64(fd, *seekto, SEEK_SET) < 0) { 868 (void) fprintf(stderr, 869 gettext("Partition %s: "), pn); 870 perror(""); 871 return (PART_NOT_FOUND); 872 } 873 return (PART_FOUND); 874 } else { 875 /* 876 * We ran out of extended dos partition 877 * drives. The only hope now is to go 878 * back to extra drives defined in the master 879 * fdisk table. But we overwrote that table 880 * already, so we must load it in again. 881 */ 882 logicalDriveCount += numDrives; 883 (void) memcpy(part, mb.parts, sizeof (part)); 884 } 885 } 886 /* 887 * Still haven't found the drive, is it an extra 888 * drive defined in the main FDISK table? 889 */ 890 if (drvnum <= logicalDriveCount + numExtraDrives) { 891 driveIndex = logicalDriveCount + numExtraDrives - drvnum; 892 *seekto = ltohi(part[extraDrives[driveIndex]].relsect); 893 if (*seekto == 0) { 894 (void) fprintf(stderr, gettext("Bogus FDISK entry? " 895 "A partition starting\nat sector 0 would " 896 "collide with the FDISK table!\n")); 897 return (PART_NOT_FOUND); 898 } 899 900 fill_bpb_sizes(wbpb, part, extraDrives[driveIndex], *seekto); 901 *seekto *= BPSEC; 902 FdiskFATsize = 903 lookup_FAT_size(part[extraDrives[driveIndex]].systid); 904 if (Verbose) 905 (void) printf(gettext("Partition's offset: " 906 "Sector %x.\n"), *seekto/BPSEC); 907 if (lseek64(fd, *seekto, SEEK_SET) < 0) { 908 (void) fprintf(stderr, 909 gettext("Partition %s: "), pn); 910 perror(""); 911 return (PART_NOT_FOUND); 912 } 913 return (PART_FOUND); 914 } 915 (void) fprintf(stderr, gettext("No such logical drive\n")); 916 return (PART_NOT_FOUND); 917 } 918 919 /* 920 * seek_nofdisk 921 * 922 * User is asking us to trust them that they know best. 923 * We basically won't do much seeking here, the only seeking we'll do 924 * is if the 'hidden' parameter was given. 925 */ 926 static 927 int 928 seek_nofdisk(int fd, bpb_t *wbpb, off64_t *seekto) 929 { 930 if (TotSize > 0xffff) 931 wbpb->bpb.sectors_in_volume = 0; 932 else 933 wbpb->bpb.sectors_in_volume = (short)TotSize; 934 wbpb->bpb.sectors_in_logical_volume = TotSize; 935 936 *seekto = RelOffset * BPSEC; 937 wbpb->bpb.hidden_sectors = RelOffset; 938 wbpb->sunbpb.bs_offset_high = RelOffset >> 16; 939 wbpb->sunbpb.bs_offset_low = RelOffset & 0xFFFF; 940 941 if (Verbose) 942 (void) printf(gettext("Requested offset: Sector %x.\n"), 943 *seekto/BPSEC); 944 945 if (lseek64(fd, *seekto, SEEK_SET) < 0) { 946 (void) fprintf(stderr, 947 gettext("User specified start sector %d"), RelOffset); 948 perror(""); 949 return (PART_NOT_FOUND); 950 } 951 return (PART_FOUND); 952 } 953 954 /* 955 * set_fat_string 956 * 957 * Fill in the type string of the FAT 958 */ 959 static 960 void 961 set_fat_string(bpb_t *wbpb, int fatsize) 962 { 963 if (fatsize == 12) { 964 (void) strncpy((char *)wbpb->ebpb.type, FAT12_TYPE_STRING, 965 strlen(FAT12_TYPE_STRING)); 966 } else if (fatsize == 16) { 967 (void) strncpy((char *)wbpb->ebpb.type, FAT16_TYPE_STRING, 968 strlen(FAT16_TYPE_STRING)); 969 } else { 970 (void) strncpy((char *)wbpb->ebpb.type, FAT32_TYPE_STRING, 971 strlen(FAT32_TYPE_STRING)); 972 } 973 } 974 975 /* 976 * prepare_image_file 977 * 978 * Open the file that will hold the image (as opposed to the image 979 * being written to the boot sector of an actual disk). 980 */ 981 static 982 int 983 prepare_image_file(char *fn, bpb_t *wbpb) 984 { 985 int fd; 986 char zerobyte = '\0'; 987 988 if ((fd = open(fn, O_RDWR | O_CREAT | O_EXCL, 0666)) < 0) { 989 perror(fn); 990 exit(2); 991 } 992 993 if (Imagesize == 5) { 994 /* Disk image of a 1.2M floppy */ 995 wbpb->bpb.sectors_in_volume = 2 * 80 * 15; 996 wbpb->bpb.sectors_in_logical_volume = 2 * 80 * 15; 997 wbpb->bpb.sectors_per_track = 15; 998 wbpb->bpb.heads = 2; 999 wbpb->bpb.media = 0xF9; 1000 wbpb->bpb.num_root_entries = 224; 1001 wbpb->bpb.sectors_per_cluster = 1; 1002 wbpb->bpb.sectors_per_fat = 7; 1003 } else { 1004 /* Disk image of a 1.44M floppy */ 1005 wbpb->bpb.sectors_in_volume = 2 * 80 * 18; 1006 wbpb->bpb.sectors_in_logical_volume = 2 * 80 * 18; 1007 wbpb->bpb.sectors_per_track = 18; 1008 wbpb->bpb.heads = 2; 1009 wbpb->bpb.media = 0xF0; 1010 wbpb->bpb.num_root_entries = 224; 1011 wbpb->bpb.sectors_per_cluster = 1; 1012 wbpb->bpb.sectors_per_fat = 9; 1013 } 1014 1015 /* 1016 * Make a holey file, with length the exact 1017 * size of the floppy image. 1018 */ 1019 if (lseek(fd, (wbpb->bpb.sectors_in_volume * BPSEC)-1, SEEK_SET) < 0) { 1020 (void) close(fd); 1021 perror(fn); 1022 exit(2); 1023 } 1024 1025 if (write(fd, &zerobyte, 1) != 1) { 1026 (void) close(fd); 1027 perror(fn); 1028 exit(2); 1029 } 1030 1031 if (lseek(fd, 0, SEEK_SET) < 0) { 1032 (void) close(fd); 1033 perror(fn); 1034 exit(2); 1035 } 1036 1037 Fatentsize = 12; /* Size of fat entry in bits */ 1038 set_fat_string(wbpb, Fatentsize); 1039 1040 wbpb->ebpb.phys_drive_num = 0; 1041 1042 wbpb->sunbpb.bs_offset_high = 0; 1043 wbpb->sunbpb.bs_offset_low = 0; 1044 1045 return (fd); 1046 } 1047 1048 /* 1049 * partn_lecture 1050 * 1051 * Give a brief sermon on dev_name user should pass to 1052 * the program from the command line. 1053 * 1054 */ 1055 static 1056 void 1057 partn_lecture(char *dn) 1058 { 1059 (void) fprintf(stderr, 1060 gettext("\nDevice %s was assumed to be a diskette.\n" 1061 "A diskette specific operation failed on this device.\n" 1062 "If the device is a hard disk, provide the name of " 1063 "the full physical disk,\n" 1064 "and qualify that name with a logical drive specifier.\n\n" 1065 "Hint: the device is usually something similar to\n\n" 1066 "/dev/rdsk/c0d0p0 or /dev/rdsk/c0t0d0p0 (x86)\n" 1067 "/dev/rdsk/c0t5d0s2 (sparc)\n\n" 1068 "The drive specifier is appended to the device name." 1069 " For example:\n\n" 1070 "/dev/rdsk/c0t5d0s2:c or /dev/rdsk/c0d0p0:boot\n\n"), dn); 1071 } 1072 1073 static 1074 void 1075 warn_funky_floppy(void) 1076 { 1077 (void) fprintf(stderr, 1078 gettext("Use the 'nofdisk' option to create file systems\n" 1079 "on non-standard floppies.\n\n")); 1080 exit(4); 1081 } 1082 1083 static 1084 void 1085 warn_funky_fatsize(void) 1086 { 1087 (void) fprintf(stderr, 1088 gettext("Non-standard FAT size requested for floppy.\n" 1089 "The 'nofdisk' option must be used to\n" 1090 "override the 12 bit floppy default.\n\n")); 1091 exit(4); 1092 } 1093 1094 static 1095 void 1096 floppy_bpb_fillin(bpb_t *wbpb, int diam, int hds, int spt) 1097 { 1098 switch (diam) { 1099 case 3: 1100 switch (hds) { 1101 case 2: 1102 switch (spt) { 1103 case 9: 1104 wbpb->bpb.media = 0xF9; 1105 wbpb->bpb.num_root_entries = 112; 1106 wbpb->bpb.sectors_per_cluster = 2; 1107 wbpb->bpb.sectors_per_fat = 3; 1108 break; 1109 case 18: 1110 wbpb->bpb.media = 0xF0; 1111 wbpb->bpb.num_root_entries = 224; 1112 wbpb->bpb.sectors_per_cluster = 1; 1113 wbpb->bpb.sectors_per_fat = 9; 1114 break; 1115 case 36: 1116 wbpb->bpb.media = 0xF0; 1117 wbpb->bpb.num_root_entries = 240; 1118 wbpb->bpb.sectors_per_cluster = 2; 1119 wbpb->bpb.sectors_per_fat = 9; 1120 break; 1121 default: 1122 (void) fprintf(stderr, 1123 gettext("Unknown diskette parameters! " 1124 "3.5'' diskette with %d heads " 1125 "and %d sectors/track.\n"), hds, spt); 1126 warn_funky_floppy(); 1127 } 1128 break; 1129 case 1: 1130 default: 1131 (void) fprintf(stderr, 1132 gettext("Unknown diskette parameters! " 1133 "3.5'' diskette with %d heads "), hds); 1134 warn_funky_floppy(); 1135 } 1136 break; 1137 case 5: 1138 switch (hds) { 1139 case 2: 1140 switch (spt) { 1141 case 15: 1142 wbpb->bpb.media = 0xF9; 1143 wbpb->bpb.num_root_entries = 224; 1144 wbpb->bpb.sectors_per_cluster = 1; 1145 wbpb->bpb.sectors_per_fat = 7; 1146 break; 1147 case 9: 1148 wbpb->bpb.media = 0xFD; 1149 wbpb->bpb.num_root_entries = 112; 1150 wbpb->bpb.sectors_per_cluster = 2; 1151 wbpb->bpb.sectors_per_fat = 2; 1152 break; 1153 case 8: 1154 wbpb->bpb.media = 0xFF; 1155 wbpb->bpb.num_root_entries = 112; 1156 wbpb->bpb.sectors_per_cluster = 1; 1157 wbpb->bpb.sectors_per_fat = 2; 1158 break; 1159 default: 1160 (void) fprintf(stderr, 1161 gettext("Unknown diskette parameters! " 1162 "5.25'' diskette with %d heads " 1163 "and %d sectors/track.\n"), hds, spt); 1164 warn_funky_floppy(); 1165 } 1166 break; 1167 case 1: 1168 switch (spt) { 1169 case 9: 1170 wbpb->bpb.media = 0xFC; 1171 wbpb->bpb.num_root_entries = 64; 1172 wbpb->bpb.sectors_per_cluster = 1; 1173 wbpb->bpb.sectors_per_fat = 2; 1174 break; 1175 case 8: 1176 wbpb->bpb.media = 0xFE; 1177 wbpb->bpb.num_root_entries = 64; 1178 wbpb->bpb.sectors_per_cluster = 1; 1179 wbpb->bpb.sectors_per_fat = 1; 1180 break; 1181 default: 1182 (void) fprintf(stderr, 1183 gettext("Unknown diskette parameters! " 1184 "5.25'' diskette with %d heads " 1185 "and %d sectors/track.\n"), hds, spt); 1186 warn_funky_floppy(); 1187 } 1188 break; 1189 default: 1190 (void) fprintf(stderr, 1191 gettext("Unknown diskette parameters! " 1192 "5.25'' diskette with %d heads."), hds); 1193 warn_funky_floppy(); 1194 } 1195 break; 1196 default: 1197 (void) fprintf(stderr, 1198 gettext("\nUnknown diskette type. Only know about " 1199 "5.25'' and 3.5'' diskettes.\n")); 1200 warn_funky_floppy(); 1201 } 1202 } 1203 1204 /* 1205 * lookup_floppy 1206 * 1207 * Look up a media descriptor byte and other crucial BPB values 1208 * based on floppy characteristics. 1209 */ 1210 static 1211 void 1212 lookup_floppy(struct fd_char *fdchar, bpb_t *wbpb) 1213 { 1214 ulong_t tsize; 1215 ulong_t cyls, spt, hds, diam; 1216 1217 cyls = fdchar->fdc_ncyl; 1218 diam = fdchar->fdc_medium; 1219 spt = fdchar->fdc_secptrack; 1220 hds = fdchar->fdc_nhead; 1221 1222 tsize = cyls * hds * spt; 1223 1224 if (GetFsParams) 1225 TotSize = tsize; 1226 1227 if (GetSize) { 1228 wbpb->bpb.sectors_in_logical_volume = tsize; 1229 } else { 1230 wbpb->bpb.sectors_in_logical_volume = 1231 warn_mismatch( 1232 gettext("length of partition (in sectors)"), 1233 gettext("FDIOGCHAR call"), tsize, TotSize); 1234 } 1235 wbpb->bpb.sectors_in_volume = 1236 (short)wbpb->bpb.sectors_in_logical_volume; 1237 1238 if (GetSPT) { 1239 wbpb->bpb.sectors_per_track = spt; 1240 } else { 1241 wbpb->bpb.sectors_per_track = 1242 warn_mismatch( 1243 gettext("sectors per track"), 1244 gettext("FDIOGCHAR call"), spt, SecPerTrk); 1245 spt = wbpb->bpb.sectors_per_track; 1246 } 1247 1248 if (GetTPC) { 1249 wbpb->bpb.heads = hds; 1250 } else { 1251 wbpb->bpb.heads = 1252 warn_mismatch( 1253 gettext("number of heads"), 1254 gettext("FDIOGCHAR call"), hds, TrkPerCyl); 1255 hds = wbpb->bpb.heads; 1256 } 1257 1258 Fatentsize = 12; /* Size of fat entry in bits */ 1259 if (!GetBPF && BitsPerFAT != Fatentsize) { 1260 warn_funky_fatsize(); 1261 } 1262 set_fat_string(wbpb, Fatentsize); 1263 1264 wbpb->ebpb.phys_drive_num = 0; 1265 1266 wbpb->bpb.hidden_sectors = 0; 1267 wbpb->sunbpb.bs_offset_high = 0; 1268 wbpb->sunbpb.bs_offset_low = 0; 1269 1270 floppy_bpb_fillin(wbpb, diam, hds, spt); 1271 } 1272 1273 /* 1274 * compute_cluster_size 1275 * 1276 * Compute an acceptable sectors/cluster value. 1277 * 1278 * Based on values from the Hardware White Paper 1279 * from Microsoft. 1280 * "Microsoft Extensible Firmware Initiative 1281 * FAT32 File System Specification 1282 * FAT: General Overview of On-Disk Format" 1283 * 1284 * Version 1.03, December 6, 2000 1285 * 1286 */ 1287 static 1288 void 1289 compute_cluster_size(bpb_t *wbpb) 1290 { 1291 ulong_t volsize; 1292 ulong_t spc; 1293 ulong_t rds, tmpval1, tmpval2; 1294 ulong_t fatsz; 1295 int newfat = 16; 1296 1297 #define FAT12_MAX_CLUSTERS 0x0FF4 1298 #define FAT16_MAX_CLUSTERS 0xFFF4 1299 #define FAT32_MAX_CLUSTERS 0x0FFFFFF0 1300 #define FAT32_SUGGESTED_NCLUST 0x400000 1301 1302 /* compute volume size in sectors. */ 1303 volsize = wbpb->bpb.sectors_in_volume ? wbpb->bpb.sectors_in_volume : 1304 wbpb->bpb.sectors_in_logical_volume; 1305 volsize -= wbpb->bpb.resv_sectors; 1306 1307 if (GetSPC) { 1308 /* 1309 * User indicated what sort of FAT to create, 1310 * make sure it is valid with the given size 1311 * and compute an SPC value. 1312 */ 1313 if (!MakeFAT32) { /* FAT16 */ 1314 /* volsize is in sectors */ 1315 if (volsize < FAT12_MAX_CLUSTERS) { 1316 (void) fprintf(stderr, 1317 gettext("Requested size is too " 1318 "small for FAT16.\n")); 1319 exit(4); 1320 } 1321 /* SPC must be a power of 2 */ 1322 for (spc = 1; spc <= 64; spc = spc * 2) { 1323 if (volsize < spc * FAT16_MAX_CLUSTERS) 1324 break; 1325 } 1326 if (volsize > (spc * FAT16_MAX_CLUSTERS)) { 1327 (void) fprintf(stderr, 1328 gettext("Requested size is too " 1329 "large for FAT16.\n")); 1330 exit(4); 1331 } 1332 } else { /* FAT32 */ 1333 /* volsize is in sectors */ 1334 if (volsize < FAT16_MAX_CLUSTERS) { 1335 (void) fprintf(stderr, 1336 gettext("Requested size is too " 1337 "small for FAT32.\n")); 1338 exit(4); 1339 } 1340 /* SPC must be a power of 2 */ 1341 for (spc = 1; spc <= 64; spc = spc * 2) { 1342 if (volsize < (spc * FAT32_SUGGESTED_NCLUST)) 1343 break; 1344 } 1345 if (volsize > (spc * FAT32_MAX_CLUSTERS)) { 1346 (void) fprintf(stderr, 1347 gettext("Requested size is too " 1348 "large for FAT32.\n")); 1349 exit(4); 1350 } 1351 } 1352 } else { 1353 /* 1354 * User gave the SPC as an explicit option, 1355 * make sure it will work with the requested 1356 * volume size. 1357 */ 1358 int nclust; 1359 1360 spc = SecPerClust; 1361 nclust = volsize / spc; 1362 1363 if (nclust <= FAT16_MAX_CLUSTERS && MakeFAT32) { 1364 (void) fprintf(stderr, gettext("Requested size is too " 1365 "small for FAT32.\n")); 1366 exit(4); 1367 } 1368 if (!MakeFAT32) { 1369 /* Determine if FAT12 or FAT16 */ 1370 if (nclust < FAT12_MAX_CLUSTERS) 1371 newfat = 12; 1372 else if (nclust < FAT16_MAX_CLUSTERS) 1373 newfat = 16; 1374 else { 1375 (void) fprintf(stderr, 1376 gettext("Requested size is too " 1377 "small for FAT32.\n")); 1378 exit(4); 1379 } 1380 } 1381 } 1382 1383 /* 1384 * RootDirSectors = ((BPB_RootEntCnt * 32) + 1385 * (BPB_BytsPerSec 1)) / BPB_BytsPerSec; 1386 */ 1387 rds = ((wbpb->bpb.num_root_entries * 32) + 1388 (wbpb->bpb.bytes_sector - 1)) / wbpb->bpb.bytes_sector; 1389 1390 if (GetBPF) { 1391 if (MakeFAT32) 1392 Fatentsize = 32; 1393 else 1394 Fatentsize = newfat; 1395 } else { 1396 Fatentsize = BitsPerFAT; 1397 1398 if (Fatentsize == 12 && 1399 (volsize - rds) >= DOS_F12MAXC * spc) { 1400 /* 1401 * If we don't have an input TTY, or we aren't 1402 * really doing anything, then don't ask 1403 * questions. Assume a yes answer to any 1404 * questions we would ask. 1405 */ 1406 if (Notreally || !isatty(fileno(stdin))) { 1407 (void) printf( 1408 gettext("Volume too large for 12 bit FAT," 1409 " increasing to 16 bit FAT size.\n")); 1410 (void) fflush(stdout); 1411 Fatentsize = 16; 1412 } else { 1413 (void) printf( 1414 gettext("Volume too large for a 12 bit FAT.\n" 1415 "Increase to 16 bit FAT " 1416 "and continue (y/n)? ")); 1417 (void) fflush(stdout); 1418 if (yes()) 1419 Fatentsize = 16; 1420 else 1421 exit(5); 1422 } 1423 } 1424 } 1425 wbpb->bpb.sectors_per_cluster = spc; 1426 1427 if (!GetFsParams && FdiskFATsize < 0) { 1428 (void) printf( 1429 gettext("Cannot verify chosen/computed FAT " 1430 "entry size (%d bits) with FDISK table.\n" 1431 "FDISK table has an unknown file system " 1432 "type for this device. Giving up...\n"), 1433 Fatentsize, Fatentsize); 1434 exit(6); 1435 } else if (!GetFsParams && FdiskFATsize && FdiskFATsize != Fatentsize) { 1436 (void) printf( 1437 gettext("Chosen/computed FAT entry size (%d bits) " 1438 "does not match FDISK table (%d bits).\n"), 1439 Fatentsize, FdiskFATsize); 1440 (void) printf( 1441 gettext("Use -o fat=%d to build a FAT " 1442 "that matches the FDISK entry.\n"), FdiskFATsize); 1443 exit(6); 1444 } 1445 set_fat_string(wbpb, Fatentsize); 1446 /* 1447 * Compure the FAT sizes according to algorithm from Microsoft: 1448 * 1449 * RootDirSectors = ((BPB_RootEntCnt * 32) + 1450 * (BPB_BytsPerSec 1)) / BPB_BytsPerSec; 1451 * TmpVal1 = DskSize - (BPB_ResvdSecCnt + RootDirSectors); 1452 * TmpVal2 = (256 * BPB_SecPerClus) + BPB_NumFATs; 1453 * If (FATType == FAT32) 1454 * TmpVal2 = TmpVal2 / 2; 1455 * FATSz = (TMPVal1 + (TmpVal2 1)) / TmpVal2; 1456 * If (FATType == FAT32) { 1457 * BPB_FATSz16 = 0; 1458 * BPB_FATSz32 = FATSz; 1459 * } else { 1460 * BPB_FATSz16 = LOWORD(FATSz); 1461 * // there is no BPB_FATSz32 in a FAT16 BPB 1462 * } 1463 */ 1464 tmpval1 = volsize - (wbpb->bpb.resv_sectors + rds); 1465 1466 tmpval2 = (256 * wbpb->bpb.sectors_per_cluster) + wbpb->bpb.num_fats; 1467 1468 if (Fatentsize == 32) 1469 tmpval2 = tmpval2 / 2; 1470 1471 fatsz = (tmpval1 + (tmpval2 - 1)) / tmpval2; 1472 1473 /* Compute a sector/fat figure */ 1474 switch (Fatentsize) { 1475 case 32: 1476 wbpb->bpb.sectors_per_fat = 0; 1477 wbpb->bpb32.big_sectors_per_fat = fatsz; 1478 if (Verbose) 1479 (void) printf("compute_cluster_size: Sectors per " 1480 "FAT32 = %d\n", wbpb->bpb32.big_sectors_per_fat); 1481 break; 1482 case 12: 1483 default: /* 16 bit FAT */ 1484 wbpb->bpb.sectors_per_fat = (ushort_t)(fatsz & 0x0000FFFF); 1485 if (Verbose) 1486 (void) printf("compute_cluster_size: Sectors per " 1487 "FAT16 = %d\n", wbpb->bpb.sectors_per_fat); 1488 break; 1489 } 1490 } 1491 1492 static 1493 void 1494 find_fixed_details(int fd, bpb_t *wbpb) 1495 { 1496 struct dk_geom dginfo; 1497 1498 /* 1499 * Look up the last remaining bits of info we need 1500 * that is specific to the hard drive using a disk ioctl. 1501 */ 1502 if (GetSPT || GetTPC) { 1503 if (ioctl(fd, DKIOCG_VIRTGEOM, &dginfo) == -1 && 1504 ioctl(fd, DKIOCG_PHYGEOM, &dginfo) == -1 && 1505 ioctl(fd, DKIOCGGEOM, &dginfo) == -1) { 1506 (void) close(fd); 1507 perror( 1508 gettext("Drive geometry lookup (need " 1509 "tracks/cylinder and/or sectors/track")); 1510 exit(2); 1511 } 1512 } 1513 1514 wbpb->bpb.heads = (GetTPC ? dginfo.dkg_nhead : TrkPerCyl); 1515 wbpb->bpb.sectors_per_track = (GetSPT ? dginfo.dkg_nsect : SecPerTrk); 1516 1517 if (Verbose) { 1518 if (GetTPC) { 1519 (void) printf( 1520 gettext("DKIOCG determined number of heads = %d\n"), 1521 dginfo.dkg_nhead); 1522 } 1523 if (GetSPT) { 1524 (void) printf( 1525 gettext("DKIOCG determined sectors per track" 1526 " = %d\n"), dginfo.dkg_nsect); 1527 } 1528 } 1529 1530 /* 1531 * XXX - MAY need an additional flag (or flags) to set media 1532 * and physical drive number fields. That in the case of weird 1533 * floppies that have to go through 'nofdisk' route for formatting. 1534 */ 1535 wbpb->bpb.media = 0xF8; 1536 if (MakeFAT32) 1537 wbpb->bpb.num_root_entries = 0; 1538 else 1539 wbpb->bpb.num_root_entries = 512; 1540 wbpb->ebpb.phys_drive_num = 0x80; 1541 compute_cluster_size(wbpb); 1542 } 1543 1544 static 1545 char * 1546 stat_actual_disk(char *diskname, struct stat *info, char **suffix) 1547 { 1548 char *actualdisk; 1549 1550 if (stat(diskname, info)) { 1551 /* 1552 * Device named on command line doesn't exist. That 1553 * probably means there is a partition-specifying 1554 * suffix attached to the actual disk name. 1555 */ 1556 actualdisk = strtok(strdup(diskname), ":"); 1557 if (*suffix = strchr(diskname, ':')) 1558 (*suffix)++; 1559 1560 if (stat(actualdisk, info)) { 1561 perror(actualdisk); 1562 exit(2); 1563 } 1564 } else { 1565 actualdisk = strdup(diskname); 1566 } 1567 1568 return (actualdisk); 1569 } 1570 1571 static 1572 void 1573 compute_file_area_size(bpb_t *wbpb) 1574 { 1575 int FATSz; 1576 int TotSec; 1577 int DataSec; 1578 int RootDirSectors = 1579 ((wbpb->bpb.num_root_entries * 32) + (wbpb->bpb.bytes_sector - 1)) / 1580 wbpb->bpb.bytes_sector; 1581 1582 if (wbpb->bpb.sectors_per_fat) { 1583 /* 1584 * Good old FAT12 or FAT16 1585 */ 1586 FATSz = wbpb->bpb.sectors_per_fat; 1587 TotSec = wbpb->bpb.sectors_in_volume; 1588 } else { 1589 /* 1590 * FAT32 1591 */ 1592 FATSz = wbpb->bpb32.big_sectors_per_fat; 1593 TotSec = wbpb->bpb.sectors_in_logical_volume; 1594 } 1595 1596 DataSec = TotSec - 1597 (wbpb->bpb.resv_sectors + (wbpb->bpb.num_fats * FATSz) + 1598 RootDirSectors); 1599 1600 1601 /* 1602 * Now change sectors to clusters 1603 */ 1604 TotalClusters = DataSec / wbpb->bpb.sectors_per_cluster; 1605 1606 if (Verbose) 1607 (void) printf(gettext("Disk has a file area of %d " 1608 "allocation units,\neach with %d sectors = %d " 1609 "bytes.\n"), TotalClusters, wbpb->bpb.sectors_per_cluster, 1610 TotalClusters * wbpb->bpb.sectors_per_cluster * BPSEC); 1611 } 1612 1613 #ifndef i386 1614 /* 1615 * swap_pack_{bpb,bpb32,sebpb}cpy 1616 * 1617 * If not on an x86 we assume the structures making up the bpb 1618 * were not packed and that longs and shorts need to be byte swapped 1619 * (we've kept everything in host order up until now). A new architecture 1620 * might not need to swap or might not need to pack, in which case 1621 * new routines will have to be written. Of course if an architecture 1622 * supports both packing and little-endian host order, it can follow the 1623 * same path as the x86 code. 1624 */ 1625 static 1626 void 1627 swap_pack_bpbcpy(struct _boot_sector *bsp, bpb_t *wbpb) 1628 { 1629 uchar_t *fillp; 1630 1631 fillp = (uchar_t *)&(bsp->bs_filler[ORIG_BPB_START_INDEX]); 1632 1633 store_16_bits(&fillp, wbpb->bpb.bytes_sector); 1634 *fillp++ = wbpb->bpb.sectors_per_cluster; 1635 store_16_bits(&fillp, wbpb->bpb.resv_sectors); 1636 *fillp++ = wbpb->bpb.num_fats; 1637 store_16_bits(&fillp, wbpb->bpb.num_root_entries); 1638 store_16_bits(&fillp, wbpb->bpb.sectors_in_volume); 1639 *fillp++ = wbpb->bpb.media; 1640 store_16_bits(&fillp, wbpb->bpb.sectors_per_fat); 1641 store_16_bits(&fillp, wbpb->bpb.sectors_per_track); 1642 store_16_bits(&fillp, wbpb->bpb.heads); 1643 store_32_bits(&fillp, wbpb->bpb.hidden_sectors); 1644 store_32_bits(&fillp, wbpb->bpb.sectors_in_logical_volume); 1645 1646 *fillp++ = wbpb->ebpb.phys_drive_num; 1647 *fillp++ = wbpb->ebpb.reserved; 1648 *fillp++ = wbpb->ebpb.ext_signature; 1649 store_32_bits(&fillp, wbpb->ebpb.volume_id); 1650 (void) strncpy((char *)fillp, (char *)wbpb->ebpb.volume_label, 11); 1651 fillp += 11; 1652 (void) strncpy((char *)fillp, (char *)wbpb->ebpb.type, 8); 1653 } 1654 1655 static 1656 void 1657 swap_pack_bpb32cpy(struct _boot_sector32 *bsp, bpb_t *wbpb) 1658 { 1659 uchar_t *fillp; 1660 int r; 1661 1662 fillp = (uchar_t *)&(bsp->bs_filler[ORIG_BPB_START_INDEX]); 1663 1664 store_16_bits(&fillp, wbpb->bpb.bytes_sector); 1665 *fillp++ = wbpb->bpb.sectors_per_cluster; 1666 store_16_bits(&fillp, wbpb->bpb.resv_sectors); 1667 *fillp++ = wbpb->bpb.num_fats; 1668 store_16_bits(&fillp, wbpb->bpb.num_root_entries); 1669 store_16_bits(&fillp, wbpb->bpb.sectors_in_volume); 1670 *fillp++ = wbpb->bpb.media; 1671 store_16_bits(&fillp, wbpb->bpb.sectors_per_fat); 1672 store_16_bits(&fillp, wbpb->bpb.sectors_per_track); 1673 store_16_bits(&fillp, wbpb->bpb.heads); 1674 store_32_bits(&fillp, wbpb->bpb.hidden_sectors); 1675 store_32_bits(&fillp, wbpb->bpb.sectors_in_logical_volume); 1676 1677 store_32_bits(&fillp, wbpb->bpb32.big_sectors_per_fat); 1678 store_16_bits(&fillp, wbpb->bpb32.ext_flags); 1679 *fillp++ = wbpb->bpb32.fs_vers_lo; 1680 *fillp++ = wbpb->bpb32.fs_vers_hi; 1681 store_32_bits(&fillp, wbpb->bpb32.root_dir_clust); 1682 store_16_bits(&fillp, wbpb->bpb32.fsinfosec); 1683 store_16_bits(&fillp, wbpb->bpb32.backupboot); 1684 for (r = 0; r < 6; r++) 1685 store_16_bits(&fillp, wbpb->bpb32.reserved[r]); 1686 1687 *fillp++ = wbpb->ebpb.phys_drive_num; 1688 *fillp++ = wbpb->ebpb.reserved; 1689 *fillp++ = wbpb->ebpb.ext_signature; 1690 store_32_bits(&fillp, wbpb->ebpb.volume_id); 1691 (void) strncpy((char *)fillp, (char *)wbpb->ebpb.volume_label, 11); 1692 fillp += 11; 1693 (void) strncpy((char *)fillp, (char *)wbpb->ebpb.type, 8); 1694 } 1695 1696 static 1697 void 1698 swap_pack_sebpbcpy(struct _boot_sector *bsp, bpb_t *wbpb) 1699 { 1700 uchar_t *fillp; 1701 1702 fillp = bsp->bs_sun_bpb; 1703 store_16_bits(&fillp, wbpb->sunbpb.bs_offset_high); 1704 store_16_bits(&fillp, wbpb->sunbpb.bs_offset_low); 1705 } 1706 1707 static 1708 void 1709 swap_pack_grabbpb(bpb_t *wbpb, struct _boot_sector *bsp) 1710 { 1711 uchar_t *grabp; 1712 1713 grabp = (uchar_t *)&(bsp->bs_filler[ORIG_BPB_START_INDEX]); 1714 1715 ((uchar_t *)&(wbpb->bpb.bytes_sector))[1] = *grabp++; 1716 ((uchar_t *)&(wbpb->bpb.bytes_sector))[0] = *grabp++; 1717 wbpb->bpb.sectors_per_cluster = *grabp++; 1718 ((uchar_t *)&(wbpb->bpb.resv_sectors))[1] = *grabp++; 1719 ((uchar_t *)&(wbpb->bpb.resv_sectors))[0] = *grabp++; 1720 wbpb->bpb.num_fats = *grabp++; 1721 ((uchar_t *)&(wbpb->bpb.num_root_entries))[1] = *grabp++; 1722 ((uchar_t *)&(wbpb->bpb.num_root_entries))[0] = *grabp++; 1723 ((uchar_t *)&(wbpb->bpb.sectors_in_volume))[1] = *grabp++; 1724 ((uchar_t *)&(wbpb->bpb.sectors_in_volume))[0] = *grabp++; 1725 wbpb->bpb.media = *grabp++; 1726 ((uchar_t *)&(wbpb->bpb.sectors_per_fat))[1] = *grabp++; 1727 ((uchar_t *)&(wbpb->bpb.sectors_per_fat))[0] = *grabp++; 1728 ((uchar_t *)&(wbpb->bpb.sectors_per_track))[1] = *grabp++; 1729 ((uchar_t *)&(wbpb->bpb.sectors_per_track))[0] = *grabp++; 1730 ((uchar_t *)&(wbpb->bpb.heads))[1] = *grabp++; 1731 ((uchar_t *)&(wbpb->bpb.heads))[0] = *grabp++; 1732 ((uchar_t *)&(wbpb->bpb.hidden_sectors))[3] = *grabp++; 1733 ((uchar_t *)&(wbpb->bpb.hidden_sectors))[2] = *grabp++; 1734 ((uchar_t *)&(wbpb->bpb.hidden_sectors))[1] = *grabp++; 1735 ((uchar_t *)&(wbpb->bpb.hidden_sectors))[0] = *grabp++; 1736 ((uchar_t *)&(wbpb->bpb.sectors_in_logical_volume))[3] = *grabp++; 1737 ((uchar_t *)&(wbpb->bpb.sectors_in_logical_volume))[2] = *grabp++; 1738 ((uchar_t *)&(wbpb->bpb.sectors_in_logical_volume))[1] = *grabp++; 1739 ((uchar_t *)&(wbpb->bpb.sectors_in_logical_volume))[0] = *grabp++; 1740 wbpb->ebpb.phys_drive_num = *grabp++; 1741 wbpb->ebpb.reserved = *grabp++; 1742 wbpb->ebpb.ext_signature = *grabp++; 1743 ((uchar_t *)&(wbpb->ebpb.volume_id))[3] = *grabp++; 1744 ((uchar_t *)&(wbpb->ebpb.volume_id))[2] = *grabp++; 1745 ((uchar_t *)&(wbpb->ebpb.volume_id))[1] = *grabp++; 1746 ((uchar_t *)&(wbpb->ebpb.volume_id))[0] = *grabp++; 1747 1748 (void) strncpy((char *)wbpb->ebpb.volume_label, (char *)grabp, 11); 1749 grabp += 11; 1750 (void) strncpy((char *)wbpb->ebpb.type, (char *)grabp, 8); 1751 } 1752 1753 static 1754 void 1755 swap_pack_grabsebpb(bpb_t *wbpb, struct _boot_sector *bsp) 1756 { 1757 uchar_t *grabp; 1758 1759 grabp = bsp->bs_sun_bpb; 1760 ((uchar_t *)&(wbpb->sunbpb.bs_offset_high))[1] = *grabp++; 1761 ((uchar_t *)&(wbpb->sunbpb.bs_offset_high))[0] = *grabp++; 1762 ((uchar_t *)&(wbpb->sunbpb.bs_offset_low))[1] = *grabp++; 1763 ((uchar_t *)&(wbpb->sunbpb.bs_offset_low))[0] = *grabp++; 1764 } 1765 1766 static 1767 void 1768 swap_pack_grab32bpb(bpb_t *wbpb, struct _boot_sector *bsp) 1769 { 1770 uchar_t *grabp; 1771 1772 grabp = (uchar_t *)&(bsp->bs_filler[BPB_32_START_INDEX]); 1773 1774 ((uchar_t *)&(wbpb->bpb32.big_sectors_per_fat))[3] = *grabp++; 1775 ((uchar_t *)&(wbpb->bpb32.big_sectors_per_fat))[2] = *grabp++; 1776 ((uchar_t *)&(wbpb->bpb32.big_sectors_per_fat))[1] = *grabp++; 1777 ((uchar_t *)&(wbpb->bpb32.big_sectors_per_fat))[0] = *grabp++; 1778 ((uchar_t *)&(wbpb->bpb32.ext_flags))[1] = *grabp++; 1779 ((uchar_t *)&(wbpb->bpb32.ext_flags))[0] = *grabp++; 1780 wbpb->bpb32.fs_vers_lo = *grabp++; 1781 wbpb->bpb32.fs_vers_hi = *grabp++; 1782 ((uchar_t *)&(wbpb->bpb32.root_dir_clust))[3] = *grabp++; 1783 ((uchar_t *)&(wbpb->bpb32.root_dir_clust))[2] = *grabp++; 1784 ((uchar_t *)&(wbpb->bpb32.root_dir_clust))[1] = *grabp++; 1785 ((uchar_t *)&(wbpb->bpb32.root_dir_clust))[0] = *grabp++; 1786 ((uchar_t *)&(wbpb->bpb32.fsinfosec))[1] = *grabp++; 1787 ((uchar_t *)&(wbpb->bpb32.fsinfosec))[0] = *grabp++; 1788 ((uchar_t *)&(wbpb->bpb32.backupboot))[1] = *grabp++; 1789 ((uchar_t *)&(wbpb->bpb32.backupboot))[0] = *grabp++; 1790 ((uchar_t *)&(wbpb->bpb32.reserved[0]))[1] = *grabp++; 1791 ((uchar_t *)&(wbpb->bpb32.reserved[0]))[0] = *grabp++; 1792 ((uchar_t *)&(wbpb->bpb32.reserved[1]))[1] = *grabp++; 1793 ((uchar_t *)&(wbpb->bpb32.reserved[1]))[0] = *grabp++; 1794 ((uchar_t *)&(wbpb->bpb32.reserved[2]))[1] = *grabp++; 1795 ((uchar_t *)&(wbpb->bpb32.reserved[2]))[0] = *grabp++; 1796 ((uchar_t *)&(wbpb->bpb32.reserved[3]))[1] = *grabp++; 1797 ((uchar_t *)&(wbpb->bpb32.reserved[3]))[0] = *grabp++; 1798 ((uchar_t *)&(wbpb->bpb32.reserved[4]))[1] = *grabp++; 1799 ((uchar_t *)&(wbpb->bpb32.reserved[4]))[0] = *grabp++; 1800 ((uchar_t *)&(wbpb->bpb32.reserved[5]))[1] = *grabp++; 1801 ((uchar_t *)&(wbpb->bpb32.reserved[5]))[0] = *grabp++; 1802 } 1803 #endif /* ! i386 */ 1804 1805 static 1806 void 1807 dashm_bail(int fd) 1808 { 1809 (void) fprintf(stderr, 1810 gettext("This media does not appear to be " 1811 "formatted with a FAT file system.\n")); 1812 (void) close(fd); 1813 exit(6); 1814 } 1815 1816 /* 1817 * read_existing_bpb 1818 * 1819 * Grab the first sector, which we think is a bios parameter block. 1820 * If it looks bad, bail. Otherwise fill in the parameter struct 1821 * fields that matter. 1822 */ 1823 static 1824 void 1825 read_existing_bpb(int fd, bpb_t *wbpb) 1826 { 1827 boot_sector_t ubpb; 1828 1829 if (read(fd, ubpb.buf, BPSEC) < BPSEC) { 1830 perror(gettext("Read BIOS parameter block " 1831 "from previously formatted media")); 1832 (void) close(fd); 1833 exit(6); 1834 } 1835 1836 if (ltohs(ubpb.mb.signature) != BOOTSECSIG) { 1837 dashm_bail(fd); 1838 } 1839 1840 #ifdef i386 1841 (void) memcpy(&(wbpb->bpb), &(ubpb.bs.bs_front.bs_bpb), 1842 sizeof (wbpb->bpb)); 1843 (void) memcpy(&(wbpb->ebpb), &(ubpb.bs.bs_ebpb), sizeof (wbpb->ebpb)); 1844 #else 1845 swap_pack_grabbpb(wbpb, &(ubpb.bs)); 1846 #endif 1847 if (SunBPBfields) { 1848 #ifdef i386 1849 (void) memcpy(&(wbpb->sunbpb), &(ubpb.bs.bs_sebpb), 1850 sizeof (wbpb->sunbpb)); 1851 #else 1852 swap_pack_grabsebpb(wbpb, &(ubpb.bs)); 1853 #endif 1854 } 1855 if (wbpb->bpb.bytes_sector != BPSEC) { 1856 (void) fprintf(stderr, 1857 gettext("Bogus bytes per sector value.\n")); 1858 if (!(ISP2(wbpb->bpb.bytes_sector) && 1859 IN_RANGE(wbpb->bpb.bytes_sector, 1, BPSEC * 8))) { 1860 (void) fprintf(stderr, 1861 gettext("The device name may be missing a " 1862 "logical drive specifier.\n")); 1863 (void) close(fd); 1864 exit(6); 1865 } else { 1866 (void) fprintf(stderr, 1867 gettext("Do not know how to build FATs with a\n" 1868 "non-standard sector size. Standard " 1869 "size is %d bytes,\nyour sector size " 1870 "is %d bytes.\n"), BPSEC, 1871 wbpb->bpb.bytes_sector); 1872 (void) close(fd); 1873 exit(6); 1874 } 1875 } 1876 if (!(ISP2(wbpb->bpb.sectors_per_cluster) && 1877 IN_RANGE(wbpb->bpb.sectors_per_cluster, 1, 128))) { 1878 (void) fprintf(stderr, 1879 gettext("Bogus sectors per cluster value.\n")); 1880 (void) fprintf(stderr, 1881 gettext("The device name may be missing a " 1882 "logical drive specifier.\n")); 1883 (void) close(fd); 1884 exit(6); 1885 } 1886 1887 if (wbpb->bpb.sectors_per_fat == 0) { 1888 #ifdef i386 1889 (void) memcpy(&(wbpb->bpb32), &(ubpb.bs32.bs_bpb32), 1890 sizeof (wbpb->bpb32)); 1891 #else 1892 swap_pack_grab32bpb(wbpb, &(ubpb.bs)); 1893 #endif 1894 compute_file_area_size(wbpb); 1895 if ((wbpb->bpb32.big_sectors_per_fat * BPSEC / 4) >= 1896 TotalClusters) { 1897 MakeFAT32 = 1; 1898 } else { 1899 dashm_bail(fd); 1900 } 1901 } else { 1902 compute_file_area_size(wbpb); 1903 } 1904 } 1905 1906 /* 1907 * compare_existing_with_computed 1908 * 1909 * We use this function when we the user specifies the -m option. 1910 * We compute and look up things like we would if they had asked 1911 * us to make the fs, and compare that to what's already layed down 1912 * in the existing fs. If there's a difference we can tell them what 1913 * options to specify in order to reproduce their existing layout. 1914 * Note that they still may not get an exact duplicate, because we 1915 * don't, for example, preserve their existing boot code. We think 1916 * we've got all the fields that matter covered, though. 1917 * 1918 * XXX - We're basically ignoring sbpb at this point. I'm unsure 1919 * if we'll ever care about those fields, in terms of the -m option. 1920 */ 1921 static 1922 void 1923 compare_existing_with_computed(int fd, char *suffix, 1924 bpb_t *wbpb, int *prtsize, int *prtspc, int *prtbpf, int *prtnsect, 1925 int *prtntrk, int *prtfdisk, int *prthidden, int *prtrsrvd, int *dashos) 1926 { 1927 struct dk_geom dginfo; 1928 struct fd_char fdchar; 1929 bpb_t compare; 1930 int fd_ioctl_worked = 0; 1931 int fatents; 1932 1933 /* 1934 * For all non-floppy cases we expect to find a 16-bit FAT 1935 */ 1936 int expectfatsize = 16; 1937 1938 compare = *wbpb; 1939 1940 if (!suffix) { 1941 if (ioctl(fd, FDIOGCHAR, &fdchar) != -1) { 1942 expectfatsize = 12; 1943 fd_ioctl_worked++; 1944 } 1945 } 1946 1947 if (fd_ioctl_worked) { 1948 #ifdef sparc 1949 fdchar.fdc_medium = 3; 1950 #endif 1951 GetSize = GetSPT = GetSPC = GetTPC = GetBPF = 1; 1952 lookup_floppy(&fdchar, &compare); 1953 if (compare.bpb.heads != wbpb->bpb.heads) { 1954 (*prtntrk)++; 1955 (*dashos)++; 1956 } 1957 if (compare.bpb.sectors_per_track != 1958 wbpb->bpb.sectors_per_track) { 1959 (*prtnsect)++; 1960 (*dashos)++; 1961 } 1962 } else { 1963 int dk_ioctl_worked = 1; 1964 1965 if (!suffix) { 1966 (*prtfdisk)++; 1967 (*prtsize)++; 1968 *dashos += 2; 1969 } 1970 if (ioctl(fd, DKIOCG_VIRTGEOM, &dginfo) == -1 && 1971 ioctl(fd, DKIOCG_PHYGEOM, &dginfo) == -1 && 1972 ioctl(fd, DKIOCGGEOM, &dginfo) == -1) { 1973 *prtnsect = *prtntrk = 1; 1974 *dashos += 2; 1975 dk_ioctl_worked = 0; 1976 } 1977 if (dk_ioctl_worked) { 1978 if (dginfo.dkg_nhead != wbpb->bpb.heads) { 1979 (*prtntrk)++; 1980 (*dashos)++; 1981 } 1982 if (dginfo.dkg_nsect != 1983 wbpb->bpb.sectors_per_track) { 1984 (*prtnsect)++; 1985 (*dashos)++; 1986 } 1987 } 1988 GetBPF = GetSPC = 1; 1989 compute_cluster_size(&compare); 1990 } 1991 1992 if (!*prtfdisk && TotSize != wbpb->bpb.sectors_in_volume && 1993 TotSize != wbpb->bpb.sectors_in_logical_volume) { 1994 (*dashos)++; 1995 (*prtsize)++; 1996 } 1997 1998 if (compare.bpb.sectors_per_cluster != wbpb->bpb.sectors_per_cluster) { 1999 (*dashos)++; 2000 (*prtspc)++; 2001 } 2002 2003 if (compare.bpb.hidden_sectors != wbpb->bpb.hidden_sectors) { 2004 (*dashos)++; 2005 (*prthidden)++; 2006 } 2007 2008 if (compare.bpb.resv_sectors != wbpb->bpb.resv_sectors) { 2009 (*dashos)++; 2010 (*prtrsrvd)++; 2011 } 2012 2013 /* 2014 * Compute approximate Fatentsize. It's approximate because the 2015 * size of the FAT may not be exactly a multiple of the number of 2016 * clusters. It should be close, though. 2017 */ 2018 if (MakeFAT32) { 2019 Fatentsize = 32; 2020 (*dashos)++; 2021 (*prtbpf)++; 2022 } else { 2023 fatents = wbpb->bpb.sectors_per_fat * BPSEC * 2 / 3; 2024 if (fatents >= TotalClusters && wbpb->ebpb.type[4] == '2') 2025 Fatentsize = 12; 2026 else 2027 Fatentsize = 16; 2028 if (Fatentsize != expectfatsize) { 2029 (*dashos)++; 2030 (*prtbpf)++; 2031 } 2032 } 2033 } 2034 2035 static 2036 void 2037 print_reproducing_command(int fd, char *actualdisk, char *suffix, bpb_t *wbpb) 2038 { 2039 int needcomma = 0; 2040 int prthidden = 0; 2041 int prtrsrvd = 0; 2042 int prtfdisk = 0; 2043 int prtnsect = 0; 2044 int prtntrk = 0; 2045 int prtsize = 0; 2046 int prtbpf = 0; 2047 int prtspc = 0; 2048 int dashos = 0; 2049 int ll, i; 2050 2051 compare_existing_with_computed(fd, suffix, wbpb, 2052 &prtsize, &prtspc, &prtbpf, &prtnsect, &prtntrk, 2053 &prtfdisk, &prthidden, &prtrsrvd, &dashos); 2054 2055 /* 2056 * Print out the command line they can use to reproduce the 2057 * file system. 2058 */ 2059 (void) printf("mkfs -F pcfs"); 2060 2061 ll = min(11, (int)strlen((char *)wbpb->ebpb.volume_label)); 2062 /* 2063 * First, eliminate trailing spaces. Now compare the name against 2064 * our default label. If there's a match we don't need to print 2065 * any label info. 2066 */ 2067 i = ll; 2068 while (wbpb->ebpb.volume_label[--i] == ' ') 2069 ; 2070 ll = i; 2071 2072 if (ll == strlen(DEFAULT_LABEL) - 1) { 2073 char cmpbuf[11]; 2074 2075 (void) strcpy(cmpbuf, DEFAULT_LABEL); 2076 for (i = ll; i >= 0; i--) { 2077 if (cmpbuf[i] != 2078 toupper((int)(wbpb->ebpb.volume_label[i]))) { 2079 break; 2080 } 2081 } 2082 if (i < 0) 2083 ll = i; 2084 } 2085 2086 if (ll >= 0) { 2087 (void) printf(" -o "); 2088 (void) printf("b=\""); 2089 for (i = 0; i <= ll; i++) { 2090 (void) printf("%c", wbpb->ebpb.volume_label[i]); 2091 } 2092 (void) printf("\""); 2093 needcomma++; 2094 } else if (dashos) { 2095 (void) printf(" -o "); 2096 } 2097 2098 #define NEXT_DASH_O dashos--; needcomma++; continue 2099 2100 while (dashos) { 2101 if (needcomma) { 2102 (void) printf(","); 2103 needcomma = 0; 2104 } 2105 if (prtfdisk) { 2106 (void) printf("nofdisk"); 2107 prtfdisk--; 2108 NEXT_DASH_O; 2109 } 2110 if (prtsize) { 2111 (void) printf("size=%u", wbpb->bpb.sectors_in_volume ? 2112 wbpb->bpb.sectors_in_volume : 2113 wbpb->bpb.sectors_in_logical_volume); 2114 prtsize--; 2115 NEXT_DASH_O; 2116 } 2117 if (prtnsect) { 2118 (void) printf("nsect=%d", wbpb->bpb.sectors_per_track); 2119 prtnsect--; 2120 NEXT_DASH_O; 2121 } 2122 if (prtspc) { 2123 (void) printf("spc=%d", wbpb->bpb.sectors_per_cluster); 2124 prtspc--; 2125 NEXT_DASH_O; 2126 } 2127 if (prtntrk) { 2128 (void) printf("ntrack=%d", wbpb->bpb.heads); 2129 prtntrk--; 2130 NEXT_DASH_O; 2131 } 2132 if (prtbpf) { 2133 (void) printf("fat=%d", Fatentsize); 2134 prtbpf--; 2135 NEXT_DASH_O; 2136 } 2137 if (prthidden) { 2138 (void) printf("hidden=%u", wbpb->bpb.hidden_sectors); 2139 prthidden--; 2140 NEXT_DASH_O; 2141 } 2142 if (prtrsrvd) { 2143 (void) printf("reserve=%d", wbpb->bpb.resv_sectors); 2144 prtrsrvd--; 2145 NEXT_DASH_O; 2146 } 2147 } 2148 2149 (void) printf(" %s%c%c\n", actualdisk, 2150 suffix ? ':' : '\0', suffix ? *suffix : '\0'); 2151 } 2152 2153 /* 2154 * open_and_examine 2155 * 2156 * Open the requested 'dev_name'. Seek to point where 2157 * we'd expect to find boot sectors, etc., based on any ':partition' 2158 * attachments to the dev_name. 2159 * 2160 * Examine the fields of any existing boot sector and display best 2161 * approximation of how this fs could be reproduced with this command. 2162 */ 2163 static 2164 int 2165 open_and_examine(char *dn, bpb_t *wbpb) 2166 { 2167 struct stat di; 2168 off64_t ignored; 2169 char *actualdisk = NULL; 2170 char *suffix = NULL; 2171 int fd; 2172 struct dk_minfo dkminfo; 2173 2174 if (Verbose) 2175 (void) printf(gettext("Opening destination device/file.\n")); 2176 2177 actualdisk = stat_actual_disk(dn, &di, &suffix); 2178 2179 /* 2180 * Destination exists, now find more about it. 2181 */ 2182 if (!(S_ISCHR(di.st_mode))) { 2183 (void) fprintf(stderr, 2184 gettext("\n%s: device name must be a " 2185 "character special device.\n"), actualdisk); 2186 exit(2); 2187 } else if ((fd = open(actualdisk, O_RDWR)) < 0) { 2188 perror(actualdisk); 2189 exit(2); 2190 } 2191 2192 /* 2193 * Check the media sector size 2194 */ 2195 if (ioctl(fd, DKIOCGMEDIAINFO, &dkminfo) != -1) { 2196 if (dkminfo.dki_lbsize != 0 && 2197 ISP2(dkminfo.dki_lbsize / DEV_BSIZE) && 2198 dkminfo.dki_lbsize != DEV_BSIZE) { 2199 (void) fprintf(stderr, 2200 gettext("The device sector size %u is not " 2201 "supported by pcfs!\n"), dkminfo.dki_lbsize); 2202 (void) close(fd); 2203 exit(1); 2204 } 2205 } 2206 2207 /* 2208 * Find appropriate partition if we were requested to do so. 2209 */ 2210 if (suffix && !(seek_partn(fd, suffix, wbpb, &ignored))) { 2211 (void) close(fd); 2212 exit(2); 2213 } 2214 2215 read_existing_bpb(fd, wbpb); 2216 print_reproducing_command(fd, actualdisk, suffix, wbpb); 2217 2218 return (fd); 2219 } 2220 2221 /* 2222 * getdiskinfo 2223 * 2224 * Extracts information about disk path in dn. We need to return both a 2225 * file descriptor and the device's suffix. 2226 * Secondarily, we need to detect the FAT type and size when dealing with 2227 * GPT partitions. 2228 */ 2229 static int 2230 getdiskinfo(char *dn, char **suffix) 2231 { 2232 struct dk_minfo dkminfo; 2233 struct stat di; 2234 int rv, fd, reserved; 2235 char *actualdisk = NULL; 2236 dk_gpt_t *gpt = NULL; 2237 2238 actualdisk = stat_actual_disk(dn, &di, suffix); 2239 2240 /* 2241 * Destination exists, now find more about it. 2242 */ 2243 if (!(S_ISCHR(di.st_mode))) { 2244 (void) fprintf(stderr, 2245 gettext("Device name must indicate a " 2246 "character special device: %s\n"), actualdisk); 2247 exit(2); 2248 } else if ((fd = open(actualdisk, O_RDWR)) < 0) { 2249 perror(actualdisk); 2250 exit(2); 2251 } 2252 2253 /* 2254 * Check the media sector size 2255 */ 2256 if (ioctl(fd, DKIOCGMEDIAINFO, &dkminfo) != -1) { 2257 if (dkminfo.dki_lbsize != 0 && 2258 ISP2(dkminfo.dki_lbsize / DEV_BSIZE) && 2259 dkminfo.dki_lbsize != DEV_BSIZE) { 2260 (void) fprintf(stderr, 2261 gettext("The device sector size %u is not " 2262 "supported by pcfs!\n"), dkminfo.dki_lbsize); 2263 (void) close(fd); 2264 exit(2); 2265 } 2266 } 2267 2268 rv = efi_alloc_and_read(fd, &gpt); 2269 /* 2270 * We should see only VT_EINVAL, VT_EIO and VT_ERROR. 2271 * VT_EINVAL is for the case there is no GPT label. 2272 * VT_ERROR will happen if device does no support the ioctl, so 2273 * we will exit only in case of VT_EIO and unknown value of rv. 2274 */ 2275 if (rv < 0 && rv != VT_EINVAL && rv != VT_ERROR) { 2276 switch (rv) { 2277 case VT_EIO: 2278 (void) fprintf(stderr, 2279 gettext("IO Error reading EFI label\n")); 2280 break; 2281 default: 2282 (void) fprintf(stderr, 2283 gettext("Unknown Error %d reading EFI label\n"), 2284 rv); 2285 break; 2286 } 2287 (void) close(fd); 2288 exit(2); 2289 } 2290 if (rv >= 0) { 2291 DontUseFdisk = 1; 2292 if (*suffix != NULL) { 2293 (void) fprintf(stderr, 2294 gettext("Can not use drive specifier \"%s\" with " 2295 "GPT partitioning.\n"), *suffix); 2296 efi_free(gpt); 2297 (void) close(fd); 2298 exit(2); 2299 } 2300 /* Can not use whole disk, 7 is GPT minor node "wd" */ 2301 if (rv == 7) { 2302 (void) fprintf(stderr, 2303 gettext("Device name must indicate a " 2304 "partition: %s\n"), actualdisk); 2305 efi_free(gpt); 2306 (void) close(fd); 2307 exit(2); 2308 } 2309 2310 if (GetSize == 1) { 2311 TotSize = gpt->efi_parts[rv].p_size; 2312 GetSize = 0; 2313 } 2314 2315 if (GetBPF == 1) { 2316 if (GetResrvd == 1) { 2317 /* FAT32 has 32 reserved sectors */ 2318 reserved = 32; 2319 } else { 2320 reserved = Resrvd; 2321 } 2322 /* 2323 * The type of FAT is determined by the size of 2324 * the partition - reserved sectors. 2325 * The calculation is based on logic used in 2326 * compute_cluster_size() and therefore we will not 2327 * get into error situation when 2328 * compute_cluster_size() will be called. 2329 */ 2330 if (TotSize - reserved < FAT16_MAX_CLUSTERS) { 2331 if (GetResrvd == 1) 2332 reserved = 1; 2333 2334 if (TotSize - reserved < FAT12_MAX_CLUSTERS) { 2335 int spc; 2336 MakeFAT32 = 0; 2337 Fatentsize = 12; 2338 /* 2339 * compute sectors per cluster 2340 * for fat12 2341 */ 2342 for (spc = 1; spc <= 64; 2343 spc = spc * 2) { 2344 if (TotSize - reserved < 2345 spc * FAT12_MAX_CLUSTERS) 2346 break; 2347 } 2348 if (GetSPC == 1) { 2349 GetSPC = 0; 2350 SecPerClust = spc; 2351 } 2352 } else { 2353 MakeFAT32 = 0; 2354 Fatentsize = 16; 2355 } 2356 } else { 2357 MakeFAT32 = 1; 2358 Fatentsize = 32; 2359 } 2360 } 2361 efi_free(gpt); 2362 } 2363 return (fd); 2364 } 2365 2366 /* 2367 * open_and_seek 2368 * 2369 * Open the requested 'dev_name'. Seek to point where 2370 * we'll write boot sectors, etc., based on any ':partition' 2371 * attachments to the dev_name. 2372 * 2373 * By the time we are finished here, the entire BPB will be 2374 * filled in, excepting the volume label. 2375 */ 2376 static 2377 int 2378 open_and_seek(char *dn, bpb_t *wbpb, off64_t *seekto) 2379 { 2380 struct fd_char fdchar; 2381 struct dk_geom dg; 2382 char *actualdisk = NULL; 2383 char *suffix = NULL; 2384 int fd; 2385 2386 if (Verbose) 2387 (void) printf(gettext("Opening destination device/file.\n")); 2388 2389 /* 2390 * We hold these truths to be self evident, all BPBs we create 2391 * will have these values in these fields. 2392 */ 2393 wbpb->bpb.num_fats = 2; 2394 wbpb->bpb.bytes_sector = BPSEC; 2395 2396 /* 2397 * Assign or use supplied numbers for hidden and 2398 * reserved sectors in the file system. 2399 */ 2400 if (GetResrvd) 2401 if (MakeFAT32) 2402 wbpb->bpb.resv_sectors = 32; 2403 else 2404 wbpb->bpb.resv_sectors = 1; 2405 else 2406 wbpb->bpb.resv_sectors = Resrvd; 2407 2408 wbpb->ebpb.ext_signature = 0x29; /* Magic number for modern format */ 2409 wbpb->ebpb.volume_id = 0; 2410 2411 if (MakeFAT32) 2412 fill_fat32_bpb(wbpb); 2413 2414 /* 2415 * If all output goes to a simple file, call a routine to setup 2416 * that scenario. Otherwise, try to find the device. 2417 */ 2418 if (Outputtofile) 2419 return (prepare_image_file(dn, wbpb)); 2420 2421 /* Collect info about device */ 2422 fd = getdiskinfo(dn, &suffix); 2423 2424 /* 2425 * Sanity check. If we've been provided a partition-specifying 2426 * suffix, we shouldn't also have been told to ignore the 2427 * fdisk table. 2428 */ 2429 if (DontUseFdisk && suffix) { 2430 (void) fprintf(stderr, 2431 gettext("Using 'nofdisk' option precludes " 2432 "appending logical drive\nspecifier " 2433 "to the device name.\n")); 2434 goto err_out; 2435 } 2436 2437 /* 2438 * Find appropriate partition if we were requested to do so. 2439 */ 2440 if (suffix && !(seek_partn(fd, suffix, wbpb, seekto))) 2441 goto err_out; 2442 2443 if (!suffix) { 2444 /* 2445 * We have one of two possibilities. Chances are we have 2446 * a floppy drive. But the user may be trying to format 2447 * some weird drive that we don't know about and is supplying 2448 * all the important values. In that case, they should have set 2449 * the 'nofdisk' flag. 2450 * 2451 * If 'nofdisk' isn't set, do a floppy-specific ioctl to 2452 * get the remainder of our info. If the ioctl fails, we have 2453 * a good idea that they aren't really on a floppy. In that 2454 * case, they should have given us a partition specifier. 2455 */ 2456 if (DontUseFdisk) { 2457 if (!(seek_nofdisk(fd, wbpb, seekto))) 2458 goto err_out; 2459 2460 find_fixed_details(fd, wbpb); 2461 } else if (ioctl(fd, FDIOGCHAR, &fdchar) == -1) { 2462 /* 2463 * It is possible that we are trying to use floppy 2464 * specific FDIOGCHAR ioctl on USB floppy. Since sd 2465 * driver, by which USB floppy is handled, doesn't 2466 * support it, we can try to use disk DKIOCGGEOM ioctl 2467 * to retrieve data we need. sd driver itself 2468 * determines floppy disk by number of blocks 2469 * (<=0x1000), then it sets geometry to 80 cylinders, 2470 * 2 heads. 2471 * 2472 * Note that DKIOCGGEOM cannot supply us with type 2473 * of media (e.g. 3.5" or 5.25"). We will set it to 2474 * 3 (3.5") which is most probable value. 2475 */ 2476 if (errno == ENOTTY) { 2477 if (ioctl(fd, DKIOCGGEOM, &dg) != -1 && 2478 dg.dkg_ncyl == 80 && dg.dkg_nhead == 2) { 2479 fdchar.fdc_ncyl = dg.dkg_ncyl; 2480 fdchar.fdc_medium = 3; 2481 fdchar.fdc_secptrack = dg.dkg_nsect; 2482 fdchar.fdc_nhead = dg.dkg_nhead; 2483 lookup_floppy(&fdchar, wbpb); 2484 } else { 2485 partn_lecture(actualdisk); 2486 goto err_out; 2487 } 2488 } 2489 } else { 2490 #ifdef sparc 2491 fdchar.fdc_medium = 3; 2492 #endif 2493 lookup_floppy(&fdchar, wbpb); 2494 } 2495 } else { 2496 find_fixed_details(fd, wbpb); 2497 } 2498 2499 return (fd); 2500 2501 err_out: 2502 (void) close(fd); 2503 exit(2); 2504 } 2505 2506 /* 2507 * The following is a copy of MS-DOS 4.0 boot block. 2508 * It consists of the BIOS parameter block, and a disk 2509 * bootstrap program. 2510 * 2511 * The BIOS parameter block contains the right values 2512 * for the 3.5" high-density 1.44MB floppy format. 2513 * 2514 * This will be our default boot sector, if the user 2515 * didn't point us at a different one. 2516 * 2517 */ 2518 static 2519 uchar_t DefBootSec[512] = { 2520 0xeb, 0x3c, 0x90, /* 8086 short jump + displacement + NOP */ 2521 'M', 'S', 'D', 'O', 'S', '4', '.', '0', /* OEM name & version */ 2522 0x00, 0x02, 0x01, 0x01, 0x00, 2523 0x02, 0xe0, 0x00, 0x40, 0x0b, 2524 0xf0, 0x09, 0x00, 0x12, 0x00, 2525 0x02, 0x00, 2526 0x00, 0x00, 0x00, 0x00, 2527 0x00, 0x00, 0x00, 0x00, 2528 0x00, 0x00, 2529 0x29, 0x00, 0x00, 0x00, 0x00, 2530 'N', 'O', 'N', 'A', 'M', 'E', ' ', ' ', ' ', ' ', ' ', 2531 'F', 'A', 'T', '1', '2', ' ', ' ', ' ', 2532 0xfa, 0x33, 2533 0xc0, 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0x16, 0x07, 2534 0xbb, 0x78, 0x00, 0x36, 0xc5, 0x37, 0x1e, 0x56, 2535 0x16, 0x53, 0xbf, 0x3e, 0x7c, 0xb9, 0x0b, 0x00, 2536 0xfc, 0xf3, 0xa4, 0x06, 0x1f, 0xc6, 0x45, 0xfe, 2537 0x0f, 0x8b, 0x0e, 0x18, 0x7c, 0x88, 0x4d, 0xf9, 2538 0x89, 0x47, 0x02, 0xc7, 0x07, 0x3e, 0x7c, 0xfb, 2539 0xcd, 0x13, 0x72, 0x7c, 0x33, 0xc0, 0x39, 0x06, 2540 0x13, 0x7c, 0x74, 0x08, 0x8b, 0x0e, 0x13, 0x7c, 2541 0x89, 0x0e, 0x20, 0x7c, 0xa0, 0x10, 0x7c, 0xf7, 2542 0x26, 0x16, 0x7c, 0x03, 0x06, 0x1c, 0x7c, 0x13, 2543 0x16, 0x1e, 0x7c, 0x03, 0x06, 0x0e, 0x7c, 0x83, 2544 0xd2, 0x00, 0xa3, 0x50, 0x7c, 0x89, 0x16, 0x52, 2545 0x7c, 0xa3, 0x49, 0x7c, 0x89, 0x16, 0x4b, 0x7c, 2546 0xb8, 0x20, 0x00, 0xf7, 0x26, 0x11, 0x7c, 0x8b, 2547 0x1e, 0x0b, 0x7c, 0x03, 0xc3, 0x48, 0xf7, 0xf3, 2548 0x01, 0x06, 0x49, 0x7c, 0x83, 0x16, 0x4b, 0x7c, 2549 0x00, 0xbb, 0x00, 0x05, 0x8b, 0x16, 0x52, 0x7c, 2550 0xa1, 0x50, 0x7c, 0xe8, 0x87, 0x00, 0x72, 0x20, 2551 0xb0, 0x01, 0xe8, 0xa1, 0x00, 0x72, 0x19, 0x8b, 2552 0xfb, 0xb9, 0x0b, 0x00, 0xbe, 0xdb, 0x7d, 0xf3, 2553 0xa6, 0x75, 0x0d, 0x8d, 0x7f, 0x20, 0xbe, 0xe6, 2554 0x7d, 0xb9, 0x0b, 0x00, 0xf3, 0xa6, 0x74, 0x18, 2555 0xbe, 0x93, 0x7d, 0xe8, 0x51, 0x00, 0x32, 0xe4, 2556 0xcd, 0x16, 0x5e, 0x1f, 0x8f, 0x04, 0x8f, 0x44, 2557 0x02, 0xcd, 0x19, 0x58, 0x58, 0x58, 0xeb, 0xe8, 2558 0xbb, 0x00, 0x07, 0xb9, 0x03, 0x00, 0xa1, 0x49, 2559 0x7c, 0x8b, 0x16, 0x4b, 0x7c, 0x50, 0x52, 0x51, 2560 0xe8, 0x3a, 0x00, 0x72, 0xe6, 0xb0, 0x01, 0xe8, 2561 0x54, 0x00, 0x59, 0x5a, 0x58, 0x72, 0xc9, 0x05, 2562 0x01, 0x00, 0x83, 0xd2, 0x00, 0x03, 0x1e, 0x0b, 2563 0x7c, 0xe2, 0xe2, 0x8a, 0x2e, 0x15, 0x7c, 0x8a, 2564 0x16, 0x24, 0x7c, 0x8b, 0x1e, 0x49, 0x7c, 0xa1, 2565 0x4b, 0x7c, 0xea, 0x00, 0x00, 0x70, 0x00, 0xac, 2566 0x0a, 0xc0, 0x74, 0x29, 0xb4, 0x0e, 0xbb, 0x07, 2567 0x00, 0xcd, 0x10, 0xeb, 0xf2, 0x3b, 0x16, 0x18, 2568 0x7c, 0x73, 0x19, 0xf7, 0x36, 0x18, 0x7c, 0xfe, 2569 0xc2, 0x88, 0x16, 0x4f, 0x7c, 0x33, 0xd2, 0xf7, 2570 0x36, 0x1a, 0x7c, 0x88, 0x16, 0x25, 0x7c, 0xa3, 2571 0x4d, 0x7c, 0xf8, 0xc3, 0xf9, 0xc3, 0xb4, 0x02, 2572 0x8b, 0x16, 0x4d, 0x7c, 0xb1, 0x06, 0xd2, 0xe6, 2573 0x0a, 0x36, 0x4f, 0x7c, 0x8b, 0xca, 0x86, 0xe9, 2574 0x8a, 0x16, 0x24, 0x7c, 0x8a, 0x36, 0x25, 0x7c, 2575 0xcd, 0x13, 0xc3, 0x0d, 0x0a, 0x4e, 0x6f, 0x6e, 2576 0x2d, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, 2577 0x64, 0x69, 0x73, 0x6b, 0x20, 0x6f, 0x72, 0x20, 2578 0x64, 0x69, 0x73, 0x6b, 0x20, 0x65, 0x72, 0x72, 2579 0x6f, 0x72, 0x0d, 0x0a, 0x52, 0x65, 0x70, 0x6c, 2580 0x61, 0x63, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 2581 0x70, 0x72, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6e, 2582 0x79, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x77, 0x68, 2583 0x65, 0x6e, 0x20, 0x72, 0x65, 0x61, 0x64, 0x79, 2584 0x0d, 0x0a, 0x00, 0x49, 0x4f, 0x20, 0x20, 0x20, 2585 0x20, 0x20, 0x20, 0x53, 0x59, 0x53, 0x4d, 0x53, 2586 0x44, 0x4f, 0x53, 0x20, 0x20, 0x20, 0x53, 0x59, 2587 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2588 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa 2589 }; 2590 2591 /* 2592 * verify_bootblkfile 2593 * 2594 * We were provided with the name of a file containing the bootblk 2595 * to install. Verify it has a valid boot sector as best we can. Any 2596 * errors and we return a bad file descriptor. Otherwise we fill up the 2597 * provided buffer with the boot sector, return the file 2598 * descriptor for later use and leave the file pointer just 2599 * past the boot sector part of the boot block file. 2600 */ 2601 static 2602 int 2603 verify_bootblkfile(char *fn, boot_sector_t *bs, ulong_t *blkfilesize) 2604 { 2605 struct stat fi; 2606 int bsfd = -1; 2607 2608 if (stat(fn, &fi)) { 2609 perror(fn); 2610 } else if (fi.st_size < BPSEC) { 2611 (void) fprintf(stderr, 2612 gettext("%s: Too short to be a boot sector.\n"), fn); 2613 } else if ((bsfd = open(fn, O_RDONLY)) < 0) { 2614 perror(fn); 2615 } else if (read(bsfd, bs->buf, BPSEC) < BPSEC) { 2616 (void) close(bsfd); 2617 bsfd = -1; 2618 perror(gettext("Boot block read")); 2619 } else { 2620 if ((bs->bs.bs_signature[0] != (BOOTSECSIG & 0xFF) && 2621 bs->bs.bs_signature[1] != ((BOOTSECSIG >> 8) & 0xFF)) || 2622 #ifdef i386 2623 (bs->bs.bs_front.bs_jump_code[0] != OPCODE1 && 2624 bs->bs.bs_front.bs_jump_code[0] != OPCODE2) 2625 #else 2626 (bs->bs.bs_jump_code[0] != OPCODE1 && 2627 bs->bs.bs_jump_code[0] != OPCODE2) 2628 #endif 2629 /* CSTYLED */ 2630 ) { 2631 (void) close(bsfd); 2632 bsfd = -1; 2633 (void) fprintf(stderr, 2634 gettext("Boot block (%s) bogus.\n"), fn); 2635 } 2636 *blkfilesize = fi.st_size; 2637 } 2638 return (bsfd); 2639 } 2640 2641 /* 2642 * verify_firstfile 2643 * 2644 * We were provided with the name of a file to be the first file 2645 * installed on the disk. We just need to verify it exists and 2646 * find out how big it is. If it doesn't exist, we print a warning 2647 * message about how the file wasn't found. We don't exit fatally, 2648 * though, rather we return a size of 0 and the FAT will be built 2649 * without installing any first file. They can then presumably 2650 * install the correct first file by hand. 2651 */ 2652 static 2653 int 2654 verify_firstfile(char *fn, ulong_t *filesize) 2655 { 2656 struct stat fi; 2657 int fd = -1; 2658 2659 *filesize = 0; 2660 if (stat(fn, &fi) || (fd = open(fn, O_RDONLY)) < 0) { 2661 perror(fn); 2662 (void) fprintf(stderr, 2663 gettext("Could not access requested file. It will not\n" 2664 "be installed in the new file system.\n")); 2665 } else { 2666 *filesize = fi.st_size; 2667 } 2668 2669 return (fd); 2670 } 2671 2672 /* 2673 * label_volume 2674 * 2675 * Fill in BPB with volume label. 2676 */ 2677 static 2678 void 2679 label_volume(char *lbl, bpb_t *wbpb) 2680 { 2681 int ll, i; 2682 2683 /* Put a volume label into our BPB. */ 2684 if (!lbl) 2685 lbl = DEFAULT_LABEL; 2686 2687 ll = min(11, (int)strlen(lbl)); 2688 for (i = 0; i < ll; i++) { 2689 wbpb->ebpb.volume_label[i] = toupper(lbl[i]); 2690 } 2691 for (; i < 11; i++) { 2692 wbpb->ebpb.volume_label[i] = ' '; 2693 } 2694 } 2695 2696 static 2697 int 2698 copy_bootblk(char *fn, boot_sector_t *bootsect, ulong_t *bootblksize) 2699 { 2700 int bsfd = -1; 2701 2702 if (Verbose && fn) 2703 (void) printf(gettext("Request to install boot " 2704 "block file %s.\n"), fn); 2705 else if (Verbose) 2706 (void) printf(gettext("Request to install DOS boot block.\n")); 2707 2708 /* 2709 * If they want to install their own boot block, sanity check 2710 * that block. 2711 */ 2712 if (fn) { 2713 bsfd = verify_bootblkfile(fn, bootsect, bootblksize); 2714 if (bsfd < 0) { 2715 exit(3); 2716 } 2717 *bootblksize = roundup(*bootblksize, BPSEC); 2718 } else { 2719 (void) memcpy(bootsect, DefBootSec, BPSEC); 2720 *bootblksize = BPSEC; 2721 } 2722 2723 return (bsfd); 2724 } 2725 2726 /* 2727 * mark_cluster 2728 * 2729 * This routine fills a FAT entry with the value supplied to it as an 2730 * argument. The fatp argument is assumed to be a pointer to the FAT's 2731 * 0th entry. The clustnum is the cluster entry that should be updated. 2732 * The value is the new value for the entry. 2733 */ 2734 static 2735 void 2736 mark_cluster(uchar_t *fatp, pc_cluster32_t clustnum, uint32_t value) 2737 { 2738 uchar_t *ep; 2739 ulong_t idx; 2740 2741 idx = (Fatentsize == 32) ? clustnum * 4 : 2742 (Fatentsize == 16) ? clustnum * 2 : clustnum + clustnum/2; 2743 ep = fatp + idx; 2744 2745 if (Fatentsize == 32) { 2746 store_32_bits(&ep, value); 2747 } else if (Fatentsize == 16) { 2748 store_16_bits(&ep, value); 2749 } else { 2750 if (clustnum & 1) { 2751 *ep = (*ep & 0x0f) | ((value << 4) & 0xf0); 2752 ep++; 2753 *ep = (value >> 4) & 0xff; 2754 } else { 2755 *ep++ = value & 0xff; 2756 *ep = (*ep & 0xf0) | ((value >> 8) & 0x0f); 2757 } 2758 } 2759 } 2760 2761 static 2762 uchar_t * 2763 build_fat(bpb_t *wbpb, struct fat_od_fsi *fsinfop, ulong_t bootblksize, 2764 ulong_t *fatsize, char *ffn, int *fffd, ulong_t *ffsize, 2765 pc_cluster32_t *ffstartclust) 2766 { 2767 pc_cluster32_t nextfree, ci; 2768 uchar_t *fatp; 2769 ushort_t numclust, numsect; 2770 int remclust; 2771 2772 /* Alloc space for a FAT and then null it out. */ 2773 if (Verbose) { 2774 (void) printf(gettext("BUILD FAT.\n%d sectors per fat.\n"), 2775 wbpb->bpb.sectors_per_fat ? wbpb->bpb.sectors_per_fat : 2776 wbpb->bpb32.big_sectors_per_fat); 2777 } 2778 2779 if (MakeFAT32) { 2780 *fatsize = BPSEC * wbpb->bpb32.big_sectors_per_fat; 2781 } else { 2782 *fatsize = BPSEC * wbpb->bpb.sectors_per_fat; 2783 } 2784 2785 if (!(fatp = (uchar_t *)malloc(*fatsize))) { 2786 perror(gettext("FAT table alloc")); 2787 exit(4); 2788 } else { 2789 (void) memset(fatp, 0, *fatsize); 2790 } 2791 2792 /* Build in-memory FAT */ 2793 *fatp = wbpb->bpb.media; 2794 *(fatp + 1) = 0xFF; 2795 *(fatp + 2) = 0xFF; 2796 2797 if (Fatentsize == 16) { 2798 *(fatp + 3) = 0xFF; 2799 } else if (Fatentsize == 32) { 2800 *(fatp + 3) = 0x0F; 2801 *(fatp + 4) = 0xFF; 2802 *(fatp + 5) = 0xFF; 2803 *(fatp + 6) = 0xFF; 2804 *(fatp + 7) = 0x0F; 2805 } 2806 2807 /* 2808 * Keep track of clusters used. 2809 */ 2810 remclust = TotalClusters; 2811 nextfree = 2; 2812 2813 /* 2814 * Get info on first file to install, if any. 2815 */ 2816 if (ffn) 2817 *fffd = verify_firstfile(ffn, ffsize); 2818 2819 /* 2820 * Compute number of clusters to preserve for bootblk overage. 2821 * Remember that we already wrote the first sector of the boot block. 2822 * These clusters are marked BAD to prevent them from being deleted 2823 * or used. The first available cluster is 2, so we always offset 2824 * the clusters. 2825 */ 2826 numsect = idivceil((bootblksize - BPSEC), BPSEC); 2827 numclust = idivceil(numsect, wbpb->bpb.sectors_per_cluster); 2828 2829 if (Verbose && numclust) 2830 (void) printf(gettext("Hiding %d excess bootblk cluster(s).\n"), 2831 numclust); 2832 for (ci = 0; ci < numclust; ci++) 2833 mark_cluster(fatp, nextfree++, 2834 MakeFAT32 ? PCF_BADCLUSTER32 : PCF_BADCLUSTER); 2835 remclust -= numclust; 2836 2837 /* 2838 * Reserve a cluster for the root directory on a FAT32. 2839 */ 2840 if (MakeFAT32) { 2841 mark_cluster(fatp, nextfree, PCF_LASTCLUSTER32); 2842 wbpb->bpb32.root_dir_clust = nextfree++; 2843 remclust--; 2844 } 2845 2846 /* 2847 * Compute and preserve number of clusters for first file. 2848 */ 2849 if (*fffd >= 0) { 2850 *ffstartclust = nextfree; 2851 numsect = idivceil(*ffsize, BPSEC); 2852 numclust = idivceil(numsect, wbpb->bpb.sectors_per_cluster); 2853 2854 if (numclust > remclust) { 2855 (void) fprintf(stderr, 2856 gettext("Requested first file too large to be\n" 2857 "installed in the new file system.\n")); 2858 (void) close(*fffd); 2859 *fffd = -1; 2860 goto finish; 2861 } 2862 2863 if (Verbose) 2864 (void) printf(gettext("Reserving %d first file " 2865 "cluster(s).\n"), numclust); 2866 for (ci = 0; (int)ci < (int)(numclust-1); ci++, nextfree++) 2867 mark_cluster(fatp, nextfree, nextfree + 1); 2868 mark_cluster(fatp, nextfree++, 2869 MakeFAT32 ? PCF_LASTCLUSTER32 : PCF_LASTCLUSTER); 2870 remclust -= numclust; 2871 } 2872 2873 finish: 2874 if (Verbose) { 2875 (void) printf(gettext("First sector of FAT")); 2876 header_for_dump(); 2877 dump_bytes(fatp, BPSEC); 2878 } 2879 2880 (void) memset(fsinfop, 0, sizeof (*fsinfop)); 2881 fsinfop->fsi_leadsig = LE_32(FSI_LEADSIG); 2882 fsinfop->fsi_strucsig = LE_32(FSI_STRUCSIG); 2883 fsinfop->fsi_trailsig = LE_32(FSI_TRAILSIG); 2884 fsinfop->fsi_incore.fs_free_clusters = LE_32(remclust); 2885 fsinfop->fsi_incore.fs_next_free = LE_32(nextfree); 2886 return (fatp); 2887 } 2888 2889 static 2890 void 2891 dirent_time_fill(struct pcdir *dep) 2892 { 2893 struct timeval tv; 2894 struct tm *tp; 2895 ushort_t dostime; 2896 ushort_t dosday; 2897 2898 (void) gettimeofday(&tv, (struct timezone *)0); 2899 tp = localtime(&tv.tv_sec); 2900 /* get the time & day into DOS format */ 2901 dostime = tp->tm_sec / 2; 2902 dostime |= tp->tm_min << 5; 2903 dostime |= tp->tm_hour << 11; 2904 dosday = tp->tm_mday; 2905 dosday |= (tp->tm_mon + 1) << 5; 2906 dosday |= (tp->tm_year - 80) << 9; 2907 dep->pcd_mtime.pct_time = htols(dostime); 2908 dep->pcd_mtime.pct_date = htols(dosday); 2909 } 2910 2911 static 2912 void 2913 dirent_label_fill(struct pcdir *dep, char *fn) 2914 { 2915 int nl, i; 2916 2917 /* 2918 * We spread the volume label across both the NAME and EXT fields 2919 */ 2920 nl = min(PCFNAMESIZE, strlen(fn)); 2921 for (i = 0; i < nl; i++) { 2922 dep->pcd_filename[i] = toupper(fn[i]); 2923 } 2924 if (i < PCFNAMESIZE) { 2925 for (; i < PCFNAMESIZE; i++) 2926 dep->pcd_filename[i] = ' '; 2927 for (i = 0; i < PCFEXTSIZE; i++) 2928 dep->pcd_ext[i] = ' '; 2929 return; 2930 } 2931 nl = min(PCFEXTSIZE, strlen(fn) - PCFNAMESIZE); 2932 for (i = 0; i < nl; i++) 2933 dep->pcd_ext[i] = toupper(fn[i + PCFNAMESIZE]); 2934 if (i < PCFEXTSIZE) { 2935 for (; i < PCFEXTSIZE; i++) 2936 dep->pcd_ext[i] = ' '; 2937 } 2938 } 2939 2940 static 2941 void 2942 dirent_fname_fill(struct pcdir *dep, char *fn) 2943 { 2944 char *fname, *fext; 2945 int nl, i; 2946 2947 if (fname = strrchr(fn, '/')) { 2948 fname++; 2949 } else { 2950 fname = fn; 2951 } 2952 2953 if (fext = strrchr(fname, '.')) { 2954 fext++; 2955 } else { 2956 fext = ""; 2957 } 2958 2959 fname = strtok(fname, "."); 2960 2961 nl = min(PCFNAMESIZE, (int)strlen(fname)); 2962 for (i = 0; i < nl; i++) { 2963 dep->pcd_filename[i] = toupper(fname[i]); 2964 } 2965 for (; i < PCFNAMESIZE; i++) { 2966 dep->pcd_filename[i] = ' '; 2967 } 2968 2969 nl = min(PCFEXTSIZE, (int)strlen(fext)); 2970 for (i = 0; i < nl; i++) { 2971 dep->pcd_ext[i] = toupper(fext[i]); 2972 } 2973 for (; i < PCFEXTSIZE; i++) { 2974 dep->pcd_ext[i] = ' '; 2975 } 2976 } 2977 2978 static 2979 uchar_t * 2980 build_rootdir(bpb_t *wbpb, char *ffn, int fffd, 2981 ulong_t ffsize, pc_cluster32_t ffstart, ulong_t *rdirsize) 2982 { 2983 struct pcdir *rootdirp; 2984 struct pcdir *entry; 2985 2986 /* 2987 * Build a root directory. It will have at least one entry, 2988 * the volume label and a second if the first file was defined. 2989 */ 2990 if (MakeFAT32) { 2991 /* 2992 * We devote an entire cluster to the root 2993 * directory on FAT32. 2994 */ 2995 *rdirsize = wbpb->bpb.sectors_per_cluster * BPSEC; 2996 } else { 2997 *rdirsize = wbpb->bpb.num_root_entries * sizeof (struct pcdir); 2998 } 2999 if ((rootdirp = (struct pcdir *)malloc(*rdirsize)) == NULL) { 3000 perror(gettext("Root directory allocation")); 3001 exit(4); 3002 } else { 3003 entry = rootdirp; 3004 (void) memset((char *)rootdirp, 0, *rdirsize); 3005 } 3006 3007 /* Create directory entry for first file, if there is one */ 3008 if (fffd >= 0) { 3009 dirent_fname_fill(entry, ffn); 3010 entry->pcd_attr = Firstfileattr; 3011 dirent_time_fill(entry); 3012 entry->pcd_scluster_lo = htols(ffstart); 3013 if (MakeFAT32) { 3014 ffstart = ffstart >> 16; 3015 entry->un.pcd_scluster_hi = htols(ffstart); 3016 } 3017 entry->pcd_size = htoli(ffsize); 3018 entry++; 3019 } 3020 3021 /* Create directory entry for volume label, if there is one */ 3022 if (Label != NULL) { 3023 dirent_label_fill(entry, Label); 3024 entry->pcd_attr = PCA_ARCH | PCA_LABEL; 3025 dirent_time_fill(entry); 3026 entry->pcd_scluster_lo = 0; 3027 if (MakeFAT32) { 3028 entry->un.pcd_scluster_hi = 0; 3029 } 3030 entry->pcd_size = 0; 3031 entry++; 3032 } 3033 3034 if (Verbose) { 3035 (void) printf(gettext("First two directory entries")); 3036 header_for_dump(); 3037 dump_bytes((uchar_t *)rootdirp, 2 * sizeof (struct pcdir)); 3038 } 3039 3040 return ((uchar_t *)rootdirp); 3041 } 3042 3043 /* 3044 * write_rest 3045 * 3046 * Write all the bytes from the current file pointer to end of file 3047 * in the source file out to the destination file. The writes should 3048 * be padded to whole clusters with 0's if necessary. 3049 */ 3050 static 3051 void 3052 write_rest(bpb_t *wbpb, char *efn, int dfd, int sfd, int remaining) 3053 { 3054 char buf[BPSEC]; 3055 ushort_t numsect, numclust; 3056 ushort_t wnumsect, s; 3057 int doneread = 0; 3058 int rstat; 3059 3060 /* 3061 * Compute number of clusters required to contain remaining bytes. 3062 */ 3063 numsect = idivceil(remaining, BPSEC); 3064 numclust = idivceil(numsect, wbpb->bpb.sectors_per_cluster); 3065 3066 wnumsect = numclust * wbpb->bpb.sectors_per_cluster; 3067 for (s = 0; s < wnumsect; s++) { 3068 if (!doneread) { 3069 if ((rstat = read(sfd, buf, BPSEC)) < 0) { 3070 perror(efn); 3071 doneread = 1; 3072 rstat = 0; 3073 } else if (rstat == 0) { 3074 doneread = 1; 3075 } 3076 (void) memset(&(buf[rstat]), 0, BPSEC - rstat); 3077 } 3078 if (write(dfd, buf, BPSEC) != BPSEC) { 3079 (void) fprintf(stderr, gettext("Copying ")); 3080 perror(efn); 3081 } 3082 } 3083 } 3084 3085 static 3086 void 3087 write_fat32_bootstuff(int fd, boot_sector_t *bsp, 3088 struct fat_od_fsi *fsinfop, off64_t seekto) 3089 { 3090 if (Verbose) { 3091 (void) printf(gettext("Dump of the fs info sector")); 3092 header_for_dump(); 3093 dump_bytes((uchar_t *)fsinfop, sizeof (*fsinfop)); 3094 } 3095 3096 if (!Notreally) { 3097 /* 3098 * FAT32's have an FS info sector, then a backup of the boot 3099 * sector, and a modified backup of the FS Info sector. 3100 */ 3101 if (write(fd, fsinfop, sizeof (*fsinfop)) != BPSEC) { 3102 perror(gettext("FS info sector write")); 3103 exit(4); 3104 } 3105 if (lseek64(fd, seekto + BKUP_BOOTSECT_OFFSET, SEEK_SET) < 0) { 3106 (void) close(fd); 3107 perror(gettext("Boot sector backup seek")); 3108 exit(4); 3109 } 3110 if (write(fd, bsp->buf, sizeof (bsp->buf)) != BPSEC) { 3111 perror(gettext("Boot sector backup write")); 3112 exit(4); 3113 } 3114 } 3115 3116 /* 3117 * Second copy of fs info sector is modified to have "don't know" 3118 * as the number of free clusters 3119 */ 3120 fsinfop->fsi_incore.fs_next_free = LE_32(FSINFO_UNKNOWN); 3121 3122 if (Verbose) { 3123 (void) printf(gettext("Dump of the backup fs info sector")); 3124 header_for_dump(); 3125 dump_bytes((uchar_t *)fsinfop, sizeof (*fsinfop)); 3126 } 3127 3128 if (!Notreally) { 3129 if (write(fd, fsinfop, sizeof (*fsinfop)) != BPSEC) { 3130 perror(gettext("FS info sector backup write")); 3131 exit(4); 3132 } 3133 } 3134 } 3135 3136 static 3137 void 3138 write_bootsects(int fd, boot_sector_t *bsp, bpb_t *wbpb, 3139 struct fat_od_fsi *fsinfop, off64_t seekto) 3140 { 3141 if (MakeFAT32) { 3142 /* Copy our BPB into bootsec structure */ 3143 #ifdef i386 3144 (void) memcpy(&(bsp->bs32.bs_front.bs_bpb), &(wbpb->bpb), 3145 sizeof (wbpb->bpb)); 3146 (void) memcpy(&(bsp->bs32.bs_bpb32), &(wbpb->bpb32), 3147 sizeof (wbpb->bpb32)); 3148 (void) memcpy(&(bsp->bs32.bs_ebpb), &(wbpb->ebpb), 3149 sizeof (wbpb->ebpb)); 3150 #else 3151 swap_pack_bpb32cpy(&(bsp->bs32), wbpb); 3152 #endif 3153 } else { 3154 /* Copy our BPB into bootsec structure */ 3155 #ifdef i386 3156 (void) memcpy(&(bsp->bs.bs_front.bs_bpb), &(wbpb->bpb), 3157 sizeof (wbpb->bpb)); 3158 (void) memcpy(&(bsp->bs.bs_ebpb), &(wbpb->ebpb), 3159 sizeof (wbpb->ebpb)); 3160 #else 3161 swap_pack_bpbcpy(&(bsp->bs), wbpb); 3162 #endif 3163 3164 /* Copy SUN BPB extensions into bootsec structure */ 3165 if (SunBPBfields) { 3166 #ifdef i386 3167 (void) memcpy(&(bsp->bs.bs_sebpb), &(wbpb->sunbpb), 3168 sizeof (wbpb->sunbpb)); 3169 #else 3170 swap_pack_sebpbcpy(&(bsp->bs), wbpb); 3171 #endif 3172 } 3173 } 3174 3175 /* Write boot sector */ 3176 if (!Notreally && write(fd, bsp->buf, sizeof (bsp->buf)) != BPSEC) { 3177 perror(gettext("Boot sector write")); 3178 exit(4); 3179 } 3180 3181 if (Verbose) { 3182 (void) printf(gettext("Dump of the boot sector")); 3183 header_for_dump(); 3184 dump_bytes(bsp->buf, sizeof (bsp->buf)); 3185 } 3186 3187 if (MakeFAT32) 3188 write_fat32_bootstuff(fd, bsp, fsinfop, seekto); 3189 } 3190 3191 static 3192 void 3193 write_fat(int fd, off64_t seekto, char *fn, char *lbl, char *ffn, bpb_t *wbpb) 3194 { 3195 struct fat_od_fsi fsinfo; 3196 pc_cluster32_t ffsc; 3197 boot_sector_t bootsect; 3198 uchar_t *fatp, *rdirp; 3199 ulong_t bootblksize, fatsize, rdirsize, ffsize; 3200 int bsfd = -1; 3201 int fffd = -1; 3202 3203 compute_file_area_size(wbpb); 3204 3205 bsfd = copy_bootblk(fn, &bootsect, &bootblksize); 3206 label_volume(lbl, wbpb); 3207 3208 if (Verbose) 3209 (void) printf(gettext("Building FAT.\n")); 3210 fatp = build_fat(wbpb, &fsinfo, bootblksize, &fatsize, 3211 ffn, &fffd, &ffsize, &ffsc); 3212 3213 write_bootsects(fd, &bootsect, wbpb, &fsinfo, seekto); 3214 3215 if (lseek64(fd, 3216 seekto + (BPSEC * wbpb->bpb.resv_sectors), SEEK_SET) < 0) { 3217 (void) close(fd); 3218 perror(gettext("Seek to end of reserved sectors")); 3219 exit(4); 3220 } 3221 3222 /* Write FAT */ 3223 if (Verbose) 3224 (void) printf(gettext("Writing FAT(s). %d bytes times %d.\n"), 3225 fatsize, wbpb->bpb.num_fats); 3226 if (!Notreally) { 3227 int nf, wb; 3228 for (nf = 0; nf < (int)wbpb->bpb.num_fats; nf++) 3229 if ((wb = write(fd, fatp, fatsize)) != fatsize) { 3230 perror(gettext("FAT write")); 3231 exit(4); 3232 } else { 3233 if (Verbose) 3234 (void) printf( 3235 gettext("Wrote %d bytes\n"), wb); 3236 } 3237 } 3238 free(fatp); 3239 3240 if (Verbose) 3241 (void) printf(gettext("Building root directory.\n")); 3242 rdirp = build_rootdir(wbpb, ffn, fffd, ffsize, ffsc, &rdirsize); 3243 3244 /* 3245 * In non FAT32, root directory exists outside of the file area 3246 */ 3247 if (!MakeFAT32) { 3248 if (Verbose) 3249 (void) printf(gettext("Writing root directory. " 3250 "%d bytes.\n"), rdirsize); 3251 if (!Notreally) { 3252 if (write(fd, rdirp, rdirsize) != rdirsize) { 3253 perror(gettext("Root directory write")); 3254 exit(4); 3255 } 3256 } 3257 free(rdirp); 3258 } 3259 3260 /* 3261 * Now write anything that needs to be in the file space. 3262 */ 3263 if (bootblksize > BPSEC) { 3264 if (Verbose) 3265 (void) printf(gettext("Writing remainder of " 3266 "boot block.\n")); 3267 if (!Notreally) 3268 write_rest(wbpb, fn, fd, bsfd, bootblksize - BPSEC); 3269 } 3270 3271 if (MakeFAT32) { 3272 if (Verbose) 3273 (void) printf(gettext("Writing root directory. " 3274 "%d bytes.\n"), rdirsize); 3275 if (!Notreally) { 3276 if (write(fd, rdirp, rdirsize) != rdirsize) { 3277 perror(gettext("Root directory write")); 3278 exit(4); 3279 } 3280 } 3281 free(rdirp); 3282 } 3283 3284 if (fffd >= 0) { 3285 if (Verbose) 3286 (void) printf(gettext("Writing first file.\n")); 3287 if (!Notreally) 3288 write_rest(wbpb, ffn, fd, fffd, ffsize); 3289 } 3290 } 3291 3292 static 3293 char *LegalOpts[] = { 3294 #define NFLAG 0 3295 "N", 3296 #define VFLAG 1 3297 "v", 3298 #define RFLAG 2 3299 "r", 3300 #define HFLAG 3 3301 "h", 3302 #define SFLAG 4 3303 "s", 3304 #define SUNFLAG 5 3305 "S", 3306 #define LABFLAG 6 3307 "b", 3308 #define BTRFLAG 7 3309 "B", 3310 #define INITFLAG 8 3311 "i", 3312 #define SZFLAG 9 3313 "size", 3314 #define SECTFLAG 10 3315 "nsect", 3316 #define TRKFLAG 11 3317 "ntrack", 3318 #define SPCFLAG 12 3319 "spc", 3320 #define BPFFLAG 13 3321 "fat", 3322 #define FFLAG 14 3323 "f", 3324 #define DFLAG 15 3325 "d", 3326 #define NOFDISKFLAG 16 3327 "nofdisk", 3328 #define RESRVFLAG 17 3329 "reserve", 3330 #define HIDDENFLAG 18 3331 "hidden", 3332 NULL 3333 }; 3334 3335 static 3336 void 3337 bad_arg(char *option) 3338 { 3339 (void) fprintf(stderr, 3340 gettext("Unrecognized option %s.\n"), option); 3341 usage(); 3342 exit(2); 3343 } 3344 3345 static 3346 void 3347 missing_arg(char *option) 3348 { 3349 (void) fprintf(stderr, 3350 gettext("Option %s requires a value.\n"), option); 3351 usage(); 3352 exit(3); 3353 } 3354 3355 static 3356 void 3357 parse_suboptions(char *optsstr) 3358 { 3359 char *value; 3360 int c; 3361 3362 while (*optsstr != '\0') { 3363 switch (c = getsubopt(&optsstr, LegalOpts, &value)) { 3364 case NFLAG: 3365 Notreally++; 3366 break; 3367 case VFLAG: 3368 Verbose++; 3369 break; 3370 case RFLAG: 3371 Firstfileattr |= 0x01; 3372 break; 3373 case HFLAG: 3374 Firstfileattr |= 0x02; 3375 break; 3376 case SFLAG: 3377 Firstfileattr |= 0x04; 3378 break; 3379 case SUNFLAG: 3380 SunBPBfields = 1; 3381 break; 3382 case LABFLAG: 3383 if (value == NULL) { 3384 missing_arg(LegalOpts[c]); 3385 } else { 3386 Label = value; 3387 } 3388 break; 3389 case BTRFLAG: 3390 if (value == NULL) { 3391 missing_arg(LegalOpts[c]); 3392 } else { 3393 BootBlkFn = value; 3394 } 3395 break; 3396 case INITFLAG: 3397 if (value == NULL) { 3398 missing_arg(LegalOpts[c]); 3399 } else { 3400 FirstFn = value; 3401 } 3402 break; 3403 case SZFLAG: 3404 if (value == NULL) { 3405 missing_arg(LegalOpts[c]); 3406 } else { 3407 TotSize = atoi(value); 3408 GetSize = 0; 3409 } 3410 break; 3411 case SECTFLAG: 3412 if (value == NULL) { 3413 missing_arg(LegalOpts[c]); 3414 } else { 3415 SecPerTrk = atoi(value); 3416 GetSPT = 0; 3417 } 3418 break; 3419 case TRKFLAG: 3420 if (value == NULL) { 3421 missing_arg(LegalOpts[c]); 3422 } else { 3423 TrkPerCyl = atoi(value); 3424 GetTPC = 0; 3425 } 3426 break; 3427 case SPCFLAG: 3428 if (value == NULL) { 3429 missing_arg(LegalOpts[c]); 3430 } else { 3431 SecPerClust = atoi(value); 3432 GetSPC = 0; 3433 } 3434 break; 3435 case BPFFLAG: 3436 if (value == NULL) { 3437 missing_arg(LegalOpts[c]); 3438 } else { 3439 BitsPerFAT = atoi(value); 3440 GetBPF = 0; 3441 } 3442 break; 3443 case NOFDISKFLAG: 3444 DontUseFdisk = 1; 3445 break; 3446 case RESRVFLAG: 3447 if (value == NULL) { 3448 missing_arg(LegalOpts[c]); 3449 } else { 3450 Resrvd = atoi(value); 3451 GetResrvd = 0; 3452 } 3453 break; 3454 case HIDDENFLAG: 3455 if (value == NULL) { 3456 missing_arg(LegalOpts[c]); 3457 } else { 3458 RelOffset = atoi(value); 3459 GetOffset = 0; 3460 } 3461 break; 3462 case FFLAG: 3463 if (value == NULL) { 3464 missing_arg(LegalOpts[c]); 3465 } else { 3466 DiskName = value; 3467 Outputtofile = 1; 3468 } 3469 break; 3470 case DFLAG: 3471 if (value == NULL) { 3472 missing_arg(LegalOpts[c]); 3473 } else { 3474 Imagesize = atoi(value); 3475 } 3476 break; 3477 default: 3478 bad_arg(value); 3479 break; 3480 } 3481 } 3482 } 3483 3484 static 3485 void 3486 sanity_check_options(int argc, int optind) 3487 { 3488 if (GetFsParams) { 3489 if (argc - optind != 1) 3490 usage(); 3491 return; 3492 } 3493 3494 if (DontUseFdisk && GetOffset) { 3495 /* Set default relative offset of zero */ 3496 RelOffset = 0; 3497 } 3498 3499 if (BitsPerFAT == 32) 3500 MakeFAT32 = 1; 3501 3502 if (Outputtofile && (argc - optind)) { 3503 usage(); 3504 } else if (Outputtofile && !DiskName) { 3505 usage(); 3506 } else if (!Outputtofile && (argc - optind != 1)) { 3507 usage(); 3508 } else if (SunBPBfields && !BootBlkFn) { 3509 (void) fprintf(stderr, 3510 gettext("Use of the 'S' option requires that\n" 3511 "the 'B=' option also be used.\n\n")); 3512 usage(); 3513 } else if (Firstfileattr != 0x20 && !FirstFn) { 3514 (void) fprintf(stderr, 3515 gettext("Use of the 'r', 'h', or 's' options requires\n" 3516 "that the 'i=' option also be used.\n\n")); 3517 usage(); 3518 } else if (!GetOffset && !DontUseFdisk) { 3519 (void) fprintf(stderr, 3520 gettext("Use of the 'hidden' option requires that\n" 3521 "the 'nofdisk' option also be used.\n\n")); 3522 usage(); 3523 } else if (DontUseFdisk && GetSize) { 3524 (void) fprintf(stderr, 3525 gettext("Use of the 'nofdisk' option requires that\n" 3526 "the 'size=' option also be used.\n\n")); 3527 usage(); 3528 } else if (!GetBPF && 3529 BitsPerFAT != 12 && BitsPerFAT != 16 && BitsPerFAT != 32) { 3530 (void) fprintf(stderr, gettext("Invalid Bits/Fat value." 3531 " Must be 12, 16 or 32.\n")); 3532 exit(2); 3533 } else if (!GetSPC && !(ISP2(SecPerClust) && 3534 IN_RANGE(SecPerClust, 1, 128))) { 3535 (void) fprintf(stderr, 3536 gettext("Invalid Sectors/Cluster value. Must be a " 3537 "power of 2 between 1 and 128.\n")); 3538 exit(2); 3539 } else if (!GetResrvd && (Resrvd < 1 || Resrvd > 0xffff)) { 3540 (void) fprintf(stderr, 3541 gettext("Invalid number of reserved sectors. " 3542 "Must be at least 1 but\nno larger than 65535.")); 3543 exit(2); 3544 } else if (!GetResrvd && MakeFAT32 && 3545 (Resrvd < 32 || Resrvd > 0xffff)) { 3546 (void) fprintf(stderr, 3547 gettext("Invalid number of reserved sectors. " 3548 "Must be at least 32 but\nno larger than 65535.")); 3549 exit(2); 3550 } else if (Imagesize != 3 && Imagesize != 5) { 3551 usage(); 3552 } 3553 } 3554 3555 int 3556 main(int argc, char **argv) 3557 { 3558 off64_t AbsBootSect = 0; 3559 bpb_t dskparamblk; 3560 char *string; 3561 int fd; 3562 int c; 3563 3564 (void) setlocale(LC_ALL, ""); 3565 3566 #if !defined(TEXT_DOMAIN) 3567 #define TEXT_DOMAIN "SYS_TEST" 3568 #endif 3569 (void) textdomain(TEXT_DOMAIN); 3570 3571 while ((c = getopt(argc, argv, "F:Vmo:")) != EOF) { 3572 switch (c) { 3573 case 'F': 3574 string = optarg; 3575 if (strcmp(string, "pcfs") != 0) 3576 usage(); 3577 break; 3578 case 'V': 3579 { 3580 char *opt_text; 3581 int opt_count; 3582 3583 (void) fprintf(stdout, 3584 gettext("mkfs -F pcfs ")); 3585 for (opt_count = 1; opt_count < argc; 3586 opt_count++) { 3587 opt_text = argv[opt_count]; 3588 if (opt_text) 3589 (void) fprintf(stdout, 3590 " %s ", opt_text); 3591 } 3592 (void) fprintf(stdout, "\n"); 3593 } 3594 break; 3595 case 'm': 3596 GetFsParams++; 3597 break; 3598 case 'o': 3599 string = optarg; 3600 parse_suboptions(string); 3601 break; 3602 } 3603 } 3604 3605 sanity_check_options(argc, optind); 3606 3607 if (!Outputtofile) 3608 DiskName = argv[optind]; 3609 3610 (void) memset(&dskparamblk, 0, sizeof (dskparamblk)); 3611 3612 if (GetFsParams) { 3613 fd = open_and_examine(DiskName, &dskparamblk); 3614 } else { 3615 fd = open_and_seek(DiskName, &dskparamblk, &AbsBootSect); 3616 if (ask_nicely(DiskName)) 3617 write_fat(fd, AbsBootSect, BootBlkFn, Label, 3618 FirstFn, &dskparamblk); 3619 } 3620 (void) close(fd); 3621 return (0); 3622 } 3623