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 /* CSTYLED */ 2505 ) { 2506 (void) close(bsfd); 2507 bsfd = -1; 2508 (void) fprintf(stderr, 2509 gettext("Boot block (%s) bogus.\n"), fn); 2510 } 2511 *blkfilesize = fi.st_size; 2512 } 2513 return (bsfd); 2514 } 2515 2516 /* 2517 * verify_firstfile 2518 * 2519 * We were provided with the name of a file to be the first file 2520 * installed on the disk. We just need to verify it exists and 2521 * find out how big it is. If it doesn't exist, we print a warning 2522 * message about how the file wasn't found. We don't exit fatally, 2523 * though, rather we return a size of 0 and the FAT will be built 2524 * without installing any first file. They can then presumably 2525 * install the correct first file by hand. 2526 */ 2527 static 2528 int 2529 verify_firstfile(char *fn, ulong_t *filesize) 2530 { 2531 struct stat fi; 2532 int fd = -1; 2533 2534 *filesize = 0; 2535 if (stat(fn, &fi) || (fd = open(fn, O_RDONLY)) < 0) { 2536 perror(fn); 2537 (void) fprintf(stderr, 2538 gettext("Could not access requested file. It will not\n" 2539 "be installed in the new file system.\n")); 2540 } else { 2541 *filesize = fi.st_size; 2542 } 2543 2544 return (fd); 2545 } 2546 2547 /* 2548 * label_volume 2549 * 2550 * Fill in BPB with volume label. 2551 */ 2552 static 2553 void 2554 label_volume(char *lbl, bpb_t *wbpb) 2555 { 2556 int ll, i; 2557 2558 /* Put a volume label into our BPB. */ 2559 if (!lbl) 2560 lbl = DEFAULT_LABEL; 2561 2562 ll = min(11, (int)strlen(lbl)); 2563 for (i = 0; i < ll; i++) { 2564 wbpb->ebpb.volume_label[i] = toupper(lbl[i]); 2565 } 2566 for (; i < 11; i++) { 2567 wbpb->ebpb.volume_label[i] = ' '; 2568 } 2569 } 2570 2571 static 2572 int 2573 copy_bootblk(char *fn, boot_sector_t *bootsect, ulong_t *bootblksize) 2574 { 2575 int bsfd = -1; 2576 2577 if (Verbose && fn) 2578 (void) printf(gettext("Request to install boot " 2579 "block file %s.\n"), fn); 2580 else if (Verbose) 2581 (void) printf(gettext("Request to install DOS boot block.\n")); 2582 2583 /* 2584 * If they want to install their own boot block, sanity check 2585 * that block. 2586 */ 2587 if (fn) { 2588 bsfd = verify_bootblkfile(fn, bootsect, bootblksize); 2589 if (bsfd < 0) { 2590 exit(3); 2591 } 2592 *bootblksize = roundup(*bootblksize, BPSEC); 2593 } else { 2594 (void) memcpy(bootsect, DefBootSec, BPSEC); 2595 *bootblksize = BPSEC; 2596 } 2597 2598 return (bsfd); 2599 } 2600 2601 /* 2602 * mark_cluster 2603 * 2604 * This routine fills a FAT entry with the value supplied to it as an 2605 * argument. The fatp argument is assumed to be a pointer to the FAT's 2606 * 0th entry. The clustnum is the cluster entry that should be updated. 2607 * The value is the new value for the entry. 2608 */ 2609 static 2610 void 2611 mark_cluster(uchar_t *fatp, pc_cluster32_t clustnum, uint32_t value) 2612 { 2613 uchar_t *ep; 2614 ulong_t idx; 2615 2616 idx = (Fatentsize == 32) ? clustnum * 4 : 2617 (Fatentsize == 16) ? clustnum * 2 : clustnum + clustnum/2; 2618 ep = fatp + idx; 2619 2620 if (Fatentsize == 32) { 2621 store_32_bits(&ep, value); 2622 } else if (Fatentsize == 16) { 2623 store_16_bits(&ep, value); 2624 } else { 2625 if (clustnum & 1) { 2626 *ep = (*ep & 0x0f) | ((value << 4) & 0xf0); 2627 ep++; 2628 *ep = (value >> 4) & 0xff; 2629 } else { 2630 *ep++ = value & 0xff; 2631 *ep = (*ep & 0xf0) | ((value >> 8) & 0x0f); 2632 } 2633 } 2634 } 2635 2636 static 2637 uchar_t * 2638 build_fat(bpb_t *wbpb, struct fat_od_fsi *fsinfop, ulong_t bootblksize, 2639 ulong_t *fatsize, char *ffn, int *fffd, ulong_t *ffsize, 2640 pc_cluster32_t *ffstartclust) 2641 { 2642 pc_cluster32_t nextfree, ci; 2643 uchar_t *fatp; 2644 ushort_t numclust, numsect; 2645 int remclust; 2646 2647 /* Alloc space for a FAT and then null it out. */ 2648 if (Verbose) { 2649 (void) printf(gettext("BUILD FAT.\n%d sectors per fat.\n"), 2650 wbpb->bpb.sectors_per_fat ? wbpb->bpb.sectors_per_fat : 2651 wbpb->bpb32.big_sectors_per_fat); 2652 } 2653 2654 if (MakeFAT32) { 2655 *fatsize = BPSEC * wbpb->bpb32.big_sectors_per_fat; 2656 } else { 2657 *fatsize = BPSEC * wbpb->bpb.sectors_per_fat; 2658 } 2659 2660 if (!(fatp = (uchar_t *)malloc(*fatsize))) { 2661 perror(gettext("FAT table alloc")); 2662 exit(4); 2663 } else { 2664 (void) memset(fatp, 0, *fatsize); 2665 } 2666 2667 /* Build in-memory FAT */ 2668 *fatp = wbpb->bpb.media; 2669 *(fatp + 1) = 0xFF; 2670 *(fatp + 2) = 0xFF; 2671 2672 if (Fatentsize == 16) { 2673 *(fatp + 3) = 0xFF; 2674 } else if (Fatentsize == 32) { 2675 *(fatp + 3) = 0x0F; 2676 *(fatp + 4) = 0xFF; 2677 *(fatp + 5) = 0xFF; 2678 *(fatp + 6) = 0xFF; 2679 *(fatp + 7) = 0x0F; 2680 } 2681 2682 /* 2683 * Keep track of clusters used. 2684 */ 2685 remclust = TotalClusters; 2686 nextfree = 2; 2687 2688 /* 2689 * Get info on first file to install, if any. 2690 */ 2691 if (ffn) 2692 *fffd = verify_firstfile(ffn, ffsize); 2693 2694 /* 2695 * Compute number of clusters to preserve for bootblk overage. 2696 * Remember that we already wrote the first sector of the boot block. 2697 * These clusters are marked BAD to prevent them from being deleted 2698 * or used. The first available cluster is 2, so we always offset 2699 * the clusters. 2700 */ 2701 numsect = idivceil((bootblksize - BPSEC), BPSEC); 2702 numclust = idivceil(numsect, wbpb->bpb.sectors_per_cluster); 2703 2704 if (Verbose && numclust) 2705 (void) printf(gettext("Hiding %d excess bootblk cluster(s).\n"), 2706 numclust); 2707 for (ci = 0; ci < numclust; ci++) 2708 mark_cluster(fatp, nextfree++, 2709 MakeFAT32 ? PCF_BADCLUSTER32 : PCF_BADCLUSTER); 2710 remclust -= numclust; 2711 2712 /* 2713 * Reserve a cluster for the root directory on a FAT32. 2714 */ 2715 if (MakeFAT32) { 2716 mark_cluster(fatp, nextfree, PCF_LASTCLUSTER32); 2717 wbpb->bpb32.root_dir_clust = nextfree++; 2718 remclust--; 2719 } 2720 2721 /* 2722 * Compute and preserve number of clusters for first file. 2723 */ 2724 if (*fffd >= 0) { 2725 *ffstartclust = nextfree; 2726 numsect = idivceil(*ffsize, BPSEC); 2727 numclust = idivceil(numsect, wbpb->bpb.sectors_per_cluster); 2728 2729 if (numclust > remclust) { 2730 (void) fprintf(stderr, 2731 gettext("Requested first file too large to be\n" 2732 "installed in the new file system.\n")); 2733 (void) close(*fffd); 2734 *fffd = -1; 2735 goto finish; 2736 } 2737 2738 if (Verbose) 2739 (void) printf(gettext("Reserving %d first file " 2740 "cluster(s).\n"), numclust); 2741 for (ci = 0; (int)ci < (int)(numclust-1); ci++, nextfree++) 2742 mark_cluster(fatp, nextfree, nextfree + 1); 2743 mark_cluster(fatp, nextfree++, 2744 MakeFAT32 ? PCF_LASTCLUSTER32 : PCF_LASTCLUSTER); 2745 remclust -= numclust; 2746 } 2747 2748 finish: 2749 if (Verbose) { 2750 (void) printf(gettext("First sector of FAT")); 2751 header_for_dump(); 2752 dump_bytes(fatp, BPSEC); 2753 } 2754 2755 (void) memset(fsinfop, 0, sizeof (*fsinfop)); 2756 fsinfop->fsi_leadsig = LE_32(FSI_LEADSIG); 2757 fsinfop->fsi_strucsig = LE_32(FSI_STRUCSIG); 2758 fsinfop->fsi_trailsig = LE_32(FSI_TRAILSIG); 2759 fsinfop->fsi_incore.fs_free_clusters = LE_32(remclust); 2760 fsinfop->fsi_incore.fs_next_free = LE_32(nextfree); 2761 return (fatp); 2762 } 2763 2764 static 2765 void 2766 dirent_time_fill(struct pcdir *dep) 2767 { 2768 struct timeval tv; 2769 struct tm *tp; 2770 ushort_t dostime; 2771 ushort_t dosday; 2772 2773 (void) gettimeofday(&tv, (struct timezone *)0); 2774 tp = localtime(&tv.tv_sec); 2775 /* get the time & day into DOS format */ 2776 dostime = tp->tm_sec / 2; 2777 dostime |= tp->tm_min << 5; 2778 dostime |= tp->tm_hour << 11; 2779 dosday = tp->tm_mday; 2780 dosday |= (tp->tm_mon + 1) << 5; 2781 dosday |= (tp->tm_year - 80) << 9; 2782 dep->pcd_mtime.pct_time = htols(dostime); 2783 dep->pcd_mtime.pct_date = htols(dosday); 2784 } 2785 2786 static 2787 void 2788 dirent_label_fill(struct pcdir *dep, char *fn) 2789 { 2790 int nl, i; 2791 2792 /* 2793 * We spread the volume label across both the NAME and EXT fields 2794 */ 2795 nl = min(PCFNAMESIZE, strlen(fn)); 2796 for (i = 0; i < nl; i++) { 2797 dep->pcd_filename[i] = toupper(fn[i]); 2798 } 2799 if (i < PCFNAMESIZE) { 2800 for (; i < PCFNAMESIZE; i++) 2801 dep->pcd_filename[i] = ' '; 2802 for (i = 0; i < PCFEXTSIZE; i++) 2803 dep->pcd_ext[i] = ' '; 2804 return; 2805 } 2806 nl = min(PCFEXTSIZE, strlen(fn) - PCFNAMESIZE); 2807 for (i = 0; i < nl; i++) 2808 dep->pcd_ext[i] = toupper(fn[i + PCFNAMESIZE]); 2809 if (i < PCFEXTSIZE) { 2810 for (; i < PCFEXTSIZE; i++) 2811 dep->pcd_ext[i] = ' '; 2812 } 2813 } 2814 2815 static 2816 void 2817 dirent_fname_fill(struct pcdir *dep, char *fn) 2818 { 2819 char *fname, *fext; 2820 int nl, i; 2821 2822 if (fname = strrchr(fn, '/')) { 2823 fname++; 2824 } else { 2825 fname = fn; 2826 } 2827 2828 if (fext = strrchr(fname, '.')) { 2829 fext++; 2830 } else { 2831 fext = ""; 2832 } 2833 2834 fname = strtok(fname, "."); 2835 2836 nl = min(PCFNAMESIZE, (int)strlen(fname)); 2837 for (i = 0; i < nl; i++) { 2838 dep->pcd_filename[i] = toupper(fname[i]); 2839 } 2840 for (; i < PCFNAMESIZE; i++) { 2841 dep->pcd_filename[i] = ' '; 2842 } 2843 2844 nl = min(PCFEXTSIZE, (int)strlen(fext)); 2845 for (i = 0; i < nl; i++) { 2846 dep->pcd_ext[i] = toupper(fext[i]); 2847 } 2848 for (; i < PCFEXTSIZE; i++) { 2849 dep->pcd_ext[i] = ' '; 2850 } 2851 } 2852 2853 static 2854 uchar_t * 2855 build_rootdir(bpb_t *wbpb, char *ffn, int fffd, 2856 ulong_t ffsize, pc_cluster32_t ffstart, ulong_t *rdirsize) 2857 { 2858 struct pcdir *rootdirp; 2859 struct pcdir *entry; 2860 2861 /* 2862 * Build a root directory. It will have at least one entry, 2863 * the volume label and a second if the first file was defined. 2864 */ 2865 if (MakeFAT32) { 2866 /* 2867 * We devote an entire cluster to the root 2868 * directory on FAT32. 2869 */ 2870 *rdirsize = wbpb->bpb.sectors_per_cluster * BPSEC; 2871 } else { 2872 *rdirsize = wbpb->bpb.num_root_entries * sizeof (struct pcdir); 2873 } 2874 if ((rootdirp = (struct pcdir *)malloc(*rdirsize)) == NULL) { 2875 perror(gettext("Root directory allocation")); 2876 exit(4); 2877 } else { 2878 entry = rootdirp; 2879 (void) memset((char *)rootdirp, 0, *rdirsize); 2880 } 2881 2882 /* Create directory entry for first file, if there is one */ 2883 if (fffd >= 0) { 2884 dirent_fname_fill(entry, ffn); 2885 entry->pcd_attr = Firstfileattr; 2886 dirent_time_fill(entry); 2887 entry->pcd_scluster_lo = htols(ffstart); 2888 if (MakeFAT32) { 2889 ffstart = ffstart >> 16; 2890 entry->un.pcd_scluster_hi = htols(ffstart); 2891 } 2892 entry->pcd_size = htoli(ffsize); 2893 entry++; 2894 } 2895 2896 /* Create directory entry for volume label, if there is one */ 2897 if (Label != NULL) { 2898 dirent_label_fill(entry, Label); 2899 entry->pcd_attr = PCA_ARCH | PCA_LABEL; 2900 dirent_time_fill(entry); 2901 entry->pcd_scluster_lo = 0; 2902 if (MakeFAT32) { 2903 entry->un.pcd_scluster_hi = 0; 2904 } 2905 entry->pcd_size = 0; 2906 entry++; 2907 } 2908 2909 if (Verbose) { 2910 (void) printf(gettext("First two directory entries")); 2911 header_for_dump(); 2912 dump_bytes((uchar_t *)rootdirp, 2 * sizeof (struct pcdir)); 2913 } 2914 2915 return ((uchar_t *)rootdirp); 2916 } 2917 2918 /* 2919 * write_rest 2920 * 2921 * Write all the bytes from the current file pointer to end of file 2922 * in the source file out to the destination file. The writes should 2923 * be padded to whole clusters with 0's if necessary. 2924 */ 2925 static 2926 void 2927 write_rest(bpb_t *wbpb, char *efn, int dfd, int sfd, int remaining) 2928 { 2929 char buf[BPSEC]; 2930 ushort_t numsect, numclust; 2931 ushort_t wnumsect, s; 2932 int doneread = 0; 2933 int rstat; 2934 2935 /* 2936 * Compute number of clusters required to contain remaining bytes. 2937 */ 2938 numsect = idivceil(remaining, BPSEC); 2939 numclust = idivceil(numsect, wbpb->bpb.sectors_per_cluster); 2940 2941 wnumsect = numclust * wbpb->bpb.sectors_per_cluster; 2942 for (s = 0; s < wnumsect; s++) { 2943 if (!doneread) { 2944 if ((rstat = read(sfd, buf, BPSEC)) < 0) { 2945 perror(efn); 2946 doneread = 1; 2947 rstat = 0; 2948 } else if (rstat == 0) { 2949 doneread = 1; 2950 } 2951 (void) memset(&(buf[rstat]), 0, BPSEC - rstat); 2952 } 2953 if (write(dfd, buf, BPSEC) != BPSEC) { 2954 (void) fprintf(stderr, gettext("Copying ")); 2955 perror(efn); 2956 } 2957 } 2958 } 2959 2960 static 2961 void 2962 write_fat32_bootstuff(int fd, boot_sector_t *bsp, 2963 struct fat_od_fsi *fsinfop, off64_t seekto) 2964 { 2965 if (Verbose) { 2966 (void) printf(gettext("Dump of the fs info sector")); 2967 header_for_dump(); 2968 dump_bytes((uchar_t *)fsinfop, sizeof (*fsinfop)); 2969 } 2970 2971 if (!Notreally) { 2972 /* 2973 * FAT32's have an FS info sector, then a backup of the boot 2974 * sector, and a modified backup of the FS Info sector. 2975 */ 2976 if (write(fd, fsinfop, sizeof (*fsinfop)) != BPSEC) { 2977 perror(gettext("FS info sector write")); 2978 exit(4); 2979 } 2980 if (lseek64(fd, seekto + BKUP_BOOTSECT_OFFSET, SEEK_SET) < 0) { 2981 (void) close(fd); 2982 perror(gettext("Boot sector backup seek")); 2983 exit(4); 2984 } 2985 if (write(fd, bsp->buf, sizeof (bsp->buf)) != BPSEC) { 2986 perror(gettext("Boot sector backup write")); 2987 exit(4); 2988 } 2989 } 2990 2991 /* 2992 * Second copy of fs info sector is modified to have "don't know" 2993 * as the number of free clusters 2994 */ 2995 fsinfop->fsi_incore.fs_next_free = LE_32(FSINFO_UNKNOWN); 2996 2997 if (Verbose) { 2998 (void) printf(gettext("Dump of the backup fs info sector")); 2999 header_for_dump(); 3000 dump_bytes((uchar_t *)fsinfop, sizeof (*fsinfop)); 3001 } 3002 3003 if (!Notreally) { 3004 if (write(fd, fsinfop, sizeof (*fsinfop)) != BPSEC) { 3005 perror(gettext("FS info sector backup write")); 3006 exit(4); 3007 } 3008 } 3009 } 3010 3011 static 3012 void 3013 write_bootsects(int fd, boot_sector_t *bsp, bpb_t *wbpb, 3014 struct fat_od_fsi *fsinfop, off64_t seekto) 3015 { 3016 if (MakeFAT32) { 3017 /* Copy our BPB into bootsec structure */ 3018 #ifdef i386 3019 (void) memcpy(&(bsp->bs32.bs_front.bs_bpb), &(wbpb->bpb), 3020 sizeof (wbpb->bpb)); 3021 (void) memcpy(&(bsp->bs32.bs_bpb32), &(wbpb->bpb32), 3022 sizeof (wbpb->bpb32)); 3023 (void) memcpy(&(bsp->bs32.bs_ebpb), &(wbpb->ebpb), 3024 sizeof (wbpb->ebpb)); 3025 #else 3026 swap_pack_bpb32cpy(&(bsp->bs32), wbpb); 3027 #endif 3028 } else { 3029 /* Copy our BPB into bootsec structure */ 3030 #ifdef i386 3031 (void) memcpy(&(bsp->bs.bs_front.bs_bpb), &(wbpb->bpb), 3032 sizeof (wbpb->bpb)); 3033 (void) memcpy(&(bsp->bs.bs_ebpb), &(wbpb->ebpb), 3034 sizeof (wbpb->ebpb)); 3035 #else 3036 swap_pack_bpbcpy(&(bsp->bs), wbpb); 3037 #endif 3038 3039 /* Copy SUN BPB extensions into bootsec structure */ 3040 if (SunBPBfields) { 3041 #ifdef i386 3042 (void) memcpy(&(bsp->bs.bs_sebpb), &(wbpb->sunbpb), 3043 sizeof (wbpb->sunbpb)); 3044 #else 3045 swap_pack_sebpbcpy(&(bsp->bs), wbpb); 3046 #endif 3047 } 3048 } 3049 3050 /* Write boot sector */ 3051 if (!Notreally && write(fd, bsp->buf, sizeof (bsp->buf)) != BPSEC) { 3052 perror(gettext("Boot sector write")); 3053 exit(4); 3054 } 3055 3056 if (Verbose) { 3057 (void) printf(gettext("Dump of the boot sector")); 3058 header_for_dump(); 3059 dump_bytes(bsp->buf, sizeof (bsp->buf)); 3060 } 3061 3062 if (MakeFAT32) 3063 write_fat32_bootstuff(fd, bsp, fsinfop, seekto); 3064 } 3065 3066 static 3067 void 3068 write_fat(int fd, off64_t seekto, char *fn, char *lbl, char *ffn, bpb_t *wbpb) 3069 { 3070 struct fat_od_fsi fsinfo; 3071 pc_cluster32_t ffsc; 3072 boot_sector_t bootsect; 3073 uchar_t *fatp, *rdirp; 3074 ulong_t bootblksize, fatsize, rdirsize, ffsize; 3075 int bsfd = -1; 3076 int fffd = -1; 3077 3078 compute_file_area_size(wbpb); 3079 3080 bsfd = copy_bootblk(fn, &bootsect, &bootblksize); 3081 label_volume(lbl, wbpb); 3082 3083 if (Verbose) 3084 (void) printf(gettext("Building FAT.\n")); 3085 fatp = build_fat(wbpb, &fsinfo, bootblksize, &fatsize, 3086 ffn, &fffd, &ffsize, &ffsc); 3087 3088 write_bootsects(fd, &bootsect, wbpb, &fsinfo, seekto); 3089 3090 if (lseek64(fd, 3091 seekto + (BPSEC * wbpb->bpb.resv_sectors), SEEK_SET) < 0) { 3092 (void) close(fd); 3093 perror(gettext("Seek to end of reserved sectors")); 3094 exit(4); 3095 } 3096 3097 /* Write FAT */ 3098 if (Verbose) 3099 (void) printf(gettext("Writing FAT(s). %d bytes times %d.\n"), 3100 fatsize, wbpb->bpb.num_fats); 3101 if (!Notreally) { 3102 int nf, wb; 3103 for (nf = 0; nf < (int)wbpb->bpb.num_fats; nf++) 3104 if ((wb = write(fd, fatp, fatsize)) != fatsize) { 3105 perror(gettext("FAT write")); 3106 exit(4); 3107 } else { 3108 if (Verbose) 3109 (void) printf( 3110 gettext("Wrote %d bytes\n"), wb); 3111 } 3112 } 3113 free(fatp); 3114 3115 if (Verbose) 3116 (void) printf(gettext("Building root directory.\n")); 3117 rdirp = build_rootdir(wbpb, ffn, fffd, ffsize, ffsc, &rdirsize); 3118 3119 /* 3120 * In non FAT32, root directory exists outside of the file area 3121 */ 3122 if (!MakeFAT32) { 3123 if (Verbose) 3124 (void) printf(gettext("Writing root directory. " 3125 "%d bytes.\n"), rdirsize); 3126 if (!Notreally) { 3127 if (write(fd, rdirp, rdirsize) != rdirsize) { 3128 perror(gettext("Root directory write")); 3129 exit(4); 3130 } 3131 } 3132 free(rdirp); 3133 } 3134 3135 /* 3136 * Now write anything that needs to be in the file space. 3137 */ 3138 if (bootblksize > BPSEC) { 3139 if (Verbose) 3140 (void) printf(gettext("Writing remainder of " 3141 "boot block.\n")); 3142 if (!Notreally) 3143 write_rest(wbpb, fn, fd, bsfd, bootblksize - BPSEC); 3144 } 3145 3146 if (MakeFAT32) { 3147 if (Verbose) 3148 (void) printf(gettext("Writing root directory. " 3149 "%d bytes.\n"), rdirsize); 3150 if (!Notreally) { 3151 if (write(fd, rdirp, rdirsize) != rdirsize) { 3152 perror(gettext("Root directory write")); 3153 exit(4); 3154 } 3155 } 3156 free(rdirp); 3157 } 3158 3159 if (fffd >= 0) { 3160 if (Verbose) 3161 (void) printf(gettext("Writing first file.\n")); 3162 if (!Notreally) 3163 write_rest(wbpb, ffn, fd, fffd, ffsize); 3164 } 3165 } 3166 3167 static 3168 char *LegalOpts[] = { 3169 #define NFLAG 0 3170 "N", 3171 #define VFLAG 1 3172 "v", 3173 #define RFLAG 2 3174 "r", 3175 #define HFLAG 3 3176 "h", 3177 #define SFLAG 4 3178 "s", 3179 #define SUNFLAG 5 3180 "S", 3181 #define LABFLAG 6 3182 "b", 3183 #define BTRFLAG 7 3184 "B", 3185 #define INITFLAG 8 3186 "i", 3187 #define SZFLAG 9 3188 "size", 3189 #define SECTFLAG 10 3190 "nsect", 3191 #define TRKFLAG 11 3192 "ntrack", 3193 #define SPCFLAG 12 3194 "spc", 3195 #define BPFFLAG 13 3196 "fat", 3197 #define FFLAG 14 3198 "f", 3199 #define DFLAG 15 3200 "d", 3201 #define NOFDISKFLAG 16 3202 "nofdisk", 3203 #define RESRVFLAG 17 3204 "reserve", 3205 #define HIDDENFLAG 18 3206 "hidden", 3207 NULL 3208 }; 3209 3210 static 3211 void 3212 bad_arg(char *option) 3213 { 3214 (void) fprintf(stderr, 3215 gettext("Unrecognized option %s.\n"), option); 3216 usage(); 3217 exit(2); 3218 } 3219 3220 static 3221 void 3222 missing_arg(char *option) 3223 { 3224 (void) fprintf(stderr, 3225 gettext("Option %s requires a value.\n"), option); 3226 usage(); 3227 exit(3); 3228 } 3229 3230 static 3231 void 3232 parse_suboptions(char *optsstr) 3233 { 3234 char *value; 3235 int c; 3236 3237 while (*optsstr != '\0') { 3238 switch (c = getsubopt(&optsstr, LegalOpts, &value)) { 3239 case NFLAG: 3240 Notreally++; 3241 break; 3242 case VFLAG: 3243 Verbose++; 3244 break; 3245 case RFLAG: 3246 Firstfileattr |= 0x01; 3247 break; 3248 case HFLAG: 3249 Firstfileattr |= 0x02; 3250 break; 3251 case SFLAG: 3252 Firstfileattr |= 0x04; 3253 break; 3254 case SUNFLAG: 3255 SunBPBfields = 1; 3256 break; 3257 case LABFLAG: 3258 if (value == NULL) { 3259 missing_arg(LegalOpts[c]); 3260 } else { 3261 Label = value; 3262 } 3263 break; 3264 case BTRFLAG: 3265 if (value == NULL) { 3266 missing_arg(LegalOpts[c]); 3267 } else { 3268 BootBlkFn = value; 3269 } 3270 break; 3271 case INITFLAG: 3272 if (value == NULL) { 3273 missing_arg(LegalOpts[c]); 3274 } else { 3275 FirstFn = value; 3276 } 3277 break; 3278 case SZFLAG: 3279 if (value == NULL) { 3280 missing_arg(LegalOpts[c]); 3281 } else { 3282 TotSize = atoi(value); 3283 GetSize = 0; 3284 } 3285 break; 3286 case SECTFLAG: 3287 if (value == NULL) { 3288 missing_arg(LegalOpts[c]); 3289 } else { 3290 SecPerTrk = atoi(value); 3291 GetSPT = 0; 3292 } 3293 break; 3294 case TRKFLAG: 3295 if (value == NULL) { 3296 missing_arg(LegalOpts[c]); 3297 } else { 3298 TrkPerCyl = atoi(value); 3299 GetTPC = 0; 3300 } 3301 break; 3302 case SPCFLAG: 3303 if (value == NULL) { 3304 missing_arg(LegalOpts[c]); 3305 } else { 3306 SecPerClust = atoi(value); 3307 GetSPC = 0; 3308 } 3309 break; 3310 case BPFFLAG: 3311 if (value == NULL) { 3312 missing_arg(LegalOpts[c]); 3313 } else { 3314 BitsPerFAT = atoi(value); 3315 GetBPF = 0; 3316 } 3317 break; 3318 case NOFDISKFLAG: 3319 DontUseFdisk = 1; 3320 break; 3321 case RESRVFLAG: 3322 if (value == NULL) { 3323 missing_arg(LegalOpts[c]); 3324 } else { 3325 Resrvd = atoi(value); 3326 GetResrvd = 0; 3327 } 3328 break; 3329 case HIDDENFLAG: 3330 if (value == NULL) { 3331 missing_arg(LegalOpts[c]); 3332 } else { 3333 RelOffset = atoi(value); 3334 GetOffset = 0; 3335 } 3336 break; 3337 case FFLAG: 3338 if (value == NULL) { 3339 missing_arg(LegalOpts[c]); 3340 } else { 3341 DiskName = value; 3342 Outputtofile = 1; 3343 } 3344 break; 3345 case DFLAG: 3346 if (value == NULL) { 3347 missing_arg(LegalOpts[c]); 3348 } else { 3349 Imagesize = atoi(value); 3350 } 3351 break; 3352 default: 3353 bad_arg(value); 3354 break; 3355 } 3356 } 3357 } 3358 3359 static 3360 void 3361 sanity_check_options(int argc, int optind) 3362 { 3363 if (GetFsParams) { 3364 if (argc - optind != 1) 3365 usage(); 3366 return; 3367 } 3368 3369 if (DontUseFdisk && GetOffset) { 3370 /* Set default relative offset of zero */ 3371 RelOffset = 0; 3372 } 3373 3374 if (BitsPerFAT == 32) 3375 MakeFAT32 = 1; 3376 3377 if (Outputtofile && (argc - optind)) { 3378 usage(); 3379 } else if (Outputtofile && !DiskName) { 3380 usage(); 3381 } else if (!Outputtofile && (argc - optind != 1)) { 3382 usage(); 3383 } else if (SunBPBfields && !BootBlkFn) { 3384 (void) fprintf(stderr, 3385 gettext("Use of the 'S' option requires that\n" 3386 "the 'B=' option also be used.\n\n")); 3387 usage(); 3388 } else if (Firstfileattr != 0x20 && !FirstFn) { 3389 (void) fprintf(stderr, 3390 gettext("Use of the 'r', 'h', or 's' options requires\n" 3391 "that the 'i=' option also be used.\n\n")); 3392 usage(); 3393 } else if (!GetOffset && !DontUseFdisk) { 3394 (void) fprintf(stderr, 3395 gettext("Use of the 'hidden' option requires that\n" 3396 "the 'nofdisk' option also be used.\n\n")); 3397 usage(); 3398 } else if (DontUseFdisk && GetSize) { 3399 (void) fprintf(stderr, 3400 gettext("Use of the 'nofdisk' option requires that\n" 3401 "the 'size=' option also be used.\n\n")); 3402 usage(); 3403 } else if (!GetBPF && 3404 BitsPerFAT != 12 && BitsPerFAT != 16 && BitsPerFAT != 32) { 3405 (void) fprintf(stderr, gettext("Invalid Bits/Fat value." 3406 " Must be 12, 16 or 32.\n")); 3407 exit(2); 3408 } else if (!GetSPC && !powerofx_le_y(2, 128, SecPerClust)) { 3409 (void) fprintf(stderr, 3410 gettext("Invalid Sectors/Cluster value. Must be a " 3411 "power of 2 between 1 and 128.\n")); 3412 exit(2); 3413 } else if (!GetResrvd && (Resrvd < 1 || Resrvd > 0xffff)) { 3414 (void) fprintf(stderr, 3415 gettext("Invalid number of reserved sectors. " 3416 "Must be at least 1 but\nno larger than 65535.")); 3417 exit(2); 3418 } else if (!GetResrvd && MakeFAT32 && 3419 (Resrvd < 32 || Resrvd > 0xffff)) { 3420 (void) fprintf(stderr, 3421 gettext("Invalid number of reserved sectors. " 3422 "Must be at least 32 but\nno larger than 65535.")); 3423 exit(2); 3424 } else if (Imagesize != 3 && Imagesize != 5) { 3425 usage(); 3426 } 3427 } 3428 3429 int 3430 main(int argc, char **argv) 3431 { 3432 off64_t AbsBootSect = 0; 3433 bpb_t dskparamblk; 3434 char *string; 3435 int fd; 3436 int c; 3437 3438 (void) setlocale(LC_ALL, ""); 3439 3440 #if !defined(TEXT_DOMAIN) 3441 #define TEXT_DOMAIN "SYS_TEST" 3442 #endif 3443 (void) textdomain(TEXT_DOMAIN); 3444 3445 while ((c = getopt(argc, argv, "F:Vmo:")) != EOF) { 3446 switch (c) { 3447 case 'F': 3448 string = optarg; 3449 if (strcmp(string, "pcfs") != 0) 3450 usage(); 3451 break; 3452 case 'V': 3453 { 3454 char *opt_text; 3455 int opt_count; 3456 3457 (void) fprintf(stdout, 3458 gettext("mkfs -F pcfs ")); 3459 for (opt_count = 1; opt_count < argc; 3460 opt_count++) { 3461 opt_text = argv[opt_count]; 3462 if (opt_text) 3463 (void) fprintf(stdout, 3464 " %s ", opt_text); 3465 } 3466 (void) fprintf(stdout, "\n"); 3467 } 3468 break; 3469 case 'm': 3470 GetFsParams++; 3471 break; 3472 case 'o': 3473 string = optarg; 3474 parse_suboptions(string); 3475 break; 3476 } 3477 } 3478 3479 sanity_check_options(argc, optind); 3480 3481 if (!Outputtofile) 3482 DiskName = argv[optind]; 3483 3484 (void) memset(&dskparamblk, 0, sizeof (dskparamblk)); 3485 3486 if (GetFsParams) { 3487 fd = open_and_examine(DiskName, &dskparamblk); 3488 } else { 3489 fd = open_and_seek(DiskName, &dskparamblk, &AbsBootSect); 3490 if (ask_nicely(DiskName)) 3491 write_fat(fd, AbsBootSect, BootBlkFn, Label, 3492 FirstFn, &dskparamblk); 3493 } 3494 (void) close(fd); 3495 return (0); 3496 } 3497