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 2008 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 2194 if (Verbose) 2195 (void) printf(gettext("Opening destination device/file.\n")); 2196 2197 actualdisk = stat_actual_disk(dn, &di, &suffix); 2198 2199 /* 2200 * Destination exists, now find more about it. 2201 */ 2202 if (!(S_ISCHR(di.st_mode))) { 2203 (void) fprintf(stderr, 2204 gettext("\n%s: device name must be a " 2205 "character special device.\n"), actualdisk); 2206 exit(2); 2207 } else if ((fd = open(actualdisk, O_RDWR)) < 0) { 2208 perror(actualdisk); 2209 exit(2); 2210 } 2211 2212 /* 2213 * Find appropriate partition if we were requested to do so. 2214 */ 2215 if (suffix && !(seek_partn(fd, suffix, wbpb, &ignored))) { 2216 (void) close(fd); 2217 exit(2); 2218 } 2219 2220 read_existing_bpb(fd, wbpb); 2221 print_reproducing_command(fd, actualdisk, suffix, wbpb); 2222 2223 return (fd); 2224 } 2225 2226 /* 2227 * open_and_seek 2228 * 2229 * Open the requested 'dev_name'. Seek to point where 2230 * we'll write boot sectors, etc., based on any ':partition' 2231 * attachments to the dev_name. 2232 * 2233 * By the time we are finished here, the entire BPB will be 2234 * filled in, excepting the volume label. 2235 */ 2236 static 2237 int 2238 open_and_seek(char *dn, bpb_t *wbpb, off64_t *seekto) 2239 { 2240 struct fd_char fdchar; 2241 struct dk_geom dg; 2242 struct stat di; 2243 char *actualdisk = NULL; 2244 char *suffix = NULL; 2245 int fd; 2246 2247 if (Verbose) 2248 (void) printf(gettext("Opening destination device/file.\n")); 2249 2250 /* 2251 * We hold these truths to be self evident, all BPBs we create 2252 * will have these values in these fields. 2253 */ 2254 wbpb->bpb.num_fats = 2; 2255 wbpb->bpb.bytes_sector = BPSEC; 2256 2257 /* 2258 * Assign or use supplied numbers for hidden and 2259 * reserved sectors in the file system. 2260 */ 2261 if (GetResrvd) 2262 if (MakeFAT32) 2263 wbpb->bpb.resv_sectors = 32; 2264 else 2265 wbpb->bpb.resv_sectors = 1; 2266 else 2267 wbpb->bpb.resv_sectors = Resrvd; 2268 2269 wbpb->ebpb.ext_signature = 0x29; /* Magic number for modern format */ 2270 wbpb->ebpb.volume_id = 0; 2271 2272 if (MakeFAT32) 2273 fill_fat32_bpb(wbpb); 2274 2275 /* 2276 * If all output goes to a simple file, call a routine to setup 2277 * that scenario. Otherwise, try to find the device. 2278 */ 2279 if (Outputtofile) 2280 return (fd = prepare_image_file(dn, wbpb)); 2281 2282 actualdisk = stat_actual_disk(dn, &di, &suffix); 2283 2284 /* 2285 * Sanity check. If we've been provided a partition-specifying 2286 * suffix, we shouldn't also have been told to ignore the 2287 * fdisk table. 2288 */ 2289 if (DontUseFdisk && suffix) { 2290 (void) fprintf(stderr, 2291 gettext("Using 'nofdisk' option precludes " 2292 "appending logical drive\nspecifier " 2293 "to the device name.\n")); 2294 exit(2); 2295 } 2296 2297 /* 2298 * Destination exists, now find more about it. 2299 */ 2300 if (!(S_ISCHR(di.st_mode))) { 2301 (void) fprintf(stderr, 2302 gettext("\n%s: device name must indicate a " 2303 "character special device.\n"), actualdisk); 2304 exit(2); 2305 } else if ((fd = open(actualdisk, O_RDWR)) < 0) { 2306 perror(actualdisk); 2307 exit(2); 2308 } 2309 2310 /* 2311 * Find appropriate partition if we were requested to do so. 2312 */ 2313 if (suffix && !(seek_partn(fd, suffix, wbpb, seekto))) { 2314 (void) close(fd); 2315 exit(2); 2316 } 2317 2318 if (!suffix) { 2319 /* 2320 * We have one of two possibilities. Chances are we have 2321 * a floppy drive. But the user may be trying to format 2322 * some weird drive that we don't know about and is supplying 2323 * all the important values. In that case, they should have set 2324 * the 'nofdisk' flag. 2325 * 2326 * If 'nofdisk' isn't set, do a floppy-specific ioctl to 2327 * get the remainder of our info. If the ioctl fails, we have 2328 * a good idea that they aren't really on a floppy. In that 2329 * case, they should have given us a partition specifier. 2330 */ 2331 if (DontUseFdisk) { 2332 if (!(seek_nofdisk(fd, wbpb, seekto))) { 2333 (void) close(fd); 2334 exit(2); 2335 } 2336 find_fixed_details(fd, wbpb); 2337 } else if (ioctl(fd, FDIOGCHAR, &fdchar) == -1) { 2338 /* 2339 * It is possible that we are trying to use floppy 2340 * specific FDIOGCHAR ioctl on USB floppy. Since sd 2341 * driver, by which USB floppy is handled, doesn't 2342 * support it, we can try to use disk DKIOCGGEOM ioctl 2343 * to retrieve data we need. sd driver itself 2344 * determines floppy disk by number of blocks 2345 * (<=0x1000), then it sets geometry to 80 cylinders, 2346 * 2 heads. 2347 * 2348 * Note that DKIOCGGEOM cannot supply us with type 2349 * of media (e.g. 3.5" or 5.25"). We will set it to 2350 * 3 (3.5") which is most probable value. 2351 */ 2352 if (errno == ENOTTY) { 2353 if (ioctl(fd, DKIOCGGEOM, &dg) != -1 && 2354 dg.dkg_ncyl == 80 && dg.dkg_nhead == 2) { 2355 fdchar.fdc_ncyl = dg.dkg_ncyl; 2356 fdchar.fdc_medium = 3; 2357 fdchar.fdc_secptrack = dg.dkg_nsect; 2358 fdchar.fdc_nhead = dg.dkg_nhead; 2359 lookup_floppy(&fdchar, wbpb); 2360 } else { 2361 partn_lecture(actualdisk); 2362 (void) close(fd); 2363 exit(2); 2364 } 2365 } 2366 } else { 2367 #ifdef sparc 2368 fdchar.fdc_medium = 3; 2369 #endif 2370 lookup_floppy(&fdchar, wbpb); 2371 } 2372 } else { 2373 find_fixed_details(fd, wbpb); 2374 } 2375 2376 return (fd); 2377 } 2378 2379 /* 2380 * The following is a copy of MS-DOS 4.0 boot block. 2381 * It consists of the BIOS parameter block, and a disk 2382 * bootstrap program. 2383 * 2384 * The BIOS parameter block contains the right values 2385 * for the 3.5" high-density 1.44MB floppy format. 2386 * 2387 * This will be our default boot sector, if the user 2388 * didn't point us at a different one. 2389 * 2390 */ 2391 static 2392 uchar_t DefBootSec[512] = { 2393 0xeb, 0x3c, 0x90, /* 8086 short jump + displacement + NOP */ 2394 'M', 'S', 'D', 'O', 'S', '4', '.', '0', /* OEM name & version */ 2395 0x00, 0x02, 0x01, 0x01, 0x00, 2396 0x02, 0xe0, 0x00, 0x40, 0x0b, 2397 0xf0, 0x09, 0x00, 0x12, 0x00, 2398 0x02, 0x00, 2399 0x00, 0x00, 0x00, 0x00, 2400 0x00, 0x00, 0x00, 0x00, 2401 0x00, 0x00, 2402 0x29, 0x00, 0x00, 0x00, 0x00, 2403 'N', 'O', 'N', 'A', 'M', 'E', ' ', ' ', ' ', ' ', ' ', 2404 'F', 'A', 'T', '1', '2', ' ', ' ', ' ', 2405 0xfa, 0x33, 2406 0xc0, 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0x16, 0x07, 2407 0xbb, 0x78, 0x00, 0x36, 0xc5, 0x37, 0x1e, 0x56, 2408 0x16, 0x53, 0xbf, 0x3e, 0x7c, 0xb9, 0x0b, 0x00, 2409 0xfc, 0xf3, 0xa4, 0x06, 0x1f, 0xc6, 0x45, 0xfe, 2410 0x0f, 0x8b, 0x0e, 0x18, 0x7c, 0x88, 0x4d, 0xf9, 2411 0x89, 0x47, 0x02, 0xc7, 0x07, 0x3e, 0x7c, 0xfb, 2412 0xcd, 0x13, 0x72, 0x7c, 0x33, 0xc0, 0x39, 0x06, 2413 0x13, 0x7c, 0x74, 0x08, 0x8b, 0x0e, 0x13, 0x7c, 2414 0x89, 0x0e, 0x20, 0x7c, 0xa0, 0x10, 0x7c, 0xf7, 2415 0x26, 0x16, 0x7c, 0x03, 0x06, 0x1c, 0x7c, 0x13, 2416 0x16, 0x1e, 0x7c, 0x03, 0x06, 0x0e, 0x7c, 0x83, 2417 0xd2, 0x00, 0xa3, 0x50, 0x7c, 0x89, 0x16, 0x52, 2418 0x7c, 0xa3, 0x49, 0x7c, 0x89, 0x16, 0x4b, 0x7c, 2419 0xb8, 0x20, 0x00, 0xf7, 0x26, 0x11, 0x7c, 0x8b, 2420 0x1e, 0x0b, 0x7c, 0x03, 0xc3, 0x48, 0xf7, 0xf3, 2421 0x01, 0x06, 0x49, 0x7c, 0x83, 0x16, 0x4b, 0x7c, 2422 0x00, 0xbb, 0x00, 0x05, 0x8b, 0x16, 0x52, 0x7c, 2423 0xa1, 0x50, 0x7c, 0xe8, 0x87, 0x00, 0x72, 0x20, 2424 0xb0, 0x01, 0xe8, 0xa1, 0x00, 0x72, 0x19, 0x8b, 2425 0xfb, 0xb9, 0x0b, 0x00, 0xbe, 0xdb, 0x7d, 0xf3, 2426 0xa6, 0x75, 0x0d, 0x8d, 0x7f, 0x20, 0xbe, 0xe6, 2427 0x7d, 0xb9, 0x0b, 0x00, 0xf3, 0xa6, 0x74, 0x18, 2428 0xbe, 0x93, 0x7d, 0xe8, 0x51, 0x00, 0x32, 0xe4, 2429 0xcd, 0x16, 0x5e, 0x1f, 0x8f, 0x04, 0x8f, 0x44, 2430 0x02, 0xcd, 0x19, 0x58, 0x58, 0x58, 0xeb, 0xe8, 2431 0xbb, 0x00, 0x07, 0xb9, 0x03, 0x00, 0xa1, 0x49, 2432 0x7c, 0x8b, 0x16, 0x4b, 0x7c, 0x50, 0x52, 0x51, 2433 0xe8, 0x3a, 0x00, 0x72, 0xe6, 0xb0, 0x01, 0xe8, 2434 0x54, 0x00, 0x59, 0x5a, 0x58, 0x72, 0xc9, 0x05, 2435 0x01, 0x00, 0x83, 0xd2, 0x00, 0x03, 0x1e, 0x0b, 2436 0x7c, 0xe2, 0xe2, 0x8a, 0x2e, 0x15, 0x7c, 0x8a, 2437 0x16, 0x24, 0x7c, 0x8b, 0x1e, 0x49, 0x7c, 0xa1, 2438 0x4b, 0x7c, 0xea, 0x00, 0x00, 0x70, 0x00, 0xac, 2439 0x0a, 0xc0, 0x74, 0x29, 0xb4, 0x0e, 0xbb, 0x07, 2440 0x00, 0xcd, 0x10, 0xeb, 0xf2, 0x3b, 0x16, 0x18, 2441 0x7c, 0x73, 0x19, 0xf7, 0x36, 0x18, 0x7c, 0xfe, 2442 0xc2, 0x88, 0x16, 0x4f, 0x7c, 0x33, 0xd2, 0xf7, 2443 0x36, 0x1a, 0x7c, 0x88, 0x16, 0x25, 0x7c, 0xa3, 2444 0x4d, 0x7c, 0xf8, 0xc3, 0xf9, 0xc3, 0xb4, 0x02, 2445 0x8b, 0x16, 0x4d, 0x7c, 0xb1, 0x06, 0xd2, 0xe6, 2446 0x0a, 0x36, 0x4f, 0x7c, 0x8b, 0xca, 0x86, 0xe9, 2447 0x8a, 0x16, 0x24, 0x7c, 0x8a, 0x36, 0x25, 0x7c, 2448 0xcd, 0x13, 0xc3, 0x0d, 0x0a, 0x4e, 0x6f, 0x6e, 2449 0x2d, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, 2450 0x64, 0x69, 0x73, 0x6b, 0x20, 0x6f, 0x72, 0x20, 2451 0x64, 0x69, 0x73, 0x6b, 0x20, 0x65, 0x72, 0x72, 2452 0x6f, 0x72, 0x0d, 0x0a, 0x52, 0x65, 0x70, 0x6c, 2453 0x61, 0x63, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 2454 0x70, 0x72, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6e, 2455 0x79, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x77, 0x68, 2456 0x65, 0x6e, 0x20, 0x72, 0x65, 0x61, 0x64, 0x79, 2457 0x0d, 0x0a, 0x00, 0x49, 0x4f, 0x20, 0x20, 0x20, 2458 0x20, 0x20, 0x20, 0x53, 0x59, 0x53, 0x4d, 0x53, 2459 0x44, 0x4f, 0x53, 0x20, 0x20, 0x20, 0x53, 0x59, 2460 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2461 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa 2462 }; 2463 2464 /* 2465 * verify_bootblkfile 2466 * 2467 * We were provided with the name of a file containing the bootblk 2468 * to install. Verify it has a valid boot sector as best we can. Any 2469 * errors and we return a bad file descriptor. Otherwise we fill up the 2470 * provided buffer with the boot sector, return the file 2471 * descriptor for later use and leave the file pointer just 2472 * past the boot sector part of the boot block file. 2473 */ 2474 static 2475 int 2476 verify_bootblkfile(char *fn, boot_sector_t *bs, ulong_t *blkfilesize) 2477 { 2478 struct stat fi; 2479 int bsfd = -1; 2480 2481 if (stat(fn, &fi)) { 2482 perror(fn); 2483 } else if (fi.st_size < BPSEC) { 2484 (void) fprintf(stderr, 2485 gettext("%s: Too short to be a boot sector.\n"), fn); 2486 } else if ((bsfd = open(fn, O_RDONLY)) < 0) { 2487 perror(fn); 2488 } else if (read(bsfd, bs->buf, BPSEC) < BPSEC) { 2489 (void) close(bsfd); 2490 bsfd = -1; 2491 perror(gettext("Boot block read")); 2492 } else { 2493 if ((bs->bs.bs_signature[0] != (BOOTSECSIG & 0xFF) && 2494 bs->bs.bs_signature[1] != ((BOOTSECSIG >> 8) & 0xFF)) || 2495 #ifdef i386 2496 (bs->bs.bs_front.bs_jump_code[0] != OPCODE1 && 2497 bs->bs.bs_front.bs_jump_code[0] != OPCODE2) 2498 #else 2499 (bs->bs.bs_jump_code[0] != OPCODE1 && 2500 bs->bs.bs_jump_code[0] != OPCODE2) 2501 #endif 2502 /* CSTYLED */ 2503 ) { 2504 (void) close(bsfd); 2505 bsfd = -1; 2506 (void) fprintf(stderr, 2507 gettext("Boot block (%s) bogus.\n"), fn); 2508 } 2509 *blkfilesize = fi.st_size; 2510 } 2511 return (bsfd); 2512 } 2513 2514 /* 2515 * verify_firstfile 2516 * 2517 * We were provided with the name of a file to be the first file 2518 * installed on the disk. We just need to verify it exists and 2519 * find out how big it is. If it doesn't exist, we print a warning 2520 * message about how the file wasn't found. We don't exit fatally, 2521 * though, rather we return a size of 0 and the FAT will be built 2522 * without installing any first file. They can then presumably 2523 * install the correct first file by hand. 2524 */ 2525 static 2526 int 2527 verify_firstfile(char *fn, ulong_t *filesize) 2528 { 2529 struct stat fi; 2530 int fd = -1; 2531 2532 *filesize = 0; 2533 if (stat(fn, &fi) || (fd = open(fn, O_RDONLY)) < 0) { 2534 perror(fn); 2535 (void) fprintf(stderr, 2536 gettext("Could not access requested file. It will not\n" 2537 "be installed in the new file system.\n")); 2538 } else { 2539 *filesize = fi.st_size; 2540 } 2541 2542 return (fd); 2543 } 2544 2545 /* 2546 * label_volume 2547 * 2548 * Fill in BPB with volume label. 2549 */ 2550 static 2551 void 2552 label_volume(char *lbl, bpb_t *wbpb) 2553 { 2554 int ll, i; 2555 2556 /* Put a volume label into our BPB. */ 2557 if (!lbl) 2558 lbl = DEFAULT_LABEL; 2559 2560 ll = min(11, (int)strlen(lbl)); 2561 for (i = 0; i < ll; i++) { 2562 wbpb->ebpb.volume_label[i] = toupper(lbl[i]); 2563 } 2564 for (; i < 11; i++) { 2565 wbpb->ebpb.volume_label[i] = ' '; 2566 } 2567 } 2568 2569 static 2570 int 2571 copy_bootblk(char *fn, boot_sector_t *bootsect, ulong_t *bootblksize) 2572 { 2573 int bsfd = -1; 2574 2575 if (Verbose && fn) 2576 (void) printf(gettext("Request to install boot " 2577 "block file %s.\n"), fn); 2578 else if (Verbose) 2579 (void) printf(gettext("Request to install DOS boot block.\n")); 2580 2581 /* 2582 * If they want to install their own boot block, sanity check 2583 * that block. 2584 */ 2585 if (fn) { 2586 bsfd = verify_bootblkfile(fn, bootsect, bootblksize); 2587 if (bsfd < 0) { 2588 exit(3); 2589 } 2590 *bootblksize = roundup(*bootblksize, BPSEC); 2591 } else { 2592 (void) memcpy(bootsect, DefBootSec, BPSEC); 2593 *bootblksize = BPSEC; 2594 } 2595 2596 return (bsfd); 2597 } 2598 2599 /* 2600 * mark_cluster 2601 * 2602 * This routine fills a FAT entry with the value supplied to it as an 2603 * argument. The fatp argument is assumed to be a pointer to the FAT's 2604 * 0th entry. The clustnum is the cluster entry that should be updated. 2605 * The value is the new value for the entry. 2606 */ 2607 static 2608 void 2609 mark_cluster(uchar_t *fatp, pc_cluster32_t clustnum, uint32_t value) 2610 { 2611 uchar_t *ep; 2612 ulong_t idx; 2613 2614 idx = (Fatentsize == 32) ? clustnum * 4 : 2615 (Fatentsize == 16) ? clustnum * 2 : clustnum + clustnum/2; 2616 ep = fatp + idx; 2617 2618 if (Fatentsize == 32) { 2619 store_32_bits(&ep, value); 2620 } else if (Fatentsize == 16) { 2621 store_16_bits(&ep, value); 2622 } else { 2623 if (clustnum & 1) { 2624 *ep = (*ep & 0x0f) | ((value << 4) & 0xf0); 2625 ep++; 2626 *ep = (value >> 4) & 0xff; 2627 } else { 2628 *ep++ = value & 0xff; 2629 *ep = (*ep & 0xf0) | ((value >> 8) & 0x0f); 2630 } 2631 } 2632 } 2633 2634 static 2635 uchar_t * 2636 build_fat(bpb_t *wbpb, struct fat_od_fsi *fsinfop, ulong_t bootblksize, 2637 ulong_t *fatsize, char *ffn, int *fffd, ulong_t *ffsize, 2638 pc_cluster32_t *ffstartclust) 2639 { 2640 pc_cluster32_t nextfree, ci; 2641 uchar_t *fatp; 2642 ushort_t numclust, numsect; 2643 int remclust; 2644 2645 /* Alloc space for a FAT and then null it out. */ 2646 if (Verbose) { 2647 (void) printf(gettext("BUILD FAT.\n%d sectors per fat.\n"), 2648 wbpb->bpb.sectors_per_fat ? wbpb->bpb.sectors_per_fat : 2649 wbpb->bpb32.big_sectors_per_fat); 2650 } 2651 2652 if (MakeFAT32) { 2653 *fatsize = BPSEC * wbpb->bpb32.big_sectors_per_fat; 2654 } else { 2655 *fatsize = BPSEC * wbpb->bpb.sectors_per_fat; 2656 } 2657 2658 if (!(fatp = (uchar_t *)malloc(*fatsize))) { 2659 perror(gettext("FAT table alloc")); 2660 exit(4); 2661 } else { 2662 (void) memset(fatp, 0, *fatsize); 2663 } 2664 2665 /* Build in-memory FAT */ 2666 *fatp = wbpb->bpb.media; 2667 *(fatp + 1) = 0xFF; 2668 *(fatp + 2) = 0xFF; 2669 2670 if (Fatentsize == 16) { 2671 *(fatp + 3) = 0xFF; 2672 } else if (Fatentsize == 32) { 2673 *(fatp + 3) = 0x0F; 2674 *(fatp + 4) = 0xFF; 2675 *(fatp + 5) = 0xFF; 2676 *(fatp + 6) = 0xFF; 2677 *(fatp + 7) = 0x0F; 2678 } 2679 2680 /* 2681 * Keep track of clusters used. 2682 */ 2683 remclust = TotalClusters; 2684 nextfree = 2; 2685 2686 /* 2687 * Get info on first file to install, if any. 2688 */ 2689 if (ffn) 2690 *fffd = verify_firstfile(ffn, ffsize); 2691 2692 /* 2693 * Compute number of clusters to preserve for bootblk overage. 2694 * Remember that we already wrote the first sector of the boot block. 2695 * These clusters are marked BAD to prevent them from being deleted 2696 * or used. The first available cluster is 2, so we always offset 2697 * the clusters. 2698 */ 2699 numsect = idivceil((bootblksize - BPSEC), BPSEC); 2700 numclust = idivceil(numsect, wbpb->bpb.sectors_per_cluster); 2701 2702 if (Verbose && numclust) 2703 (void) printf(gettext("Hiding %d excess bootblk cluster(s).\n"), 2704 numclust); 2705 for (ci = 0; ci < numclust; ci++) 2706 mark_cluster(fatp, nextfree++, 2707 MakeFAT32 ? PCF_BADCLUSTER32 : PCF_BADCLUSTER); 2708 remclust -= numclust; 2709 2710 /* 2711 * Reserve a cluster for the root directory on a FAT32. 2712 */ 2713 if (MakeFAT32) { 2714 mark_cluster(fatp, nextfree, PCF_LASTCLUSTER32); 2715 wbpb->bpb32.root_dir_clust = nextfree++; 2716 remclust--; 2717 } 2718 2719 /* 2720 * Compute and preserve number of clusters for first file. 2721 */ 2722 if (*fffd >= 0) { 2723 *ffstartclust = nextfree; 2724 numsect = idivceil(*ffsize, BPSEC); 2725 numclust = idivceil(numsect, wbpb->bpb.sectors_per_cluster); 2726 2727 if (numclust > remclust) { 2728 (void) fprintf(stderr, 2729 gettext("Requested first file too large to be\n" 2730 "installed in the new file system.\n")); 2731 (void) close(*fffd); 2732 *fffd = -1; 2733 goto finish; 2734 } 2735 2736 if (Verbose) 2737 (void) printf(gettext("Reserving %d first file " 2738 "cluster(s).\n"), numclust); 2739 for (ci = 0; (int)ci < (int)(numclust-1); ci++, nextfree++) 2740 mark_cluster(fatp, nextfree, nextfree + 1); 2741 mark_cluster(fatp, nextfree++, 2742 MakeFAT32 ? PCF_LASTCLUSTER32 : PCF_LASTCLUSTER); 2743 remclust -= numclust; 2744 } 2745 2746 finish: 2747 if (Verbose) { 2748 (void) printf(gettext("First sector of FAT")); 2749 header_for_dump(); 2750 dump_bytes(fatp, BPSEC); 2751 } 2752 2753 (void) memset(fsinfop, 0, sizeof (*fsinfop)); 2754 fsinfop->fsi_leadsig = LE_32(FSI_LEADSIG); 2755 fsinfop->fsi_strucsig = LE_32(FSI_STRUCSIG); 2756 fsinfop->fsi_trailsig = LE_32(FSI_TRAILSIG); 2757 fsinfop->fsi_incore.fs_free_clusters = LE_32(remclust); 2758 fsinfop->fsi_incore.fs_next_free = LE_32(nextfree); 2759 return (fatp); 2760 } 2761 2762 static 2763 void 2764 dirent_time_fill(struct pcdir *dep) 2765 { 2766 struct timeval tv; 2767 struct tm *tp; 2768 ushort_t dostime; 2769 ushort_t dosday; 2770 2771 (void) gettimeofday(&tv, (struct timezone *)0); 2772 tp = localtime(&tv.tv_sec); 2773 /* get the time & day into DOS format */ 2774 dostime = tp->tm_sec / 2; 2775 dostime |= tp->tm_min << 5; 2776 dostime |= tp->tm_hour << 11; 2777 dosday = tp->tm_mday; 2778 dosday |= (tp->tm_mon + 1) << 5; 2779 dosday |= (tp->tm_year - 80) << 9; 2780 dep->pcd_mtime.pct_time = htols(dostime); 2781 dep->pcd_mtime.pct_date = htols(dosday); 2782 } 2783 2784 static 2785 void 2786 dirent_label_fill(struct pcdir *dep, char *fn) 2787 { 2788 int nl, i; 2789 2790 /* 2791 * We spread the volume label across both the NAME and EXT fields 2792 */ 2793 nl = min(PCFNAMESIZE, strlen(fn)); 2794 for (i = 0; i < nl; i++) { 2795 dep->pcd_filename[i] = toupper(fn[i]); 2796 } 2797 if (i < PCFNAMESIZE) { 2798 for (; i < PCFNAMESIZE; i++) 2799 dep->pcd_filename[i] = ' '; 2800 for (i = 0; i < PCFEXTSIZE; i++) 2801 dep->pcd_ext[i] = ' '; 2802 return; 2803 } 2804 nl = min(PCFEXTSIZE, strlen(fn) - PCFNAMESIZE); 2805 for (i = 0; i < nl; i++) 2806 dep->pcd_ext[i] = toupper(fn[i + PCFNAMESIZE]); 2807 if (i < PCFEXTSIZE) { 2808 for (; i < PCFEXTSIZE; i++) 2809 dep->pcd_ext[i] = ' '; 2810 } 2811 } 2812 2813 static 2814 void 2815 dirent_fname_fill(struct pcdir *dep, char *fn) 2816 { 2817 char *fname, *fext; 2818 int nl, i; 2819 2820 if (fname = strrchr(fn, '/')) { 2821 fname++; 2822 } else { 2823 fname = fn; 2824 } 2825 2826 if (fext = strrchr(fname, '.')) { 2827 fext++; 2828 } else { 2829 fext = ""; 2830 } 2831 2832 fname = strtok(fname, "."); 2833 2834 nl = min(PCFNAMESIZE, (int)strlen(fname)); 2835 for (i = 0; i < nl; i++) { 2836 dep->pcd_filename[i] = toupper(fname[i]); 2837 } 2838 for (; i < PCFNAMESIZE; i++) { 2839 dep->pcd_filename[i] = ' '; 2840 } 2841 2842 nl = min(PCFEXTSIZE, (int)strlen(fext)); 2843 for (i = 0; i < nl; i++) { 2844 dep->pcd_ext[i] = toupper(fext[i]); 2845 } 2846 for (; i < PCFEXTSIZE; i++) { 2847 dep->pcd_ext[i] = ' '; 2848 } 2849 } 2850 2851 static 2852 uchar_t * 2853 build_rootdir(bpb_t *wbpb, char *ffn, int fffd, 2854 ulong_t ffsize, pc_cluster32_t ffstart, ulong_t *rdirsize) 2855 { 2856 struct pcdir *rootdirp; 2857 struct pcdir *entry; 2858 2859 /* 2860 * Build a root directory. It will have at least one entry, 2861 * the volume label and a second if the first file was defined. 2862 */ 2863 if (MakeFAT32) { 2864 /* 2865 * We devote an entire cluster to the root 2866 * directory on FAT32. 2867 */ 2868 *rdirsize = wbpb->bpb.sectors_per_cluster * BPSEC; 2869 } else { 2870 *rdirsize = wbpb->bpb.num_root_entries * sizeof (struct pcdir); 2871 } 2872 if ((rootdirp = (struct pcdir *)malloc(*rdirsize)) == NULL) { 2873 perror(gettext("Root directory allocation")); 2874 exit(4); 2875 } else { 2876 entry = rootdirp; 2877 (void) memset((char *)rootdirp, 0, *rdirsize); 2878 } 2879 2880 /* Create directory entry for first file, if there is one */ 2881 if (fffd >= 0) { 2882 dirent_fname_fill(entry, ffn); 2883 entry->pcd_attr = Firstfileattr; 2884 dirent_time_fill(entry); 2885 entry->pcd_scluster_lo = htols(ffstart); 2886 if (MakeFAT32) { 2887 ffstart = ffstart >> 16; 2888 entry->un.pcd_scluster_hi = htols(ffstart); 2889 } 2890 entry->pcd_size = htoli(ffsize); 2891 entry++; 2892 } 2893 2894 /* Create directory entry for volume label, if there is one */ 2895 if (Label != NULL) { 2896 dirent_label_fill(entry, Label); 2897 entry->pcd_attr = PCA_ARCH | PCA_LABEL; 2898 dirent_time_fill(entry); 2899 entry->pcd_scluster_lo = 0; 2900 if (MakeFAT32) { 2901 entry->un.pcd_scluster_hi = 0; 2902 } 2903 entry->pcd_size = 0; 2904 entry++; 2905 } 2906 2907 if (Verbose) { 2908 (void) printf(gettext("First two directory entries")); 2909 header_for_dump(); 2910 dump_bytes((uchar_t *)rootdirp, 2 * sizeof (struct pcdir)); 2911 } 2912 2913 return ((uchar_t *)rootdirp); 2914 } 2915 2916 /* 2917 * write_rest 2918 * 2919 * Write all the bytes from the current file pointer to end of file 2920 * in the source file out to the destination file. The writes should 2921 * be padded to whole clusters with 0's if necessary. 2922 */ 2923 static 2924 void 2925 write_rest(bpb_t *wbpb, char *efn, int dfd, int sfd, int remaining) 2926 { 2927 char buf[BPSEC]; 2928 ushort_t numsect, numclust; 2929 ushort_t wnumsect, s; 2930 int doneread = 0; 2931 int rstat; 2932 2933 /* 2934 * Compute number of clusters required to contain remaining bytes. 2935 */ 2936 numsect = idivceil(remaining, BPSEC); 2937 numclust = idivceil(numsect, wbpb->bpb.sectors_per_cluster); 2938 2939 wnumsect = numclust * wbpb->bpb.sectors_per_cluster; 2940 for (s = 0; s < wnumsect; s++) { 2941 if (!doneread) { 2942 if ((rstat = read(sfd, buf, BPSEC)) < 0) { 2943 perror(efn); 2944 doneread = 1; 2945 rstat = 0; 2946 } else if (rstat == 0) { 2947 doneread = 1; 2948 } 2949 (void) memset(&(buf[rstat]), 0, BPSEC - rstat); 2950 } 2951 if (write(dfd, buf, BPSEC) != BPSEC) { 2952 (void) fprintf(stderr, gettext("Copying ")); 2953 perror(efn); 2954 } 2955 } 2956 } 2957 2958 static 2959 void 2960 write_fat32_bootstuff(int fd, boot_sector_t *bsp, 2961 struct fat_od_fsi *fsinfop, off64_t seekto) 2962 { 2963 if (Verbose) { 2964 (void) printf(gettext("Dump of the fs info sector")); 2965 header_for_dump(); 2966 dump_bytes((uchar_t *)fsinfop, sizeof (*fsinfop)); 2967 } 2968 2969 if (!Notreally) { 2970 /* 2971 * FAT32's have an FS info sector, then a backup of the boot 2972 * sector, and a modified backup of the FS Info sector. 2973 */ 2974 if (write(fd, fsinfop, sizeof (*fsinfop)) != BPSEC) { 2975 perror(gettext("FS info sector write")); 2976 exit(4); 2977 } 2978 if (lseek64(fd, seekto + BKUP_BOOTSECT_OFFSET, SEEK_SET) < 0) { 2979 (void) close(fd); 2980 perror(gettext("Boot sector backup seek")); 2981 exit(4); 2982 } 2983 if (write(fd, bsp->buf, sizeof (bsp->buf)) != BPSEC) { 2984 perror(gettext("Boot sector backup write")); 2985 exit(4); 2986 } 2987 } 2988 2989 /* 2990 * Second copy of fs info sector is modified to have "don't know" 2991 * as the number of free clusters 2992 */ 2993 fsinfop->fsi_incore.fs_next_free = LE_32(FSINFO_UNKNOWN); 2994 2995 if (Verbose) { 2996 (void) printf(gettext("Dump of the backup fs info sector")); 2997 header_for_dump(); 2998 dump_bytes((uchar_t *)fsinfop, sizeof (*fsinfop)); 2999 } 3000 3001 if (!Notreally) { 3002 if (write(fd, fsinfop, sizeof (*fsinfop)) != BPSEC) { 3003 perror(gettext("FS info sector backup write")); 3004 exit(4); 3005 } 3006 } 3007 } 3008 3009 static 3010 void 3011 write_bootsects(int fd, boot_sector_t *bsp, bpb_t *wbpb, 3012 struct fat_od_fsi *fsinfop, off64_t seekto) 3013 { 3014 if (MakeFAT32) { 3015 /* Copy our BPB into bootsec structure */ 3016 #ifdef i386 3017 (void) memcpy(&(bsp->bs32.bs_front.bs_bpb), &(wbpb->bpb), 3018 sizeof (wbpb->bpb)); 3019 (void) memcpy(&(bsp->bs32.bs_bpb32), &(wbpb->bpb32), 3020 sizeof (wbpb->bpb32)); 3021 (void) memcpy(&(bsp->bs32.bs_ebpb), &(wbpb->ebpb), 3022 sizeof (wbpb->ebpb)); 3023 #else 3024 swap_pack_bpb32cpy(&(bsp->bs32), wbpb); 3025 #endif 3026 } else { 3027 /* Copy our BPB into bootsec structure */ 3028 #ifdef i386 3029 (void) memcpy(&(bsp->bs.bs_front.bs_bpb), &(wbpb->bpb), 3030 sizeof (wbpb->bpb)); 3031 (void) memcpy(&(bsp->bs.bs_ebpb), &(wbpb->ebpb), 3032 sizeof (wbpb->ebpb)); 3033 #else 3034 swap_pack_bpbcpy(&(bsp->bs), wbpb); 3035 #endif 3036 3037 /* Copy SUN BPB extensions into bootsec structure */ 3038 if (SunBPBfields) { 3039 #ifdef i386 3040 (void) memcpy(&(bsp->bs.bs_sebpb), &(wbpb->sunbpb), 3041 sizeof (wbpb->sunbpb)); 3042 #else 3043 swap_pack_sebpbcpy(&(bsp->bs), wbpb); 3044 #endif 3045 } 3046 } 3047 3048 /* Write boot sector */ 3049 if (!Notreally && write(fd, bsp->buf, sizeof (bsp->buf)) != BPSEC) { 3050 perror(gettext("Boot sector write")); 3051 exit(4); 3052 } 3053 3054 if (Verbose) { 3055 (void) printf(gettext("Dump of the boot sector")); 3056 header_for_dump(); 3057 dump_bytes(bsp->buf, sizeof (bsp->buf)); 3058 } 3059 3060 if (MakeFAT32) 3061 write_fat32_bootstuff(fd, bsp, fsinfop, seekto); 3062 } 3063 3064 static 3065 void 3066 write_fat(int fd, off64_t seekto, char *fn, char *lbl, char *ffn, bpb_t *wbpb) 3067 { 3068 struct fat_od_fsi fsinfo; 3069 pc_cluster32_t ffsc; 3070 boot_sector_t bootsect; 3071 uchar_t *fatp, *rdirp; 3072 ulong_t bootblksize, fatsize, rdirsize, ffsize; 3073 int bsfd = -1; 3074 int fffd = -1; 3075 3076 compute_file_area_size(wbpb); 3077 3078 bsfd = copy_bootblk(fn, &bootsect, &bootblksize); 3079 label_volume(lbl, wbpb); 3080 3081 if (Verbose) 3082 (void) printf(gettext("Building FAT.\n")); 3083 fatp = build_fat(wbpb, &fsinfo, bootblksize, &fatsize, 3084 ffn, &fffd, &ffsize, &ffsc); 3085 3086 write_bootsects(fd, &bootsect, wbpb, &fsinfo, seekto); 3087 3088 if (lseek64(fd, 3089 seekto + (BPSEC * wbpb->bpb.resv_sectors), SEEK_SET) < 0) { 3090 (void) close(fd); 3091 perror(gettext("Seek to end of reserved sectors")); 3092 exit(4); 3093 } 3094 3095 /* Write FAT */ 3096 if (Verbose) 3097 (void) printf(gettext("Writing FAT(s). %d bytes times %d.\n"), 3098 fatsize, wbpb->bpb.num_fats); 3099 if (!Notreally) { 3100 int nf, wb; 3101 for (nf = 0; nf < (int)wbpb->bpb.num_fats; nf++) 3102 if ((wb = write(fd, fatp, fatsize)) != fatsize) { 3103 perror(gettext("FAT write")); 3104 exit(4); 3105 } else { 3106 if (Verbose) 3107 (void) printf( 3108 gettext("Wrote %d bytes\n"), wb); 3109 } 3110 } 3111 free(fatp); 3112 3113 if (Verbose) 3114 (void) printf(gettext("Building root directory.\n")); 3115 rdirp = build_rootdir(wbpb, ffn, fffd, ffsize, ffsc, &rdirsize); 3116 3117 /* 3118 * In non FAT32, root directory exists outside of the file area 3119 */ 3120 if (!MakeFAT32) { 3121 if (Verbose) 3122 (void) printf(gettext("Writing root directory. " 3123 "%d bytes.\n"), rdirsize); 3124 if (!Notreally) { 3125 if (write(fd, rdirp, rdirsize) != rdirsize) { 3126 perror(gettext("Root directory write")); 3127 exit(4); 3128 } 3129 } 3130 free(rdirp); 3131 } 3132 3133 /* 3134 * Now write anything that needs to be in the file space. 3135 */ 3136 if (bootblksize > BPSEC) { 3137 if (Verbose) 3138 (void) printf(gettext("Writing remainder of " 3139 "boot block.\n")); 3140 if (!Notreally) 3141 write_rest(wbpb, fn, fd, bsfd, bootblksize - BPSEC); 3142 } 3143 3144 if (MakeFAT32) { 3145 if (Verbose) 3146 (void) printf(gettext("Writing root directory. " 3147 "%d bytes.\n"), rdirsize); 3148 if (!Notreally) { 3149 if (write(fd, rdirp, rdirsize) != rdirsize) { 3150 perror(gettext("Root directory write")); 3151 exit(4); 3152 } 3153 } 3154 free(rdirp); 3155 } 3156 3157 if (fffd >= 0) { 3158 if (Verbose) 3159 (void) printf(gettext("Writing first file.\n")); 3160 if (!Notreally) 3161 write_rest(wbpb, ffn, fd, fffd, ffsize); 3162 } 3163 } 3164 3165 static 3166 char *LegalOpts[] = { 3167 #define NFLAG 0 3168 "N", 3169 #define VFLAG 1 3170 "v", 3171 #define RFLAG 2 3172 "r", 3173 #define HFLAG 3 3174 "h", 3175 #define SFLAG 4 3176 "s", 3177 #define SUNFLAG 5 3178 "S", 3179 #define LABFLAG 6 3180 "b", 3181 #define BTRFLAG 7 3182 "B", 3183 #define INITFLAG 8 3184 "i", 3185 #define SZFLAG 9 3186 "size", 3187 #define SECTFLAG 10 3188 "nsect", 3189 #define TRKFLAG 11 3190 "ntrack", 3191 #define SPCFLAG 12 3192 "spc", 3193 #define BPFFLAG 13 3194 "fat", 3195 #define FFLAG 14 3196 "f", 3197 #define DFLAG 15 3198 "d", 3199 #define NOFDISKFLAG 16 3200 "nofdisk", 3201 #define RESRVFLAG 17 3202 "reserve", 3203 #define HIDDENFLAG 18 3204 "hidden", 3205 NULL 3206 }; 3207 3208 static 3209 void 3210 bad_arg(char *option) 3211 { 3212 (void) fprintf(stderr, 3213 gettext("Unrecognized option %s.\n"), option); 3214 usage(); 3215 exit(2); 3216 } 3217 3218 static 3219 void 3220 missing_arg(char *option) 3221 { 3222 (void) fprintf(stderr, 3223 gettext("Option %s requires a value.\n"), option); 3224 usage(); 3225 exit(3); 3226 } 3227 3228 static 3229 void 3230 parse_suboptions(char *optsstr) 3231 { 3232 char *value; 3233 int c; 3234 3235 while (*optsstr != '\0') { 3236 switch (c = getsubopt(&optsstr, LegalOpts, &value)) { 3237 case NFLAG: 3238 Notreally++; 3239 break; 3240 case VFLAG: 3241 Verbose++; 3242 break; 3243 case RFLAG: 3244 Firstfileattr |= 0x01; 3245 break; 3246 case HFLAG: 3247 Firstfileattr |= 0x02; 3248 break; 3249 case SFLAG: 3250 Firstfileattr |= 0x04; 3251 break; 3252 case SUNFLAG: 3253 SunBPBfields = 1; 3254 break; 3255 case LABFLAG: 3256 if (value == NULL) { 3257 missing_arg(LegalOpts[c]); 3258 } else { 3259 Label = value; 3260 } 3261 break; 3262 case BTRFLAG: 3263 if (value == NULL) { 3264 missing_arg(LegalOpts[c]); 3265 } else { 3266 BootBlkFn = value; 3267 } 3268 break; 3269 case INITFLAG: 3270 if (value == NULL) { 3271 missing_arg(LegalOpts[c]); 3272 } else { 3273 FirstFn = value; 3274 } 3275 break; 3276 case SZFLAG: 3277 if (value == NULL) { 3278 missing_arg(LegalOpts[c]); 3279 } else { 3280 TotSize = atoi(value); 3281 GetSize = 0; 3282 } 3283 break; 3284 case SECTFLAG: 3285 if (value == NULL) { 3286 missing_arg(LegalOpts[c]); 3287 } else { 3288 SecPerTrk = atoi(value); 3289 GetSPT = 0; 3290 } 3291 break; 3292 case TRKFLAG: 3293 if (value == NULL) { 3294 missing_arg(LegalOpts[c]); 3295 } else { 3296 TrkPerCyl = atoi(value); 3297 GetTPC = 0; 3298 } 3299 break; 3300 case SPCFLAG: 3301 if (value == NULL) { 3302 missing_arg(LegalOpts[c]); 3303 } else { 3304 SecPerClust = atoi(value); 3305 GetSPC = 0; 3306 } 3307 break; 3308 case BPFFLAG: 3309 if (value == NULL) { 3310 missing_arg(LegalOpts[c]); 3311 } else { 3312 BitsPerFAT = atoi(value); 3313 GetBPF = 0; 3314 } 3315 break; 3316 case NOFDISKFLAG: 3317 DontUseFdisk = 1; 3318 break; 3319 case RESRVFLAG: 3320 if (value == NULL) { 3321 missing_arg(LegalOpts[c]); 3322 } else { 3323 Resrvd = atoi(value); 3324 GetResrvd = 0; 3325 } 3326 break; 3327 case HIDDENFLAG: 3328 if (value == NULL) { 3329 missing_arg(LegalOpts[c]); 3330 } else { 3331 RelOffset = atoi(value); 3332 GetOffset = 0; 3333 } 3334 break; 3335 case FFLAG: 3336 if (value == NULL) { 3337 missing_arg(LegalOpts[c]); 3338 } else { 3339 DiskName = value; 3340 Outputtofile = 1; 3341 } 3342 break; 3343 case DFLAG: 3344 if (value == NULL) { 3345 missing_arg(LegalOpts[c]); 3346 } else { 3347 Imagesize = atoi(value); 3348 } 3349 break; 3350 default: 3351 bad_arg(value); 3352 break; 3353 } 3354 } 3355 } 3356 3357 static 3358 void 3359 sanity_check_options(int argc, int optind) 3360 { 3361 if (GetFsParams) { 3362 if (argc - optind != 1) 3363 usage(); 3364 return; 3365 } 3366 3367 if (DontUseFdisk && GetOffset) { 3368 /* Set default relative offset of zero */ 3369 RelOffset = 0; 3370 } 3371 3372 if (BitsPerFAT == 32) 3373 MakeFAT32 = 1; 3374 3375 if (Outputtofile && (argc - optind)) { 3376 usage(); 3377 } else if (Outputtofile && !DiskName) { 3378 usage(); 3379 } else if (!Outputtofile && (argc - optind != 1)) { 3380 usage(); 3381 } else if (SunBPBfields && !BootBlkFn) { 3382 (void) fprintf(stderr, 3383 gettext("Use of the 'S' option requires that\n" 3384 "the 'B=' option also be used.\n\n")); 3385 usage(); 3386 } else if (Firstfileattr != 0x20 && !FirstFn) { 3387 (void) fprintf(stderr, 3388 gettext("Use of the 'r', 'h', or 's' options requires\n" 3389 "that the 'i=' option also be used.\n\n")); 3390 usage(); 3391 } else if (!GetOffset && !DontUseFdisk) { 3392 (void) fprintf(stderr, 3393 gettext("Use of the 'hidden' option requires that\n" 3394 "the 'nofdisk' option also be used.\n\n")); 3395 usage(); 3396 } else if (DontUseFdisk && GetSize) { 3397 (void) fprintf(stderr, 3398 gettext("Use of the 'nofdisk' option requires that\n" 3399 "the 'size=' option also be used.\n\n")); 3400 usage(); 3401 } else if (!GetBPF && 3402 BitsPerFAT != 12 && BitsPerFAT != 16 && BitsPerFAT != 32) { 3403 (void) fprintf(stderr, gettext("Invalid Bits/Fat value." 3404 " Must be 12, 16 or 32.\n")); 3405 exit(2); 3406 } else if (!GetSPC && !powerofx_le_y(2, 128, SecPerClust)) { 3407 (void) fprintf(stderr, 3408 gettext("Invalid Sectors/Cluster value. Must be a " 3409 "power of 2 between 1 and 128.\n")); 3410 exit(2); 3411 } else if (!GetResrvd && (Resrvd < 1 || Resrvd > 0xffff)) { 3412 (void) fprintf(stderr, 3413 gettext("Invalid number of reserved sectors. " 3414 "Must be at least 1 but\nno larger than 65535.")); 3415 exit(2); 3416 } else if (!GetResrvd && MakeFAT32 && 3417 (Resrvd < 32 || Resrvd > 0xffff)) { 3418 (void) fprintf(stderr, 3419 gettext("Invalid number of reserved sectors. " 3420 "Must be at least 32 but\nno larger than 65535.")); 3421 exit(2); 3422 } else if (Imagesize != 3 && Imagesize != 5) { 3423 usage(); 3424 } 3425 } 3426 3427 int 3428 main(int argc, char **argv) 3429 { 3430 off64_t AbsBootSect = 0; 3431 bpb_t dskparamblk; 3432 char *string; 3433 int fd; 3434 int c; 3435 3436 (void) setlocale(LC_ALL, ""); 3437 3438 #if !defined(TEXT_DOMAIN) 3439 #define TEXT_DOMAIN "SYS_TEST" 3440 #endif 3441 (void) textdomain(TEXT_DOMAIN); 3442 3443 while ((c = getopt(argc, argv, "F:Vmo:")) != EOF) { 3444 switch (c) { 3445 case 'F': 3446 string = optarg; 3447 if (strcmp(string, "pcfs") != 0) 3448 usage(); 3449 break; 3450 case 'V': 3451 { 3452 char *opt_text; 3453 int opt_count; 3454 3455 (void) fprintf(stdout, 3456 gettext("mkfs -F pcfs ")); 3457 for (opt_count = 1; opt_count < argc; 3458 opt_count++) { 3459 opt_text = argv[opt_count]; 3460 if (opt_text) 3461 (void) fprintf(stdout, 3462 " %s ", opt_text); 3463 } 3464 (void) fprintf(stdout, "\n"); 3465 } 3466 break; 3467 case 'm': 3468 GetFsParams++; 3469 break; 3470 case 'o': 3471 string = optarg; 3472 parse_suboptions(string); 3473 break; 3474 } 3475 } 3476 3477 sanity_check_options(argc, optind); 3478 3479 if (!Outputtofile) 3480 DiskName = argv[optind]; 3481 3482 (void) memset(&dskparamblk, 0, sizeof (dskparamblk)); 3483 3484 if (GetFsParams) { 3485 fd = open_and_examine(DiskName, &dskparamblk); 3486 } else { 3487 fd = open_and_seek(DiskName, &dskparamblk, &AbsBootSect); 3488 if (ask_nicely(DiskName)) 3489 write_fat(fd, AbsBootSect, BootBlkFn, Label, 3490 FirstFn, &dskparamblk); 3491 } 3492 (void) close(fd); 3493 return (0); 3494 } 3495