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