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