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