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