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