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; 1318 ulong_t spc; 1319 ulong_t rds, tmpval1, tmpval2; 1320 ulong_t fatsz; 1321 volsize = wbpb->bpb.sectors_in_volume ? wbpb->bpb.sectors_in_volume : 1322 wbpb->bpb.sectors_in_logical_volume; 1323 volsize -= wbpb->bpb.resv_sectors; 1324 1325 if (GetSPC) { 1326 if (MakeFAT32) { 1327 if (volsize < 0x10428) { 1328 spc = 0; /* too small, trigger an error */ 1329 } else if (volsize <= 0x82000) { /* 260MB */ 1330 spc = 1; 1331 } else if (volsize <= 0x1000000) { /* 8G */ 1332 spc = 8; 1333 } else if (volsize <= 0x2000000) { /* 16G */ 1334 spc = 16; 1335 } else if (volsize <= 0x4000000) { /* 32G */ 1336 spc = 32; 1337 } else { 1338 spc = 64; 1339 } 1340 } else { 1341 /* FAT16 Table */ 1342 if (volsize <= 0x20D0) { /* 4.1M */ 1343 spc = 0; /* too small, trigger an error */ 1344 } else if (volsize <= 0x7FA8) { /* 16M */ 1345 spc = 2; 1346 } else if (volsize <= 0x40000) { /* 128M */ 1347 spc = 4; 1348 } else if (volsize <= 0x80000) { /* 256M */ 1349 spc = 8; 1350 } else if (volsize <= 0x100000) { /* 512M */ 1351 spc = 16; 1352 /* Entries beyond here are only if FAT16 is forced */ 1353 } else if (volsize <= 0x200000) { /* 1G */ 1354 spc = 32; 1355 } else if (volsize <= 0x400000) { /* 2G */ 1356 spc = 64; 1357 } else if (volsize <= 0x800000) { /* 4G */ 1358 spc = 128; 1359 } else { 1360 (void) fprintf(stderr, gettext( 1361 "Partition too large for a FAT!\n")); 1362 exit(4); 1363 } 1364 } 1365 } else { 1366 spc = SecPerClust; 1367 } 1368 1369 /* 1370 * RootDirSectors = ((BPB_RootEntCnt * 32) + 1371 * (BPB_BytsPerSec 1)) / BPB_BytsPerSec; 1372 */ 1373 rds = ((wbpb->bpb.num_root_entries * 32) + 1374 (wbpb->bpb.bytes_sector - 1)) / 1375 wbpb->bpb.bytes_sector; 1376 1377 if (GetBPF) { 1378 if (MakeFAT32) 1379 Fatentsize = 32; 1380 else 1381 Fatentsize = 16; 1382 } else { 1383 Fatentsize = BitsPerFAT; 1384 1385 if (Fatentsize == 12 && 1386 (volsize - rds) >= DOS_F12MAXC * spc) { 1387 /* 1388 * 4228473 No way to non-interactively make a 1389 * pcfs filesystem 1390 * 1391 * If we don't have an input TTY, or we aren't 1392 * really doing anything, then don't ask 1393 * questions. Assume a yes answer to any 1394 * questions we would ask. 1395 */ 1396 if (Notreally || !isatty(fileno(stdin))) { 1397 (void) printf( 1398 gettext("Volume too large for 12 bit FAT," 1399 " increasing to 16 bit FAT size.\n")); 1400 (void) fflush(stdout); 1401 Fatentsize = 16; 1402 } else { 1403 (void) printf( 1404 gettext("Volume too large for a 12 bit FAT.\n" 1405 "Increase to 16 bit FAT " 1406 "and continue (y/n)? ")); 1407 (void) fflush(stdout); 1408 if (yes()) 1409 Fatentsize = 16; 1410 else 1411 exit(5); 1412 } 1413 } 1414 } 1415 wbpb->bpb.sectors_per_cluster = spc; 1416 1417 if (!GetFsParams && FdiskFATsize < 0) { 1418 (void) printf( 1419 gettext("Cannot verify chosen/computed FAT " 1420 "entry size (%d bits) with FDISK table.\n" 1421 "FDISK table has an unknown file system " 1422 "type for this device. Giving up...\n"), 1423 Fatentsize, Fatentsize); 1424 exit(6); 1425 } else if (!GetFsParams && FdiskFATsize && FdiskFATsize != Fatentsize) { 1426 (void) printf( 1427 gettext("Chosen/computed FAT entry size (%d bits) " 1428 "does not match FDISK table (%d bits).\n"), 1429 Fatentsize, FdiskFATsize); 1430 (void) printf( 1431 gettext("Use -o fat=%d to build a FAT " 1432 "that matches the FDISK entry.\n"), FdiskFATsize); 1433 exit(6); 1434 } 1435 set_fat_string(wbpb, Fatentsize); 1436 /* 1437 * Compure the FAT sizes according to algorithm from Microsoft: 1438 * 1439 * RootDirSectors = ((BPB_RootEntCnt * 32) + 1440 * (BPB_BytsPerSec 1)) / BPB_BytsPerSec; 1441 * TmpVal1 = DskSize - (BPB_ResvdSecCnt + RootDirSectors); 1442 * TmpVal2 = (256 * BPB_SecPerClus) + BPB_NumFATs; 1443 * If (FATType == FAT32) 1444 * TmpVal2 = TmpVal2 / 2; 1445 * FATSz = (TMPVal1 + (TmpVal2 1)) / TmpVal2; 1446 * If (FATType == FAT32) { 1447 * BPB_FATSz16 = 0; 1448 * BPB_FATSz32 = FATSz; 1449 * } else { 1450 * BPB_FATSz16 = LOWORD(FATSz); 1451 * // there is no BPB_FATSz32 in a FAT16 BPB 1452 * } 1453 */ 1454 tmpval1 = volsize - (wbpb->bpb.resv_sectors + rds); 1455 1456 tmpval2 = (256 * wbpb->bpb.sectors_per_cluster) + 1457 wbpb->bpb.num_fats; 1458 1459 if (Fatentsize == 32) 1460 tmpval2 = tmpval2 / 2; 1461 1462 fatsz = (tmpval1 + (tmpval2 - 1)) / tmpval2; 1463 1464 /* Compute a sector/fat figure */ 1465 switch (Fatentsize) { 1466 case 32: 1467 wbpb->bpb.sectors_per_fat = 0; 1468 wbpb->bpb32.big_sectors_per_fat = fatsz; 1469 if (Verbose) 1470 (void) printf("compute_cluster_size: Sectors per " 1471 "FAT32 = %d\n", 1472 wbpb->bpb32.big_sectors_per_fat); 1473 break; 1474 case 12: 1475 default: /* 16 bit FAT */ 1476 wbpb->bpb.sectors_per_fat = (ushort_t)(fatsz & 0x0000FFFF); 1477 if (Verbose) 1478 (void) printf("compute_cluster_size: Sectors per " 1479 "FAT16 = %d\n", wbpb->bpb.sectors_per_fat); 1480 break; 1481 } 1482 } 1483 1484 static 1485 void 1486 find_fixed_details(int fd, bpb_t *wbpb) 1487 { 1488 struct dk_geom dginfo; 1489 1490 /* 1491 * Look up the last remaining bits of info we need 1492 * that is specific to the hard drive using a disk ioctl. 1493 */ 1494 if (GetSPT || GetTPC) { 1495 if ((ioctl(fd, DKIOCG_VIRTGEOM, &dginfo)) == -1) { 1496 if ((ioctl(fd, DKIOCG_PHYGEOM, &dginfo)) == -1) { 1497 if ((ioctl(fd, DKIOCGGEOM, &dginfo)) == -1) { 1498 (void) close(fd); 1499 perror( 1500 gettext("Drive geometry lookup (need " 1501 "tracks/cylinder and/or sectors/track")); 1502 exit(2); 1503 } 1504 } 1505 } 1506 } 1507 1508 wbpb->bpb.heads = (GetTPC ? dginfo.dkg_nhead : TrkPerCyl); 1509 wbpb->bpb.sectors_per_track = (GetSPT ? dginfo.dkg_nsect : SecPerTrk); 1510 1511 if (Verbose) { 1512 if (GetTPC) { 1513 (void) printf( 1514 gettext("DKIOCG determined number of heads = %d\n"), 1515 dginfo.dkg_nhead); 1516 } 1517 if (GetSPT) { 1518 (void) printf( 1519 gettext("DKIOCG determined sectors per track = %d\n"), 1520 dginfo.dkg_nsect); 1521 } 1522 } 1523 1524 /* 1525 * XXX - MAY need an additional flag (or flags) to set media 1526 * and physical drive number fields. That in the case of weird 1527 * floppies that have to go through 'nofdisk' route for formatting. 1528 */ 1529 wbpb->bpb.media = 0xF8; 1530 if (MakeFAT32) 1531 wbpb->bpb.num_root_entries = 0; 1532 else 1533 wbpb->bpb.num_root_entries = 512; 1534 wbpb->ebpb.phys_drive_num = 0x80; 1535 compute_cluster_size(wbpb); 1536 } 1537 1538 static 1539 char * 1540 stat_actual_disk(char *diskname, struct stat *info, char **suffix) 1541 { 1542 char *actualdisk; 1543 1544 if (stat(diskname, info)) { 1545 /* 1546 * Device named on command line doesn't exist. That 1547 * probably means there is a partition-specifying 1548 * suffix attached to the actual disk name. 1549 */ 1550 actualdisk = strtok(strdup(diskname), ":"); 1551 if (*suffix = strchr(diskname, ':')) 1552 (*suffix)++; 1553 1554 if (stat(actualdisk, info)) { 1555 perror(actualdisk); 1556 exit(2); 1557 } 1558 } else { 1559 actualdisk = strdup(diskname); 1560 } 1561 1562 return (actualdisk); 1563 } 1564 1565 static 1566 void 1567 compute_file_area_size(bpb_t *wbpb) 1568 { 1569 int FATSz; 1570 int TotSec; 1571 int DataSec; 1572 int RootDirSectors = ((wbpb->bpb.num_root_entries * 32) + 1573 (wbpb->bpb.bytes_sector - 1)) / 1574 wbpb->bpb.bytes_sector; 1575 1576 if (wbpb->bpb.sectors_per_fat) { 1577 /* 1578 * Good old FAT12 or FAT16 1579 */ 1580 FATSz = wbpb->bpb.sectors_per_fat; 1581 TotSec = wbpb->bpb.sectors_in_volume; 1582 } else { 1583 /* 1584 * FAT32 1585 */ 1586 FATSz = wbpb->bpb32.big_sectors_per_fat; 1587 TotSec = wbpb->bpb.sectors_in_logical_volume; 1588 } 1589 1590 DataSec = TotSec - (wbpb->bpb.resv_sectors + 1591 (wbpb->bpb.num_fats * FATSz) + 1592 RootDirSectors); 1593 1594 1595 /* 1596 * Now change sectors to clusters 1597 */ 1598 TotalClusters = DataSec / wbpb->bpb.sectors_per_cluster; 1599 1600 if (Verbose) 1601 (void) printf(gettext("Disk has a file area of %d " 1602 "allocation units,\neach with %d sectors = %d " 1603 "bytes.\n"), TotalClusters, wbpb->bpb.sectors_per_cluster, 1604 TotalClusters * wbpb->bpb.sectors_per_cluster * BPSEC); 1605 } 1606 1607 #ifndef i386 1608 /* 1609 * swap_pack_{bpb,bpb32,sebpb}cpy 1610 * 1611 * If not on an x86 we assume the structures making up the bpb 1612 * were not packed and that longs and shorts need to be byte swapped 1613 * (we've kept everything in host order up until now). A new architecture 1614 * might not need to swap or might not need to pack, in which case 1615 * new routines will have to be written. Of course if an architecture 1616 * supports both packing and little-endian host order, it can follow the 1617 * same path as the x86 code. 1618 */ 1619 static 1620 void 1621 swap_pack_bpbcpy(struct _boot_sector *bsp, bpb_t *wbpb) 1622 { 1623 uchar_t *fillp; 1624 1625 fillp = (uchar_t *)&(bsp->bs_filler[ORIG_BPB_START_INDEX]); 1626 1627 store_16_bits(&fillp, wbpb->bpb.bytes_sector); 1628 *fillp++ = wbpb->bpb.sectors_per_cluster; 1629 store_16_bits(&fillp, wbpb->bpb.resv_sectors); 1630 *fillp++ = wbpb->bpb.num_fats; 1631 store_16_bits(&fillp, wbpb->bpb.num_root_entries); 1632 store_16_bits(&fillp, wbpb->bpb.sectors_in_volume); 1633 *fillp++ = wbpb->bpb.media; 1634 store_16_bits(&fillp, wbpb->bpb.sectors_per_fat); 1635 store_16_bits(&fillp, wbpb->bpb.sectors_per_track); 1636 store_16_bits(&fillp, wbpb->bpb.heads); 1637 store_32_bits(&fillp, wbpb->bpb.hidden_sectors); 1638 store_32_bits(&fillp, wbpb->bpb.sectors_in_logical_volume); 1639 1640 *fillp++ = wbpb->ebpb.phys_drive_num; 1641 *fillp++ = wbpb->ebpb.reserved; 1642 *fillp++ = wbpb->ebpb.ext_signature; 1643 store_32_bits(&fillp, wbpb->ebpb.volume_id); 1644 (void) strncpy((char *)fillp, (char *)wbpb->ebpb.volume_label, 11); 1645 fillp += 11; 1646 (void) strncpy((char *)fillp, (char *)wbpb->ebpb.type, 8); 1647 } 1648 1649 static 1650 void 1651 swap_pack_bpb32cpy(struct _boot_sector32 *bsp, bpb_t *wbpb) 1652 { 1653 uchar_t *fillp; 1654 int r; 1655 1656 fillp = (uchar_t *)&(bsp->bs_filler[ORIG_BPB_START_INDEX]); 1657 1658 store_16_bits(&fillp, wbpb->bpb.bytes_sector); 1659 *fillp++ = wbpb->bpb.sectors_per_cluster; 1660 store_16_bits(&fillp, wbpb->bpb.resv_sectors); 1661 *fillp++ = wbpb->bpb.num_fats; 1662 store_16_bits(&fillp, wbpb->bpb.num_root_entries); 1663 store_16_bits(&fillp, wbpb->bpb.sectors_in_volume); 1664 *fillp++ = wbpb->bpb.media; 1665 store_16_bits(&fillp, wbpb->bpb.sectors_per_fat); 1666 store_16_bits(&fillp, wbpb->bpb.sectors_per_track); 1667 store_16_bits(&fillp, wbpb->bpb.heads); 1668 store_32_bits(&fillp, wbpb->bpb.hidden_sectors); 1669 store_32_bits(&fillp, wbpb->bpb.sectors_in_logical_volume); 1670 1671 store_32_bits(&fillp, wbpb->bpb32.big_sectors_per_fat); 1672 store_16_bits(&fillp, wbpb->bpb32.ext_flags); 1673 *fillp++ = wbpb->bpb32.fs_vers_lo; 1674 *fillp++ = wbpb->bpb32.fs_vers_hi; 1675 store_32_bits(&fillp, wbpb->bpb32.root_dir_clust); 1676 store_16_bits(&fillp, wbpb->bpb32.fsinfosec); 1677 store_16_bits(&fillp, wbpb->bpb32.backupboot); 1678 for (r = 0; r < 6; r++) 1679 store_16_bits(&fillp, wbpb->bpb32.reserved[r]); 1680 1681 *fillp++ = wbpb->ebpb.phys_drive_num; 1682 *fillp++ = wbpb->ebpb.reserved; 1683 *fillp++ = wbpb->ebpb.ext_signature; 1684 store_32_bits(&fillp, wbpb->ebpb.volume_id); 1685 (void) strncpy((char *)fillp, (char *)wbpb->ebpb.volume_label, 11); 1686 fillp += 11; 1687 (void) strncpy((char *)fillp, (char *)wbpb->ebpb.type, 8); 1688 } 1689 1690 static 1691 void 1692 swap_pack_sebpbcpy(struct _boot_sector *bsp, bpb_t *wbpb) 1693 { 1694 uchar_t *fillp; 1695 1696 fillp = bsp->bs_sun_bpb; 1697 store_16_bits(&fillp, wbpb->sunbpb.bs_offset_high); 1698 store_16_bits(&fillp, wbpb->sunbpb.bs_offset_low); 1699 } 1700 1701 static 1702 void 1703 swap_pack_grabbpb(bpb_t *wbpb, struct _boot_sector *bsp) 1704 { 1705 uchar_t *grabp; 1706 1707 grabp = (uchar_t *)&(bsp->bs_filler[ORIG_BPB_START_INDEX]); 1708 1709 ((uchar_t *)&(wbpb->bpb.bytes_sector))[1] = *grabp++; 1710 ((uchar_t *)&(wbpb->bpb.bytes_sector))[0] = *grabp++; 1711 wbpb->bpb.sectors_per_cluster = *grabp++; 1712 ((uchar_t *)&(wbpb->bpb.resv_sectors))[1] = *grabp++; 1713 ((uchar_t *)&(wbpb->bpb.resv_sectors))[0] = *grabp++; 1714 wbpb->bpb.num_fats = *grabp++; 1715 ((uchar_t *)&(wbpb->bpb.num_root_entries))[1] = *grabp++; 1716 ((uchar_t *)&(wbpb->bpb.num_root_entries))[0] = *grabp++; 1717 ((uchar_t *)&(wbpb->bpb.sectors_in_volume))[1] = *grabp++; 1718 ((uchar_t *)&(wbpb->bpb.sectors_in_volume))[0] = *grabp++; 1719 wbpb->bpb.media = *grabp++; 1720 ((uchar_t *)&(wbpb->bpb.sectors_per_fat))[1] = *grabp++; 1721 ((uchar_t *)&(wbpb->bpb.sectors_per_fat))[0] = *grabp++; 1722 ((uchar_t *)&(wbpb->bpb.sectors_per_track))[1] = *grabp++; 1723 ((uchar_t *)&(wbpb->bpb.sectors_per_track))[0] = *grabp++; 1724 ((uchar_t *)&(wbpb->bpb.heads))[1] = *grabp++; 1725 ((uchar_t *)&(wbpb->bpb.heads))[0] = *grabp++; 1726 ((uchar_t *)&(wbpb->bpb.hidden_sectors))[3] = *grabp++; 1727 ((uchar_t *)&(wbpb->bpb.hidden_sectors))[2] = *grabp++; 1728 ((uchar_t *)&(wbpb->bpb.hidden_sectors))[1] = *grabp++; 1729 ((uchar_t *)&(wbpb->bpb.hidden_sectors))[0] = *grabp++; 1730 ((uchar_t *)&(wbpb->bpb.sectors_in_logical_volume))[3] = *grabp++; 1731 ((uchar_t *)&(wbpb->bpb.sectors_in_logical_volume))[2] = *grabp++; 1732 ((uchar_t *)&(wbpb->bpb.sectors_in_logical_volume))[1] = *grabp++; 1733 ((uchar_t *)&(wbpb->bpb.sectors_in_logical_volume))[0] = *grabp++; 1734 wbpb->ebpb.phys_drive_num = *grabp++; 1735 wbpb->ebpb.reserved = *grabp++; 1736 wbpb->ebpb.ext_signature = *grabp++; 1737 ((uchar_t *)&(wbpb->ebpb.volume_id))[3] = *grabp++; 1738 ((uchar_t *)&(wbpb->ebpb.volume_id))[2] = *grabp++; 1739 ((uchar_t *)&(wbpb->ebpb.volume_id))[1] = *grabp++; 1740 ((uchar_t *)&(wbpb->ebpb.volume_id))[0] = *grabp++; 1741 1742 (void) strncpy((char *)wbpb->ebpb.volume_label, (char *)grabp, 11); 1743 grabp += 11; 1744 (void) strncpy((char *)wbpb->ebpb.type, (char *)grabp, 8); 1745 } 1746 1747 static 1748 void 1749 swap_pack_grabsebpb(bpb_t *wbpb, struct _boot_sector *bsp) 1750 { 1751 uchar_t *grabp; 1752 1753 grabp = bsp->bs_sun_bpb; 1754 ((uchar_t *)&(wbpb->sunbpb.bs_offset_high))[1] = *grabp++; 1755 ((uchar_t *)&(wbpb->sunbpb.bs_offset_high))[0] = *grabp++; 1756 ((uchar_t *)&(wbpb->sunbpb.bs_offset_low))[1] = *grabp++; 1757 ((uchar_t *)&(wbpb->sunbpb.bs_offset_low))[0] = *grabp++; 1758 } 1759 1760 static 1761 void 1762 swap_pack_grab32bpb(bpb_t *wbpb, struct _boot_sector *bsp) 1763 { 1764 uchar_t *grabp; 1765 1766 grabp = (uchar_t *)&(bsp->bs_filler[BPB_32_START_INDEX]); 1767 1768 ((uchar_t *)&(wbpb->bpb32.big_sectors_per_fat))[3] = *grabp++; 1769 ((uchar_t *)&(wbpb->bpb32.big_sectors_per_fat))[2] = *grabp++; 1770 ((uchar_t *)&(wbpb->bpb32.big_sectors_per_fat))[1] = *grabp++; 1771 ((uchar_t *)&(wbpb->bpb32.big_sectors_per_fat))[0] = *grabp++; 1772 ((uchar_t *)&(wbpb->bpb32.ext_flags))[1] = *grabp++; 1773 ((uchar_t *)&(wbpb->bpb32.ext_flags))[0] = *grabp++; 1774 wbpb->bpb32.fs_vers_lo = *grabp++; 1775 wbpb->bpb32.fs_vers_hi = *grabp++; 1776 ((uchar_t *)&(wbpb->bpb32.root_dir_clust))[3] = *grabp++; 1777 ((uchar_t *)&(wbpb->bpb32.root_dir_clust))[2] = *grabp++; 1778 ((uchar_t *)&(wbpb->bpb32.root_dir_clust))[1] = *grabp++; 1779 ((uchar_t *)&(wbpb->bpb32.root_dir_clust))[0] = *grabp++; 1780 ((uchar_t *)&(wbpb->bpb32.fsinfosec))[1] = *grabp++; 1781 ((uchar_t *)&(wbpb->bpb32.fsinfosec))[0] = *grabp++; 1782 ((uchar_t *)&(wbpb->bpb32.backupboot))[1] = *grabp++; 1783 ((uchar_t *)&(wbpb->bpb32.backupboot))[0] = *grabp++; 1784 ((uchar_t *)&(wbpb->bpb32.reserved[0]))[1] = *grabp++; 1785 ((uchar_t *)&(wbpb->bpb32.reserved[0]))[0] = *grabp++; 1786 ((uchar_t *)&(wbpb->bpb32.reserved[1]))[1] = *grabp++; 1787 ((uchar_t *)&(wbpb->bpb32.reserved[1]))[0] = *grabp++; 1788 ((uchar_t *)&(wbpb->bpb32.reserved[2]))[1] = *grabp++; 1789 ((uchar_t *)&(wbpb->bpb32.reserved[2]))[0] = *grabp++; 1790 ((uchar_t *)&(wbpb->bpb32.reserved[3]))[1] = *grabp++; 1791 ((uchar_t *)&(wbpb->bpb32.reserved[3]))[0] = *grabp++; 1792 ((uchar_t *)&(wbpb->bpb32.reserved[4]))[1] = *grabp++; 1793 ((uchar_t *)&(wbpb->bpb32.reserved[4]))[0] = *grabp++; 1794 ((uchar_t *)&(wbpb->bpb32.reserved[5]))[1] = *grabp++; 1795 ((uchar_t *)&(wbpb->bpb32.reserved[5]))[0] = *grabp++; 1796 } 1797 #endif /* ! i386 */ 1798 1799 static 1800 void 1801 dashm_bail(int fd) 1802 { 1803 (void) fprintf(stderr, 1804 gettext("This media does not appear to be " 1805 "formatted with a FAT file system.\n")); 1806 (void) close(fd); 1807 exit(6); 1808 } 1809 1810 /* 1811 * read_existing_bpb 1812 * 1813 * Grab the first sector, which we think is a bios parameter block. 1814 * If it looks bad, bail. Otherwise fill in the parameter struct 1815 * fields that matter. 1816 */ 1817 static 1818 void 1819 read_existing_bpb(int fd, bpb_t *wbpb) 1820 { 1821 boot_sector_t ubpb; 1822 1823 if (read(fd, ubpb.buf, BPSEC) < BPSEC) { 1824 perror(gettext("Read BIOS parameter block " 1825 "from previously formatted media")); 1826 (void) close(fd); 1827 exit(6); 1828 } 1829 1830 if (ltohs(ubpb.mb.signature) != BOOTSECSIG) { 1831 dashm_bail(fd); 1832 } 1833 1834 #ifdef i386 1835 (void) memcpy(&(wbpb->bpb), &(ubpb.bs.bs_front.bs_bpb), 1836 sizeof (wbpb->bpb)); 1837 (void) memcpy(&(wbpb->ebpb), &(ubpb.bs.bs_ebpb), sizeof (wbpb->ebpb)); 1838 #else 1839 swap_pack_grabbpb(wbpb, &(ubpb.bs)); 1840 #endif 1841 if (SunBPBfields) { 1842 #ifdef i386 1843 (void) memcpy(&(wbpb->sunbpb), &(ubpb.bs.bs_sebpb), 1844 sizeof (wbpb->sunbpb)); 1845 #else 1846 swap_pack_grabsebpb(wbpb, &(ubpb.bs)); 1847 #endif 1848 } 1849 if (wbpb->bpb.bytes_sector != BPSEC) { 1850 (void) fprintf(stderr, 1851 gettext("Bogus bytes per sector value.\n")); 1852 if (!powerofx_le_y(2, BPSEC * 8, wbpb->bpb.bytes_sector)) { 1853 (void) fprintf(stderr, 1854 gettext("The device name may be missing a " 1855 "logical drive specifier.\n")); 1856 (void) close(fd); 1857 exit(6); 1858 } else { 1859 (void) fprintf(stderr, 1860 gettext("Do not know how to build FATs with a\n" 1861 "non-standard sector size. Standard " 1862 "size is %d bytes,\nyour sector size " 1863 "is %d bytes.\n"), BPSEC, 1864 wbpb->bpb.bytes_sector); 1865 (void) close(fd); 1866 exit(6); 1867 } 1868 } 1869 if (!(powerofx_le_y(2, 128, wbpb->bpb.sectors_per_cluster))) { 1870 (void) fprintf(stderr, 1871 gettext("Bogus sectors per cluster value.\n")); 1872 (void) fprintf(stderr, 1873 gettext("The device name may be missing a " 1874 "logical drive specifier.\n")); 1875 (void) close(fd); 1876 exit(6); 1877 } 1878 1879 if (wbpb->bpb.sectors_per_fat == 0) { 1880 #ifdef i386 1881 (void) memcpy(&(wbpb->bpb32), &(ubpb.bs32.bs_bpb32), 1882 sizeof (wbpb->bpb32)); 1883 #else 1884 swap_pack_grab32bpb(wbpb, &(ubpb.bs)); 1885 #endif 1886 compute_file_area_size(wbpb); 1887 if ((wbpb->bpb32.big_sectors_per_fat * BPSEC / 4) >= 1888 TotalClusters) { 1889 MakeFAT32 = 1; 1890 } else { 1891 dashm_bail(fd); 1892 } 1893 } else { 1894 compute_file_area_size(wbpb); 1895 } 1896 } 1897 1898 /* 1899 * compare_existing_with_computed 1900 * 1901 * We use this function when we the user specifies the -m option. 1902 * We compute and look up things like we would if they had asked 1903 * us to make the fs, and compare that to what's already layed down 1904 * in the existing fs. If there's a difference we can tell them what 1905 * options to specify in order to reproduce their existing layout. 1906 * Note that they still may not get an exact duplicate, because we 1907 * don't, for example, preserve their existing boot code. We think 1908 * we've got all the fields that matter covered, though. 1909 * 1910 * XXX - We're basically ignoring sbpb at this point. I'm unsure 1911 * if we'll ever care about those fields, in terms of the -m option. 1912 */ 1913 static 1914 void 1915 compare_existing_with_computed(int fd, char *suffix, 1916 bpb_t *wbpb, int *prtsize, int *prtspc, int *prtbpf, int *prtnsect, 1917 int *prtntrk, int *prtfdisk, int *prthidden, int *prtrsrvd, int *dashos) 1918 { 1919 struct dk_geom dginfo; 1920 struct fd_char fdchar; 1921 bpb_t compare; 1922 int fd_ioctl_worked = 0; 1923 int fatents; 1924 1925 /* 1926 * For all non-floppy cases we expect to find a 16-bit FAT 1927 */ 1928 int expectfatsize = 16; 1929 1930 compare = *wbpb; 1931 1932 if (!suffix) { 1933 if (ioctl(fd, FDIOGCHAR, &fdchar) != -1) { 1934 expectfatsize = 12; 1935 fd_ioctl_worked++; 1936 } 1937 } 1938 1939 if (fd_ioctl_worked) { 1940 #ifdef sparc 1941 fdchar.fdc_medium = 3; 1942 #endif 1943 GetSize = GetSPT = GetSPC = GetTPC = GetBPF = 1; 1944 lookup_floppy(&fdchar, &compare); 1945 if (compare.bpb.heads != wbpb->bpb.heads) { 1946 (*prtntrk)++; 1947 (*dashos)++; 1948 } 1949 if (compare.bpb.sectors_per_track != 1950 wbpb->bpb.sectors_per_track) { 1951 (*prtnsect)++; 1952 (*dashos)++; 1953 } 1954 } else { 1955 int dk_ioctl_worked = 1; 1956 1957 if (!suffix) { 1958 (*prtfdisk)++; 1959 (*prtsize)++; 1960 *dashos += 2; 1961 } 1962 if ((ioctl(fd, DKIOCG_VIRTGEOM, &dginfo)) == -1) { 1963 if ((ioctl(fd, DKIOCG_PHYGEOM, &dginfo)) == -1) { 1964 if ((ioctl(fd, DKIOCGGEOM, &dginfo)) == -1) { 1965 *prtnsect = *prtntrk = 1; 1966 *dashos += 2; 1967 dk_ioctl_worked = 0; 1968 } 1969 } 1970 } 1971 if (dk_ioctl_worked) { 1972 if (dginfo.dkg_nhead != wbpb->bpb.heads) { 1973 (*prtntrk)++; 1974 (*dashos)++; 1975 } 1976 if (dginfo.dkg_nsect != 1977 wbpb->bpb.sectors_per_track) { 1978 (*prtnsect)++; 1979 (*dashos)++; 1980 } 1981 } 1982 GetBPF = GetSPC = 1; 1983 compute_cluster_size(&compare); 1984 } 1985 1986 if (!*prtfdisk && TotSize != wbpb->bpb.sectors_in_volume && 1987 TotSize != wbpb->bpb.sectors_in_logical_volume) { 1988 (*dashos)++; 1989 (*prtsize)++; 1990 } 1991 1992 if (compare.bpb.sectors_per_cluster != wbpb->bpb.sectors_per_cluster) { 1993 (*dashos)++; 1994 (*prtspc)++; 1995 } 1996 1997 if (compare.bpb.hidden_sectors != wbpb->bpb.hidden_sectors) { 1998 (*dashos)++; 1999 (*prthidden)++; 2000 } 2001 2002 if (compare.bpb.resv_sectors != wbpb->bpb.resv_sectors) { 2003 (*dashos)++; 2004 (*prtrsrvd)++; 2005 } 2006 2007 /* 2008 * Compute approximate Fatentsize. It's approximate because the 2009 * size of the FAT may not be exactly a multiple of the number of 2010 * clusters. It should be close, though. 2011 */ 2012 if (MakeFAT32) { 2013 Fatentsize = 32; 2014 (*dashos)++; 2015 (*prtbpf)++; 2016 } else { 2017 fatents = wbpb->bpb.sectors_per_fat * BPSEC * 2 / 3; 2018 if (fatents >= TotalClusters && wbpb->ebpb.type[4] == '2') 2019 Fatentsize = 12; 2020 else 2021 Fatentsize = 16; 2022 if (Fatentsize != expectfatsize) { 2023 (*dashos)++; 2024 (*prtbpf)++; 2025 } 2026 } 2027 } 2028 2029 static 2030 void 2031 print_reproducing_command(int fd, char *actualdisk, char *suffix, bpb_t *wbpb) 2032 { 2033 int needcomma = 0; 2034 int prthidden = 0; 2035 int prtrsrvd = 0; 2036 int prtfdisk = 0; 2037 int prtnsect = 0; 2038 int prtntrk = 0; 2039 int prtsize = 0; 2040 int prtbpf = 0; 2041 int prtspc = 0; 2042 int dashos = 0; 2043 int ll, i; 2044 2045 compare_existing_with_computed(fd, suffix, wbpb, 2046 &prtsize, &prtspc, &prtbpf, &prtnsect, &prtntrk, 2047 &prtfdisk, &prthidden, &prtrsrvd, &dashos); 2048 2049 /* 2050 * Print out the command line they can use to reproduce the 2051 * file system. 2052 */ 2053 (void) printf("mkfs -F pcfs"); 2054 2055 ll = min(11, (int)strlen((char *)wbpb->ebpb.volume_label)); 2056 /* 2057 * First, eliminate trailing spaces. Now compare the name against 2058 * our default label. If there's a match we don't need to print 2059 * any label info. 2060 */ 2061 i = ll; 2062 while (wbpb->ebpb.volume_label[--i] == ' '); 2063 ll = i; 2064 2065 if (ll == strlen(DEFAULT_LABEL) - 1) { 2066 char cmpbuf[11]; 2067 2068 (void) strcpy(cmpbuf, DEFAULT_LABEL); 2069 for (i = ll; i >= 0; i--) { 2070 if (cmpbuf[i] != 2071 toupper((int)(wbpb->ebpb.volume_label[i]))) { 2072 break; 2073 } 2074 } 2075 if (i < 0) 2076 ll = i; 2077 } 2078 2079 if (ll >= 0) { 2080 (void) printf(" -o "); 2081 (void) printf("b=\""); 2082 for (i = 0; i <= ll; i++) { 2083 (void) printf("%c", wbpb->ebpb.volume_label[i]); 2084 } 2085 (void) printf("\""); 2086 needcomma++; 2087 } else if (dashos) { 2088 (void) printf(" -o "); 2089 } 2090 2091 #define NEXT_DASH_O dashos--; needcomma++; continue 2092 2093 while (dashos) { 2094 if (needcomma) { 2095 (void) printf(","); 2096 needcomma = 0; 2097 } 2098 if (prtfdisk) { 2099 (void) printf("nofdisk"); 2100 prtfdisk--; 2101 NEXT_DASH_O; 2102 } 2103 if (prtsize) { 2104 (void) printf("size=%u", wbpb->bpb.sectors_in_volume ? 2105 wbpb->bpb.sectors_in_volume : 2106 wbpb->bpb.sectors_in_logical_volume); 2107 prtsize--; 2108 NEXT_DASH_O; 2109 } 2110 if (prtnsect) { 2111 (void) printf("nsect=%d", wbpb->bpb.sectors_per_track); 2112 prtnsect--; 2113 NEXT_DASH_O; 2114 } 2115 if (prtspc) { 2116 (void) printf("spc=%d", wbpb->bpb.sectors_per_cluster); 2117 prtspc--; 2118 NEXT_DASH_O; 2119 } 2120 if (prtntrk) { 2121 (void) printf("ntrack=%d", wbpb->bpb.heads); 2122 prtntrk--; 2123 NEXT_DASH_O; 2124 } 2125 if (prtbpf) { 2126 (void) printf("fat=%d", Fatentsize); 2127 prtbpf--; 2128 NEXT_DASH_O; 2129 } 2130 if (prthidden) { 2131 (void) printf("hidden=%u", wbpb->bpb.hidden_sectors); 2132 prthidden--; 2133 NEXT_DASH_O; 2134 } 2135 if (prtrsrvd) { 2136 (void) printf("reserve=%d", wbpb->bpb.resv_sectors); 2137 prtrsrvd--; 2138 NEXT_DASH_O; 2139 } 2140 } 2141 2142 (void) printf(" %s%c%c\n", actualdisk, 2143 suffix ? ':' : '\0', suffix ? *suffix : '\0'); 2144 } 2145 2146 /* 2147 * open_and_examine 2148 * 2149 * Open the requested 'dev_name'. Seek to point where 2150 * we'd expect to find boot sectors, etc., based on any ':partition' 2151 * attachments to the dev_name. 2152 * 2153 * Examine the fields of any existing boot sector and display best 2154 * approximation of how this fs could be reproduced with this command. 2155 */ 2156 static 2157 int 2158 open_and_examine(char *dn, bpb_t *wbpb) 2159 { 2160 struct stat di; 2161 off64_t ignored; 2162 char *actualdisk = NULL; 2163 char *suffix = NULL; 2164 int fd; 2165 2166 if (Verbose) 2167 (void) printf(gettext("Opening destination device/file.\n")); 2168 2169 actualdisk = stat_actual_disk(dn, &di, &suffix); 2170 2171 /* 2172 * Destination exists, now find more about it. 2173 */ 2174 if (!(S_ISCHR(di.st_mode))) { 2175 (void) fprintf(stderr, 2176 gettext("\n%s: device name must be a " 2177 "character special device.\n"), actualdisk); 2178 exit(2); 2179 } else if ((fd = open(actualdisk, O_RDWR | O_EXCL)) < 0) { 2180 perror(actualdisk); 2181 exit(2); 2182 } 2183 2184 /* 2185 * Find appropriate partition if we were requested to do so. 2186 */ 2187 if (suffix && !(seek_partn(fd, suffix, wbpb, &ignored))) { 2188 (void) close(fd); 2189 exit(2); 2190 } 2191 2192 read_existing_bpb(fd, wbpb); 2193 print_reproducing_command(fd, actualdisk, suffix, wbpb); 2194 2195 return (fd); 2196 } 2197 2198 /* 2199 * open_and_seek 2200 * 2201 * Open the requested 'dev_name'. Seek to point where 2202 * we'll write boot sectors, etc., based on any ':partition' 2203 * attachments to the dev_name. 2204 * 2205 * By the time we are finished here, the entire BPB will be 2206 * filled in, excepting the volume label. 2207 */ 2208 static 2209 int 2210 open_and_seek(char *dn, bpb_t *wbpb, off64_t *seekto) 2211 { 2212 struct fd_char fdchar; 2213 struct dk_geom dg; 2214 struct stat di; 2215 char *actualdisk = NULL; 2216 char *suffix = NULL; 2217 int fd; 2218 2219 if (Verbose) 2220 (void) printf(gettext("Opening destination device/file.\n")); 2221 2222 /* 2223 * We hold these truths to be self evident, all BPBs we create 2224 * will have these values in these fields. 2225 */ 2226 wbpb->bpb.num_fats = 2; 2227 wbpb->bpb.bytes_sector = BPSEC; 2228 2229 /* 2230 * Assign or use supplied numbers for hidden and 2231 * reserved sectors in the file system. 2232 */ 2233 if (GetResrvd) 2234 if (MakeFAT32) 2235 wbpb->bpb.resv_sectors = 32; 2236 else 2237 wbpb->bpb.resv_sectors = 1; 2238 else 2239 wbpb->bpb.resv_sectors = Resrvd; 2240 2241 wbpb->ebpb.ext_signature = 0x29; /* Magic number for modern format */ 2242 wbpb->ebpb.volume_id = 0; 2243 2244 if (MakeFAT32) 2245 fill_fat32_bpb(wbpb); 2246 2247 /* 2248 * If all output goes to a simple file, call a routine to setup 2249 * that scenario. Otherwise, try to find the device. 2250 */ 2251 if (Outputtofile) 2252 return (fd = prepare_image_file(dn, wbpb)); 2253 2254 actualdisk = stat_actual_disk(dn, &di, &suffix); 2255 2256 /* 2257 * Sanity check. If we've been provided a partition-specifying 2258 * suffix, we shouldn't also have been told to ignore the 2259 * fdisk table. 2260 */ 2261 if (DontUseFdisk && suffix) { 2262 (void) fprintf(stderr, 2263 gettext("Using 'nofdisk' option precludes " 2264 "appending logical drive\nspecifier " 2265 "to the device name.\n")); 2266 exit(2); 2267 } 2268 2269 /* 2270 * Destination exists, now find more about it. 2271 */ 2272 if (!(S_ISCHR(di.st_mode))) { 2273 (void) fprintf(stderr, 2274 gettext("\n%s: device name must indicate a " 2275 "character special device.\n"), actualdisk); 2276 exit(2); 2277 } else if ((fd = open(actualdisk, O_RDWR | O_EXCL)) < 0) { 2278 perror(actualdisk); 2279 exit(2); 2280 } 2281 2282 /* 2283 * Find appropriate partition if we were requested to do so. 2284 */ 2285 if (suffix && !(seek_partn(fd, suffix, wbpb, seekto))) { 2286 (void) close(fd); 2287 exit(2); 2288 } 2289 2290 if (!suffix) { 2291 /* 2292 * We have one of two possibilities. Chances are we have 2293 * a floppy drive. But the user may be trying to format 2294 * some weird drive that we don't know about and is supplying 2295 * all the important values. In that case, they should have set 2296 * the 'nofdisk' flag. 2297 * 2298 * If 'nofdisk' isn't set, do a floppy-specific ioctl to 2299 * get the remainder of our info. If the ioctl fails, we have 2300 * a good idea that they aren't really on a floppy. In that 2301 * case, they should have given us a partition specifier. 2302 */ 2303 if (DontUseFdisk) { 2304 if (!(seek_nofdisk(fd, wbpb, seekto))) { 2305 (void) close(fd); 2306 exit(2); 2307 } 2308 find_fixed_details(fd, wbpb); 2309 } else if (ioctl(fd, FDIOGCHAR, &fdchar) == -1) { 2310 /* 2311 * It is possible that we are trying to use floppy 2312 * specific FDIOGCHAR ioctl on USB floppy. Since sd 2313 * driver, by which USB floppy is handled, doesn't 2314 * support it, we can try to use disk DKIOCGGEOM ioctl 2315 * to retrieve data we need. sd driver itself 2316 * determines floppy disk by number of blocks 2317 * (<=0x1000), then it sets geometry to 80 cylinders, 2318 * 2 heads. 2319 * 2320 * Note that DKIOCGGEOM cannot supply us with type 2321 * of media (e.g. 3.5" or 5.25"). We will set it to 2322 * 3 (3.5") which is most probable value. 2323 */ 2324 if (errno == ENOTTY) { 2325 if (ioctl(fd, DKIOCGGEOM, &dg) != -1 && 2326 dg.dkg_ncyl == 80 && dg.dkg_nhead == 2) { 2327 fdchar.fdc_ncyl = dg.dkg_ncyl; 2328 fdchar.fdc_medium = 3; 2329 fdchar.fdc_secptrack = dg.dkg_nsect; 2330 fdchar.fdc_nhead = dg.dkg_nhead; 2331 lookup_floppy(&fdchar, wbpb); 2332 } else { 2333 partn_lecture(actualdisk); 2334 (void) close(fd); 2335 exit(2); 2336 } 2337 } 2338 } else { 2339 #ifdef sparc 2340 fdchar.fdc_medium = 3; 2341 #endif 2342 lookup_floppy(&fdchar, wbpb); 2343 } 2344 } else { 2345 find_fixed_details(fd, wbpb); 2346 } 2347 2348 return (fd); 2349 } 2350 2351 /* 2352 * The following is a copy of MS-DOS 4.0 boot block. 2353 * It consists of the BIOS parameter block, and a disk 2354 * bootstrap program. 2355 * 2356 * The BIOS parameter block contains the right values 2357 * for the 3.5" high-density 1.44MB floppy format. 2358 * 2359 * This will be our default boot sector, if the user 2360 * didn't point us at a different one. 2361 * 2362 */ 2363 static 2364 uchar_t DefBootSec[512] = { 2365 0xeb, 0x3c, 0x90, /* 8086 short jump + displacement + NOP */ 2366 'M', 'S', 'D', 'O', 'S', '4', '.', '0', /* OEM name & version */ 2367 0x00, 0x02, 0x01, 0x01, 0x00, 2368 0x02, 0xe0, 0x00, 0x40, 0x0b, 2369 0xf0, 0x09, 0x00, 0x12, 0x00, 2370 0x02, 0x00, 2371 0x00, 0x00, 0x00, 0x00, 2372 0x00, 0x00, 0x00, 0x00, 2373 0x00, 0x00, 2374 0x29, 0x00, 0x00, 0x00, 0x00, 2375 'N', 'O', 'N', 'A', 'M', 'E', ' ', ' ', ' ', ' ', ' ', 2376 'F', 'A', 'T', '1', '2', ' ', ' ', ' ', 2377 0xfa, 0x33, 2378 0xc0, 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0x16, 0x07, 2379 0xbb, 0x78, 0x00, 0x36, 0xc5, 0x37, 0x1e, 0x56, 2380 0x16, 0x53, 0xbf, 0x3e, 0x7c, 0xb9, 0x0b, 0x00, 2381 0xfc, 0xf3, 0xa4, 0x06, 0x1f, 0xc6, 0x45, 0xfe, 2382 0x0f, 0x8b, 0x0e, 0x18, 0x7c, 0x88, 0x4d, 0xf9, 2383 0x89, 0x47, 0x02, 0xc7, 0x07, 0x3e, 0x7c, 0xfb, 2384 0xcd, 0x13, 0x72, 0x7c, 0x33, 0xc0, 0x39, 0x06, 2385 0x13, 0x7c, 0x74, 0x08, 0x8b, 0x0e, 0x13, 0x7c, 2386 0x89, 0x0e, 0x20, 0x7c, 0xa0, 0x10, 0x7c, 0xf7, 2387 0x26, 0x16, 0x7c, 0x03, 0x06, 0x1c, 0x7c, 0x13, 2388 0x16, 0x1e, 0x7c, 0x03, 0x06, 0x0e, 0x7c, 0x83, 2389 0xd2, 0x00, 0xa3, 0x50, 0x7c, 0x89, 0x16, 0x52, 2390 0x7c, 0xa3, 0x49, 0x7c, 0x89, 0x16, 0x4b, 0x7c, 2391 0xb8, 0x20, 0x00, 0xf7, 0x26, 0x11, 0x7c, 0x8b, 2392 0x1e, 0x0b, 0x7c, 0x03, 0xc3, 0x48, 0xf7, 0xf3, 2393 0x01, 0x06, 0x49, 0x7c, 0x83, 0x16, 0x4b, 0x7c, 2394 0x00, 0xbb, 0x00, 0x05, 0x8b, 0x16, 0x52, 0x7c, 2395 0xa1, 0x50, 0x7c, 0xe8, 0x87, 0x00, 0x72, 0x20, 2396 0xb0, 0x01, 0xe8, 0xa1, 0x00, 0x72, 0x19, 0x8b, 2397 0xfb, 0xb9, 0x0b, 0x00, 0xbe, 0xdb, 0x7d, 0xf3, 2398 0xa6, 0x75, 0x0d, 0x8d, 0x7f, 0x20, 0xbe, 0xe6, 2399 0x7d, 0xb9, 0x0b, 0x00, 0xf3, 0xa6, 0x74, 0x18, 2400 0xbe, 0x93, 0x7d, 0xe8, 0x51, 0x00, 0x32, 0xe4, 2401 0xcd, 0x16, 0x5e, 0x1f, 0x8f, 0x04, 0x8f, 0x44, 2402 0x02, 0xcd, 0x19, 0x58, 0x58, 0x58, 0xeb, 0xe8, 2403 0xbb, 0x00, 0x07, 0xb9, 0x03, 0x00, 0xa1, 0x49, 2404 0x7c, 0x8b, 0x16, 0x4b, 0x7c, 0x50, 0x52, 0x51, 2405 0xe8, 0x3a, 0x00, 0x72, 0xe6, 0xb0, 0x01, 0xe8, 2406 0x54, 0x00, 0x59, 0x5a, 0x58, 0x72, 0xc9, 0x05, 2407 0x01, 0x00, 0x83, 0xd2, 0x00, 0x03, 0x1e, 0x0b, 2408 0x7c, 0xe2, 0xe2, 0x8a, 0x2e, 0x15, 0x7c, 0x8a, 2409 0x16, 0x24, 0x7c, 0x8b, 0x1e, 0x49, 0x7c, 0xa1, 2410 0x4b, 0x7c, 0xea, 0x00, 0x00, 0x70, 0x00, 0xac, 2411 0x0a, 0xc0, 0x74, 0x29, 0xb4, 0x0e, 0xbb, 0x07, 2412 0x00, 0xcd, 0x10, 0xeb, 0xf2, 0x3b, 0x16, 0x18, 2413 0x7c, 0x73, 0x19, 0xf7, 0x36, 0x18, 0x7c, 0xfe, 2414 0xc2, 0x88, 0x16, 0x4f, 0x7c, 0x33, 0xd2, 0xf7, 2415 0x36, 0x1a, 0x7c, 0x88, 0x16, 0x25, 0x7c, 0xa3, 2416 0x4d, 0x7c, 0xf8, 0xc3, 0xf9, 0xc3, 0xb4, 0x02, 2417 0x8b, 0x16, 0x4d, 0x7c, 0xb1, 0x06, 0xd2, 0xe6, 2418 0x0a, 0x36, 0x4f, 0x7c, 0x8b, 0xca, 0x86, 0xe9, 2419 0x8a, 0x16, 0x24, 0x7c, 0x8a, 0x36, 0x25, 0x7c, 2420 0xcd, 0x13, 0xc3, 0x0d, 0x0a, 0x4e, 0x6f, 0x6e, 2421 0x2d, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, 2422 0x64, 0x69, 0x73, 0x6b, 0x20, 0x6f, 0x72, 0x20, 2423 0x64, 0x69, 0x73, 0x6b, 0x20, 0x65, 0x72, 0x72, 2424 0x6f, 0x72, 0x0d, 0x0a, 0x52, 0x65, 0x70, 0x6c, 2425 0x61, 0x63, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 2426 0x70, 0x72, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6e, 2427 0x79, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x77, 0x68, 2428 0x65, 0x6e, 0x20, 0x72, 0x65, 0x61, 0x64, 0x79, 2429 0x0d, 0x0a, 0x00, 0x49, 0x4f, 0x20, 0x20, 0x20, 2430 0x20, 0x20, 0x20, 0x53, 0x59, 0x53, 0x4d, 0x53, 2431 0x44, 0x4f, 0x53, 0x20, 0x20, 0x20, 0x53, 0x59, 2432 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 2433 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa 2434 }; 2435 2436 /* 2437 * verify_bootblkfile 2438 * 2439 * We were provided with the name of a file containing the bootblk 2440 * to install. Verify it has a valid boot sector as best we can. Any 2441 * errors and we return a bad file descriptor. Otherwise we fill up the 2442 * provided buffer with the boot sector, return the file 2443 * descriptor for later use and leave the file pointer just 2444 * past the boot sector part of the boot block file. 2445 */ 2446 static 2447 int 2448 verify_bootblkfile(char *fn, boot_sector_t *bs, ulong_t *blkfilesize) 2449 { 2450 struct stat fi; 2451 int bsfd = -1; 2452 2453 if (stat(fn, &fi)) { 2454 perror(fn); 2455 } else if (fi.st_size < BPSEC) { 2456 (void) fprintf(stderr, 2457 gettext("%s: Too short to be a boot sector.\n"), fn); 2458 } else if ((bsfd = open(fn, O_RDONLY)) < 0) { 2459 perror(fn); 2460 } else if (read(bsfd, bs->buf, BPSEC) < BPSEC) { 2461 (void) close(bsfd); 2462 bsfd = -1; 2463 perror(gettext("Boot block read")); 2464 } else { 2465 #ifdef i386 2466 if ((bs->bs.bs_front.bs_jump_code[0] != OPCODE1 && 2467 bs->bs.bs_front.bs_jump_code[0] != OPCODE2) || 2468 #else 2469 if ((bs->bs.bs_jump_code[0] != OPCODE1 && 2470 bs->bs.bs_jump_code[0] != OPCODE2) || 2471 #endif 2472 (bs->bs.bs_signature[0] != (BOOTSECSIG & 0xFF) && 2473 bs->bs.bs_signature[1] != ((BOOTSECSIG >> 8) & 0xFF))) { 2474 (void) close(bsfd); 2475 bsfd = -1; 2476 (void) fprintf(stderr, 2477 gettext("Boot block (%s) bogus.\n"), fn); 2478 } 2479 *blkfilesize = fi.st_size; 2480 } 2481 return (bsfd); 2482 } 2483 2484 /* 2485 * verify_firstfile 2486 * 2487 * We were provided with the name of a file to be the first file 2488 * installed on the disk. We just need to verify it exists and 2489 * find out how big it is. If it doesn't exist, we print a warning 2490 * message about how the file wasn't found. We don't exit fatally, 2491 * though, rather we return a size of 0 and the FAT will be built 2492 * without installing any first file. They can then presumably 2493 * install the correct first file by hand. 2494 */ 2495 static 2496 int 2497 verify_firstfile(char *fn, ulong_t *filesize) 2498 { 2499 struct stat fi; 2500 int fd = -1; 2501 2502 *filesize = 0; 2503 if (stat(fn, &fi) || (fd = open(fn, O_RDONLY)) < 0) { 2504 perror(fn); 2505 (void) fprintf(stderr, 2506 gettext("Could not access requested file. It will not\n" 2507 "be installed in the new file system.\n")); 2508 } else { 2509 *filesize = fi.st_size; 2510 } 2511 2512 return (fd); 2513 } 2514 2515 /* 2516 * label_volume 2517 * 2518 * Fill in BPB with volume label. 2519 */ 2520 static 2521 void 2522 label_volume(char *lbl, bpb_t *wbpb) 2523 { 2524 int ll, i; 2525 2526 /* Put a volume label into our BPB. */ 2527 if (!lbl) 2528 lbl = DEFAULT_LABEL; 2529 2530 ll = min(11, (int)strlen(lbl)); 2531 for (i = 0; i < ll; i++) { 2532 wbpb->ebpb.volume_label[i] = toupper(lbl[i]); 2533 } 2534 for (; i < 11; i++) { 2535 wbpb->ebpb.volume_label[i] = ' '; 2536 } 2537 } 2538 2539 static 2540 int 2541 copy_bootblk(char *fn, boot_sector_t *bootsect, ulong_t *bootblksize) 2542 { 2543 int bsfd = -1; 2544 2545 if (Verbose && fn) 2546 (void) printf(gettext("Request to install boot " 2547 "block file %s.\n"), fn); 2548 else if (Verbose) 2549 (void) printf(gettext("Request to install DOS boot block.\n")); 2550 2551 /* 2552 * If they want to install their own boot block, sanity check 2553 * that block. 2554 */ 2555 if (fn) { 2556 bsfd = verify_bootblkfile(fn, bootsect, bootblksize); 2557 if (bsfd < 0) { 2558 exit(3); 2559 } 2560 *bootblksize = roundup(*bootblksize, BPSEC); 2561 } else { 2562 (void) memcpy(bootsect, DefBootSec, BPSEC); 2563 *bootblksize = BPSEC; 2564 } 2565 2566 return (bsfd); 2567 } 2568 2569 /* 2570 * mark_cluster 2571 * 2572 * This routine fills a FAT entry with the value supplied to it as an 2573 * argument. The fatp argument is assumed to be a pointer to the FAT's 2574 * 0th entry. The clustnum is the cluster entry that should be updated. 2575 * The value is the new value for the entry. 2576 */ 2577 static 2578 void 2579 mark_cluster(uchar_t *fatp, pc_cluster32_t clustnum, uint32_t value) 2580 { 2581 uchar_t *ep; 2582 ulong_t idx; 2583 2584 idx = (Fatentsize == 32) ? clustnum * 4 : 2585 (Fatentsize == 16) ? clustnum * 2 : clustnum + clustnum/2; 2586 ep = fatp + idx; 2587 2588 if (Fatentsize == 32) { 2589 store_32_bits(&ep, value); 2590 } else if (Fatentsize == 16) { 2591 store_16_bits(&ep, value); 2592 } else { 2593 if (clustnum & 1) { 2594 *ep = (*ep & 0x0f) | ((value << 4) & 0xf0); 2595 ep++; 2596 *ep = (value >> 4) & 0xff; 2597 } else { 2598 *ep++ = value & 0xff; 2599 *ep = (*ep & 0xf0) | ((value >> 8) & 0x0f); 2600 } 2601 } 2602 } 2603 2604 static 2605 uchar_t * 2606 build_fat(bpb_t *wbpb, struct fat32_boot_fsinfo *fsinfop, ulong_t bootblksize, 2607 ulong_t *fatsize, char *ffn, int *fffd, ulong_t *ffsize, 2608 pc_cluster32_t *ffstartclust) 2609 { 2610 pc_cluster32_t nextfree, ci; 2611 uchar_t *fatp; 2612 ushort_t numclust, numsect; 2613 int remclust; 2614 2615 /* Alloc space for a FAT and then null it out. */ 2616 if (Verbose) { 2617 (void) printf(gettext("BUILD FAT.\n%d sectors per fat.\n"), 2618 wbpb->bpb.sectors_per_fat ? wbpb->bpb.sectors_per_fat : 2619 wbpb->bpb32.big_sectors_per_fat); 2620 } 2621 2622 if (MakeFAT32) { 2623 *fatsize = BPSEC * wbpb->bpb32.big_sectors_per_fat; 2624 } else { 2625 *fatsize = BPSEC * wbpb->bpb.sectors_per_fat; 2626 } 2627 2628 if (!(fatp = (uchar_t *)malloc(*fatsize))) { 2629 perror(gettext("FAT table alloc")); 2630 exit(4); 2631 } else { 2632 (void) memset(fatp, 0, *fatsize); 2633 } 2634 2635 /* Build in-memory FAT */ 2636 *fatp = wbpb->bpb.media; 2637 *(fatp + 1) = 0xFF; 2638 *(fatp + 2) = 0xFF; 2639 2640 if (Fatentsize == 16) { 2641 *(fatp + 3) = 0xFF; 2642 } else if (Fatentsize == 32) { 2643 *(fatp + 3) = 0x0F; 2644 *(fatp + 4) = 0xFF; 2645 *(fatp + 5) = 0xFF; 2646 *(fatp + 6) = 0xFF; 2647 *(fatp + 7) = 0x0F; 2648 } 2649 2650 /* 2651 * Keep track of clusters used. 2652 */ 2653 remclust = TotalClusters; 2654 nextfree = 2; 2655 2656 /* 2657 * Get info on first file to install, if any. 2658 */ 2659 if (ffn) 2660 *fffd = verify_firstfile(ffn, ffsize); 2661 2662 /* 2663 * Compute number of clusters to preserve for bootblk overage. 2664 * Remember that we already wrote the first sector of the boot block. 2665 * These clusters are marked BAD to prevent them from being deleted 2666 * or used. The first available cluster is 2, so we always offset 2667 * the clusters. 2668 */ 2669 numsect = idivceil((bootblksize - BPSEC), BPSEC); 2670 numclust = idivceil(numsect, wbpb->bpb.sectors_per_cluster); 2671 2672 if (Verbose && numclust) 2673 (void) printf(gettext("Hiding %d excess bootblk cluster(s).\n"), 2674 numclust); 2675 for (ci = 0; ci < numclust; ci++) 2676 mark_cluster(fatp, nextfree++, 2677 MakeFAT32 ? PCF_BADCLUSTER32 : PCF_BADCLUSTER); 2678 remclust -= numclust; 2679 2680 /* 2681 * Reserve a cluster for the root directory on a FAT32. 2682 */ 2683 if (MakeFAT32) { 2684 mark_cluster(fatp, nextfree, PCF_LASTCLUSTER32); 2685 wbpb->bpb32.root_dir_clust = nextfree++; 2686 remclust--; 2687 } 2688 2689 /* 2690 * Compute and preserve number of clusters for first file. 2691 */ 2692 if (*fffd >= 0) { 2693 *ffstartclust = nextfree; 2694 numsect = idivceil(*ffsize, BPSEC); 2695 numclust = idivceil(numsect, wbpb->bpb.sectors_per_cluster); 2696 2697 if (numclust > remclust) { 2698 (void) fprintf(stderr, 2699 gettext("Requested first file too large to be\n" 2700 "installed in the new file system.\n")); 2701 (void) close(*fffd); 2702 *fffd = -1; 2703 goto finish; 2704 } 2705 2706 if (Verbose) 2707 (void) printf(gettext("Reserving %d first file " 2708 "cluster(s).\n"), numclust); 2709 for (ci = 0; (int)ci < (int)(numclust-1); ci++, nextfree++) 2710 mark_cluster(fatp, nextfree, nextfree + 1); 2711 mark_cluster(fatp, nextfree++, 2712 MakeFAT32 ? PCF_LASTCLUSTER32 : PCF_LASTCLUSTER); 2713 remclust -= numclust; 2714 } 2715 2716 finish: 2717 if (Verbose) { 2718 (void) printf(gettext("First sector of FAT")); 2719 header_for_dump(); 2720 dump_bytes(fatp, BPSEC); 2721 } 2722 2723 fsinfop->fs_signature = FAT32_FS_SIGN; 2724 fsinfop->fs_free_clusters = remclust; 2725 fsinfop->fs_next_cluster = nextfree; 2726 return (fatp); 2727 } 2728 2729 static 2730 void 2731 dirent_time_fill(struct pcdir *dep) 2732 { 2733 struct timeval tv; 2734 struct tm *tp; 2735 ushort_t dostime; 2736 ushort_t dosday; 2737 2738 (void) gettimeofday(&tv, (struct timezone *)0); 2739 tp = localtime(&tv.tv_sec); 2740 /* get the time & day into DOS format */ 2741 dostime = tp->tm_sec / 2; 2742 dostime |= tp->tm_min << 5; 2743 dostime |= tp->tm_hour << 11; 2744 dosday = tp->tm_mday; 2745 dosday |= (tp->tm_mon + 1) << 5; 2746 dosday |= (tp->tm_year - 80) << 9; 2747 dep->pcd_mtime.pct_time = htols(dostime); 2748 dep->pcd_mtime.pct_date = htols(dosday); 2749 } 2750 2751 static 2752 void 2753 dirent_label_fill(struct pcdir *dep, char *fn) 2754 { 2755 int nl, i; 2756 2757 /* 2758 * We spread the volume label across both the NAME and EXT fields 2759 */ 2760 nl = min(PCFNAMESIZE, strlen(fn)); 2761 for (i = 0; i < nl; i++) { 2762 dep->pcd_filename[i] = toupper(fn[i]); 2763 } 2764 if (i < PCFNAMESIZE) { 2765 for (; i < PCFNAMESIZE; i++) 2766 dep->pcd_filename[i] = ' '; 2767 for (i = 0; i < PCFEXTSIZE; i++) 2768 dep->pcd_ext[i] = ' '; 2769 return; 2770 } 2771 nl = min(PCFEXTSIZE, strlen(fn) - PCFNAMESIZE); 2772 for (i = 0; i < nl; i++) 2773 dep->pcd_ext[i] = toupper(fn[i + PCFNAMESIZE]); 2774 if (i < PCFEXTSIZE) { 2775 for (; i < PCFEXTSIZE; i++) 2776 dep->pcd_ext[i] = ' '; 2777 } 2778 } 2779 2780 static 2781 void 2782 dirent_fname_fill(struct pcdir *dep, char *fn) 2783 { 2784 char *fname, *fext; 2785 int nl, i; 2786 2787 if (fname = strrchr(fn, '/')) { 2788 fname++; 2789 } else { 2790 fname = fn; 2791 } 2792 2793 if (fext = strrchr(fname, '.')) { 2794 fext++; 2795 } else { 2796 fext = ""; 2797 } 2798 2799 fname = strtok(fname, "."); 2800 2801 nl = min(PCFNAMESIZE, (int)strlen(fname)); 2802 for (i = 0; i < nl; i++) { 2803 dep->pcd_filename[i] = toupper(fname[i]); 2804 } 2805 for (; i < PCFNAMESIZE; i++) { 2806 dep->pcd_filename[i] = ' '; 2807 } 2808 2809 nl = min(PCFEXTSIZE, (int)strlen(fext)); 2810 for (i = 0; i < nl; i++) { 2811 dep->pcd_ext[i] = toupper(fext[i]); 2812 } 2813 for (; i < PCFEXTSIZE; i++) { 2814 dep->pcd_ext[i] = ' '; 2815 } 2816 } 2817 2818 static 2819 uchar_t * 2820 build_rootdir(bpb_t *wbpb, char *ffn, int fffd, 2821 ulong_t ffsize, pc_cluster32_t ffstart, ulong_t *rdirsize) 2822 { 2823 struct pcdir *rootdirp; 2824 struct pcdir *entry; 2825 2826 /* 2827 * Build a root directory. It will have at least one entry, 2828 * the volume label and a second if the first file was defined. 2829 */ 2830 if (MakeFAT32) { 2831 /* 2832 * We devote an entire cluster to the root 2833 * directory on FAT32. 2834 */ 2835 *rdirsize = wbpb->bpb.sectors_per_cluster * BPSEC; 2836 } else { 2837 *rdirsize = wbpb->bpb.num_root_entries * sizeof (struct pcdir); 2838 } 2839 if ((rootdirp = (struct pcdir *)malloc(*rdirsize)) == NULL) { 2840 perror(gettext("Root directory allocation")); 2841 exit(4); 2842 } else { 2843 entry = rootdirp; 2844 (void) memset((char *)rootdirp, 0, *rdirsize); 2845 } 2846 2847 /* Create directory entry for first file, if there is one */ 2848 if (fffd >= 0) { 2849 dirent_fname_fill(entry, ffn); 2850 entry->pcd_attr = Firstfileattr; 2851 dirent_time_fill(entry); 2852 entry->pcd_scluster_lo = htols(ffstart); 2853 if (MakeFAT32) { 2854 ffstart = ffstart >> 16; 2855 entry->un.pcd_scluster_hi = htols(ffstart); 2856 } 2857 entry->pcd_size = htoli(ffsize); 2858 entry++; 2859 } 2860 2861 /* Create directory entry for volume label, if there is one */ 2862 if (Label != NULL) { 2863 dirent_label_fill(entry, Label); 2864 entry->pcd_attr = PCA_ARCH | PCA_LABEL; 2865 dirent_time_fill(entry); 2866 entry->pcd_scluster_lo = 0; 2867 if (MakeFAT32) { 2868 entry->un.pcd_scluster_hi = 0; 2869 } 2870 entry->pcd_size = 0; 2871 entry++; 2872 } 2873 2874 if (Verbose) { 2875 (void) printf(gettext("First two directory entries")); 2876 header_for_dump(); 2877 dump_bytes((uchar_t *)rootdirp, 2 * sizeof (struct pcdir)); 2878 } 2879 2880 return ((uchar_t *)rootdirp); 2881 } 2882 2883 /* 2884 * write_rest 2885 * 2886 * Write all the bytes from the current file pointer to end of file 2887 * in the source file out to the destination file. The writes should 2888 * be padded to whole clusters with 0's if necessary. 2889 */ 2890 static 2891 void 2892 write_rest(bpb_t *wbpb, char *efn, int dfd, int sfd, int remaining) 2893 { 2894 char buf[BPSEC]; 2895 ushort_t numsect, numclust; 2896 ushort_t wnumsect, s; 2897 int doneread = 0; 2898 int rstat; 2899 2900 /* 2901 * Compute number of clusters required to contain remaining bytes. 2902 */ 2903 numsect = idivceil(remaining, BPSEC); 2904 numclust = idivceil(numsect, wbpb->bpb.sectors_per_cluster); 2905 2906 wnumsect = numclust * wbpb->bpb.sectors_per_cluster; 2907 for (s = 0; s < wnumsect; s++) { 2908 if (!doneread) { 2909 if ((rstat = read(sfd, buf, BPSEC)) < 0) { 2910 perror(efn); 2911 doneread = 1; 2912 rstat = 0; 2913 } else if (rstat == 0) { 2914 doneread = 1; 2915 } 2916 (void) memset(&(buf[rstat]), 0, BPSEC - rstat); 2917 } 2918 if (write(dfd, buf, BPSEC) != BPSEC) { 2919 (void) fprintf(stderr, gettext("Copying ")); 2920 perror(efn); 2921 } 2922 } 2923 } 2924 2925 static 2926 void 2927 write_fat32_bootstuff(int fd, boot_sector_t *bsp, 2928 struct fat32_boot_fsinfo *fsinfop, off64_t seekto) 2929 { 2930 uchar_t fsinfobuf[BPSEC]; 2931 uchar_t *fp; 2932 2933 /* 2934 * Construct the fsinfo buf 2935 */ 2936 (void) memset(fsinfobuf, 0, BPSEC); 2937 /* 2938 * Not sure if this magic signature at the beginning of the 2939 * sector is necessary for us to create or not. For now, I'm 2940 * going to assume it is, since I haven't seen any Windows FAT32s 2941 * without it. 2942 */ 2943 fsinfobuf[0] = 'R'; 2944 fsinfobuf[1] = 'R'; 2945 fsinfobuf[2] = 'a'; 2946 fsinfobuf[3] = 'A'; 2947 /* 2948 * We also appear to want the magic Boot sector signature at the 2949 * end of the sector. 2950 */ 2951 fsinfobuf[BPSEC - 2] = BOOTSECSIG & 0xFF; 2952 fsinfobuf[BPSEC - 1] = (BOOTSECSIG >> 8) & 0xFF; 2953 2954 fp = &(fsinfobuf[FAT32_BOOT_FSINFO_OFF]); 2955 fp += 4; /* skip first reserved field */ 2956 store_32_bits(&fp, fsinfop->fs_signature); 2957 store_32_bits(&fp, fsinfop->fs_free_clusters); 2958 store_32_bits(&fp, fsinfop->fs_next_cluster); 2959 2960 if (Verbose) { 2961 (void) printf(gettext("Dump of the fs info sector")); 2962 header_for_dump(); 2963 dump_bytes(fsinfobuf, sizeof (fsinfobuf)); 2964 } 2965 2966 if (!Notreally) { 2967 /* 2968 * FAT32's have an FS info sector, then a backup of the boot 2969 * sector, and a modified backup of the FS Info sector. 2970 */ 2971 if (write(fd, fsinfobuf, sizeof (fsinfobuf)) != BPSEC) { 2972 perror(gettext("FS info sector write")); 2973 exit(4); 2974 } 2975 if (lseek64(fd, seekto + BKUP_BOOTSECT_OFFSET, SEEK_SET) < 0) { 2976 (void) close(fd); 2977 perror(gettext("Boot sector backup seek")); 2978 exit(4); 2979 } 2980 if (write(fd, bsp->buf, sizeof (bsp->buf)) != BPSEC) { 2981 perror(gettext("Boot sector backup write")); 2982 exit(4); 2983 } 2984 } 2985 2986 /* 2987 * Second copy of fs info sector is modified to have "don't know" 2988 * as the number of free clusters 2989 */ 2990 fp = &(fsinfobuf[FAT32_BOOT_FSINFO_OFF]); 2991 fp += 8; /* skip first reserved field and signature */ 2992 store_32_bits(&fp, -1); 2993 2994 if (Verbose) { 2995 (void) printf(gettext("Dump of the backup fs info sector")); 2996 header_for_dump(); 2997 dump_bytes(fsinfobuf, sizeof (fsinfobuf)); 2998 } 2999 3000 if (!Notreally) { 3001 if (write(fd, fsinfobuf, sizeof (fsinfobuf)) != BPSEC) { 3002 perror(gettext("FS info sector backup write")); 3003 exit(4); 3004 } 3005 } 3006 } 3007 3008 static 3009 void 3010 write_bootsects(int fd, boot_sector_t *bsp, bpb_t *wbpb, 3011 struct fat32_boot_fsinfo *fsinfop, off64_t seekto) 3012 { 3013 if (MakeFAT32) { 3014 /* Copy our BPB into bootsec structure */ 3015 #ifdef i386 3016 (void) memcpy(&(bsp->bs32.bs_front.bs_bpb), &(wbpb->bpb), 3017 sizeof (wbpb->bpb)); 3018 (void) memcpy(&(bsp->bs32.bs_bpb32), &(wbpb->bpb32), 3019 sizeof (wbpb->bpb32)); 3020 (void) memcpy(&(bsp->bs32.bs_ebpb), &(wbpb->ebpb), 3021 sizeof (wbpb->ebpb)); 3022 #else 3023 swap_pack_bpb32cpy(&(bsp->bs32), wbpb); 3024 #endif 3025 } else { 3026 /* Copy our BPB into bootsec structure */ 3027 #ifdef i386 3028 (void) memcpy(&(bsp->bs.bs_front.bs_bpb), &(wbpb->bpb), 3029 sizeof (wbpb->bpb)); 3030 (void) memcpy(&(bsp->bs.bs_ebpb), &(wbpb->ebpb), 3031 sizeof (wbpb->ebpb)); 3032 #else 3033 swap_pack_bpbcpy(&(bsp->bs), wbpb); 3034 #endif 3035 3036 /* Copy SUN BPB extensions into bootsec structure */ 3037 if (SunBPBfields) { 3038 #ifdef i386 3039 (void) memcpy(&(bsp->bs.bs_sebpb), &(wbpb->sunbpb), 3040 sizeof (wbpb->sunbpb)); 3041 #else 3042 swap_pack_sebpbcpy(&(bsp->bs), wbpb); 3043 #endif 3044 } 3045 } 3046 3047 /* Write boot sector */ 3048 if (!Notreally && write(fd, bsp->buf, sizeof (bsp->buf)) != BPSEC) { 3049 perror(gettext("Boot sector write")); 3050 exit(4); 3051 } 3052 3053 if (Verbose) { 3054 (void) printf(gettext("Dump of the boot sector")); 3055 header_for_dump(); 3056 dump_bytes(bsp->buf, sizeof (bsp->buf)); 3057 } 3058 3059 if (MakeFAT32) 3060 write_fat32_bootstuff(fd, bsp, fsinfop, seekto); 3061 } 3062 3063 static 3064 void 3065 write_fat(int fd, off64_t seekto, char *fn, char *lbl, char *ffn, bpb_t *wbpb) 3066 { 3067 struct fat32_boot_fsinfo fsinfo; 3068 pc_cluster32_t ffsc; 3069 boot_sector_t bootsect; 3070 uchar_t *fatp, *rdirp; 3071 ulong_t bootblksize, fatsize, rdirsize, ffsize; 3072 int bsfd = -1; 3073 int fffd = -1; 3074 3075 compute_file_area_size(wbpb); 3076 3077 bsfd = copy_bootblk(fn, &bootsect, &bootblksize); 3078 label_volume(lbl, wbpb); 3079 3080 if (Verbose) 3081 (void) printf(gettext("Building FAT.\n")); 3082 fatp = build_fat(wbpb, &fsinfo, bootblksize, &fatsize, 3083 ffn, &fffd, &ffsize, &ffsc); 3084 3085 write_bootsects(fd, &bootsect, wbpb, &fsinfo, seekto); 3086 3087 if (lseek64(fd, 3088 seekto + (BPSEC * wbpb->bpb.resv_sectors), SEEK_SET) < 0) { 3089 (void) close(fd); 3090 perror(gettext("Seek to end of reserved sectors")); 3091 exit(4); 3092 } 3093 3094 /* Write FAT */ 3095 if (Verbose) 3096 (void) printf(gettext("Writing FAT(s). %d bytes times %d.\n"), 3097 fatsize, wbpb->bpb.num_fats); 3098 if (!Notreally) { 3099 int nf, wb; 3100 for (nf = 0; nf < (int)wbpb->bpb.num_fats; nf++) 3101 if ((wb = write(fd, fatp, fatsize)) != fatsize) { 3102 perror(gettext("FAT write")); 3103 exit(4); 3104 } else { 3105 if (Verbose) 3106 (void) printf( 3107 gettext("Wrote %d bytes\n"), wb); 3108 } 3109 } 3110 free(fatp); 3111 3112 if (Verbose) 3113 (void) printf(gettext("Building root directory.\n")); 3114 rdirp = build_rootdir(wbpb, ffn, fffd, ffsize, ffsc, &rdirsize); 3115 3116 /* 3117 * In non FAT32, root directory exists outside of the file area 3118 */ 3119 if (!MakeFAT32) { 3120 if (Verbose) 3121 (void) printf( 3122 gettext("Writing root directory. " 3123 "%d bytes.\n"), rdirsize); 3124 if (!Notreally) { 3125 if (write(fd, rdirp, rdirsize) != rdirsize) { 3126 perror(gettext("Root directory write")); 3127 exit(4); 3128 } 3129 } 3130 free(rdirp); 3131 } 3132 3133 /* 3134 * Now write anything that needs to be in the file space. 3135 */ 3136 if (bootblksize > BPSEC) { 3137 if (Verbose) 3138 (void) printf(gettext("Writing remainder of " 3139 "boot block.\n")); 3140 if (!Notreally) 3141 write_rest(wbpb, fn, fd, bsfd, bootblksize - BPSEC); 3142 } 3143 3144 if (MakeFAT32) { 3145 if (Verbose) 3146 (void) printf( 3147 gettext("Writing root directory. " 3148 "%d bytes.\n"), rdirsize); 3149 if (!Notreally) { 3150 if (write(fd, rdirp, rdirsize) != rdirsize) { 3151 perror(gettext("Root directory write")); 3152 exit(4); 3153 } 3154 } 3155 free(rdirp); 3156 } 3157 3158 if (fffd >= 0) { 3159 if (Verbose) 3160 (void) printf(gettext("Writing first file.\n")); 3161 if (!Notreally) 3162 write_rest(wbpb, ffn, fd, fffd, ffsize); 3163 } 3164 } 3165 3166 static 3167 char *LegalOpts[] = { 3168 #define NFLAG 0 3169 "N", 3170 #define VFLAG 1 3171 "v", 3172 #define RFLAG 2 3173 "r", 3174 #define HFLAG 3 3175 "h", 3176 #define SFLAG 4 3177 "s", 3178 #define SUNFLAG 5 3179 "S", 3180 #define LABFLAG 6 3181 "b", 3182 #define BTRFLAG 7 3183 "B", 3184 #define INITFLAG 8 3185 "i", 3186 #define SZFLAG 9 3187 "size", 3188 #define SECTFLAG 10 3189 "nsect", 3190 #define TRKFLAG 11 3191 "ntrack", 3192 #define SPCFLAG 12 3193 "spc", 3194 #define BPFFLAG 13 3195 "fat", 3196 #define FFLAG 14 3197 "f", 3198 #define DFLAG 15 3199 "d", 3200 #define NOFDISKFLAG 16 3201 "nofdisk", 3202 #define RESRVFLAG 17 3203 "reserve", 3204 #define HIDDENFLAG 18 3205 "hidden", 3206 NULL 3207 }; 3208 3209 static 3210 void 3211 bad_arg(char *option) 3212 { 3213 (void) fprintf(stderr, 3214 gettext("Unrecognized option %s.\n"), option); 3215 usage(); 3216 exit(2); 3217 } 3218 3219 static 3220 void 3221 missing_arg(char *option) 3222 { 3223 (void) fprintf(stderr, 3224 gettext("Option %s requires a value.\n"), option); 3225 usage(); 3226 exit(3); 3227 } 3228 3229 static 3230 void 3231 parse_suboptions(char *optsstr) 3232 { 3233 char *value; 3234 int c; 3235 3236 while (*optsstr != '\0') { 3237 switch (c = getsubopt(&optsstr, LegalOpts, &value)) { 3238 case NFLAG: 3239 Notreally++; 3240 break; 3241 case VFLAG: 3242 Verbose++; 3243 break; 3244 case RFLAG: 3245 Firstfileattr |= 0x01; 3246 break; 3247 case HFLAG: 3248 Firstfileattr |= 0x02; 3249 break; 3250 case SFLAG: 3251 Firstfileattr |= 0x04; 3252 break; 3253 case SUNFLAG: 3254 SunBPBfields = 1; 3255 break; 3256 case LABFLAG: 3257 if (value == NULL) { 3258 missing_arg(LegalOpts[c]); 3259 } else { 3260 Label = value; 3261 } 3262 break; 3263 case BTRFLAG: 3264 if (value == NULL) { 3265 missing_arg(LegalOpts[c]); 3266 } else { 3267 BootBlkFn = value; 3268 } 3269 break; 3270 case INITFLAG: 3271 if (value == NULL) { 3272 missing_arg(LegalOpts[c]); 3273 } else { 3274 FirstFn = value; 3275 } 3276 break; 3277 case SZFLAG: 3278 if (value == NULL) { 3279 missing_arg(LegalOpts[c]); 3280 } else { 3281 TotSize = atoi(value); 3282 GetSize = 0; 3283 } 3284 break; 3285 case SECTFLAG: 3286 if (value == NULL) { 3287 missing_arg(LegalOpts[c]); 3288 } else { 3289 SecPerTrk = atoi(value); 3290 GetSPT = 0; 3291 } 3292 break; 3293 case TRKFLAG: 3294 if (value == NULL) { 3295 missing_arg(LegalOpts[c]); 3296 } else { 3297 TrkPerCyl = atoi(value); 3298 GetTPC = 0; 3299 } 3300 break; 3301 case SPCFLAG: 3302 if (value == NULL) { 3303 missing_arg(LegalOpts[c]); 3304 } else { 3305 SecPerClust = atoi(value); 3306 GetSPC = 0; 3307 } 3308 break; 3309 case BPFFLAG: 3310 if (value == NULL) { 3311 missing_arg(LegalOpts[c]); 3312 } else { 3313 BitsPerFAT = atoi(value); 3314 GetBPF = 0; 3315 } 3316 break; 3317 case NOFDISKFLAG: 3318 DontUseFdisk = 1; 3319 break; 3320 case RESRVFLAG: 3321 if (value == NULL) { 3322 missing_arg(LegalOpts[c]); 3323 } else { 3324 Resrvd = atoi(value); 3325 GetResrvd = 0; 3326 } 3327 break; 3328 case HIDDENFLAG: 3329 if (value == NULL) { 3330 missing_arg(LegalOpts[c]); 3331 } else { 3332 RelOffset = atoi(value); 3333 GetOffset = 0; 3334 } 3335 break; 3336 case FFLAG: 3337 if (value == NULL) { 3338 missing_arg(LegalOpts[c]); 3339 } else { 3340 DiskName = value; 3341 Outputtofile = 1; 3342 } 3343 break; 3344 case DFLAG: 3345 if (value == NULL) { 3346 missing_arg(LegalOpts[c]); 3347 } else { 3348 Imagesize = atoi(value); 3349 } 3350 break; 3351 default: 3352 bad_arg(value); 3353 break; 3354 } 3355 } 3356 } 3357 3358 static 3359 void 3360 sanity_check_options(int argc, int optind) 3361 { 3362 if (GetFsParams) { 3363 if (argc - optind != 1) 3364 usage(); 3365 return; 3366 } 3367 3368 if (DontUseFdisk && GetOffset) { 3369 /* Set default relative offset of zero */ 3370 RelOffset = 0; 3371 } 3372 3373 if (BitsPerFAT == 32) 3374 MakeFAT32 = 1; 3375 3376 if (Outputtofile && (argc - optind)) { 3377 usage(); 3378 } else if (Outputtofile && !DiskName) { 3379 usage(); 3380 } else if (!Outputtofile && (argc - optind != 1)) { 3381 usage(); 3382 } else if (SunBPBfields && !BootBlkFn) { 3383 (void) fprintf(stderr, 3384 gettext("Use of the 'S' option requires that\n" 3385 "the 'B=' option also be used.\n\n")); 3386 usage(); 3387 } else if (Firstfileattr != 0x20 && !FirstFn) { 3388 (void) fprintf(stderr, 3389 gettext("Use of the 'r', 'h', or 's' options requires\n" 3390 "that the 'i=' option also be used.\n\n")); 3391 usage(); 3392 } else if (!GetOffset && !DontUseFdisk) { 3393 (void) fprintf(stderr, 3394 gettext("Use of the 'hidden' option requires that\n" 3395 "the 'nofdisk' option also be used.\n\n")); 3396 usage(); 3397 } else if (DontUseFdisk && GetSize) { 3398 (void) fprintf(stderr, 3399 gettext("Use of the 'nofdisk' option requires that\n" 3400 "the 'size=' option also be used.\n\n")); 3401 usage(); 3402 } else if (!GetBPF && 3403 BitsPerFAT != 12 && BitsPerFAT != 16 && BitsPerFAT != 32) { 3404 (void) fprintf(stderr, 3405 gettext("Invalid Bits/Fat value." 3406 " Must be 12, 16 or 32.\n")); 3407 exit(2); 3408 } else if (!GetSPC && !powerofx_le_y(2, 128, SecPerClust)) { 3409 (void) fprintf(stderr, 3410 gettext("Invalid Sectors/Cluster value. Must be a " 3411 "power of 2 between 1 and 128.\n")); 3412 exit(2); 3413 } else if (!GetResrvd && (Resrvd < 1 || Resrvd > 0xffff)) { 3414 (void) fprintf(stderr, 3415 gettext("Invalid number of reserved sectors. " 3416 "Must be at least 1 but\nno larger than 65535.")); 3417 exit(2); 3418 } else if (!GetResrvd && MakeFAT32 && 3419 (Resrvd < 32 || Resrvd > 0xffff)) { 3420 (void) fprintf(stderr, 3421 gettext("Invalid number of reserved sectors. " 3422 "Must be at least 32 but\nno larger than 65535.")); 3423 exit(2); 3424 } else if (Imagesize != 3 && Imagesize != 5) { 3425 usage(); 3426 } 3427 } 3428 3429 int 3430 main(int argc, char **argv) 3431 { 3432 off64_t AbsBootSect = 0; 3433 bpb_t dskparamblk; 3434 char *string; 3435 int fd; 3436 int c; 3437 3438 (void) setlocale(LC_ALL, ""); 3439 3440 #if !defined(TEXT_DOMAIN) 3441 #define TEXT_DOMAIN "SYS_TEST" 3442 #endif 3443 (void) textdomain(TEXT_DOMAIN); 3444 3445 while ((c = getopt(argc, argv, "F:Vmo:")) != EOF) { 3446 switch (c) { 3447 case 'F': 3448 string = optarg; 3449 if (strcmp(string, "pcfs") != 0) 3450 usage(); 3451 break; 3452 case 'V': 3453 { 3454 char *opt_text; 3455 int opt_count; 3456 3457 (void) fprintf(stdout, 3458 gettext("mkfs -F pcfs ")); 3459 for (opt_count = 1; opt_count < argc; 3460 opt_count++) { 3461 opt_text = argv[opt_count]; 3462 if (opt_text) 3463 (void) fprintf(stdout, " %s ", 3464 opt_text); 3465 } 3466 (void) fprintf(stdout, "\n"); 3467 } 3468 break; 3469 case 'm': 3470 GetFsParams++; 3471 break; 3472 case 'o': 3473 string = optarg; 3474 parse_suboptions(string); 3475 break; 3476 } 3477 } 3478 3479 sanity_check_options(argc, optind); 3480 3481 if (!Outputtofile) 3482 DiskName = argv[optind]; 3483 3484 (void) memset(&dskparamblk, 0, sizeof (dskparamblk)); 3485 3486 if (GetFsParams) { 3487 fd = open_and_examine(DiskName, &dskparamblk); 3488 } else { 3489 fd = open_and_seek(DiskName, &dskparamblk, &AbsBootSect); 3490 if (ask_nicely(DiskName)) 3491 write_fat(fd, AbsBootSect, BootBlkFn, Label, 3492 FirstFn, &dskparamblk); 3493 } 3494 (void) close(fd); 3495 return (0); 3496 } 3497