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