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