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