/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2011 Gary Mills
*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#include <ctype.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <libintl.h>
#include <locale.h>
#include <sys/sysmacros.h>
#include "mkfs_pcfs.h"
#include <macros.h>
/*
* mkfs (for pcfs)
*
* Install a boot block, FAT, and (if desired) the first resident
* of the new fs.
*
* XXX -- floppy opens need O_NDELAY?
*/
#define IN_RANGE(n, x, y) (((n) >= (x)) && ((n) <= (y)))
static int Outputtofile = 0;
static int SunBPBfields = 0;
static int GetFsParams = 0;
static int Fatentsize = 0;
static int Notreally = 0;
static int Verbose = 0;
static int MakeFAT32 = 0;
/*
* If there is an FDISK entry for the device where we're about to
* make the file system, we ought to make a file system that has the
* same size FAT as the FDISK table claims. We track the size FDISK
* thinks in this variable.
*/
static int FdiskFATsize = 0;
/*
* Unless we are told otherwise, we should use fdisk table for non-diskettes.
*/
static int DontUseFdisk = 0;
/*
* Function prototypes
*/
#ifndef i386
#endif
int *dashos);
static void warn_funky_fatsize(void);
static void warn_funky_floppy(void);
static void parse_suboptions(char *optsstr);
static void header_for_dump(void);
static void partn_lecture(char *dn);
static void missing_arg(char *option);
static void dashm_bail(int fd);
static void dump_bytes(uchar_t *, int);
static void usage(void);
static int parse_drvnum(char *pn);
static int ask_nicely(char *special);
static int yes(void);
/*
* usage
*
* Display usage message and exit.
*/
static
void
usage(void)
{
gettext("pcfs usage: mkfs [-F FSType] [-V] [-m] "
"[-o specific_options] special\n"));
gettext(" -V: print this command line and return\n"
" -m: dump command line used to create a FAT on this media\n"
"\t(other options are ignored if this option is chosen).\n"
" -o: pcfs_specific_options:\n"
"\t'pcfs_specific_options' is a comma separated list\n"
"\tincluding one or more of the following options:\n"
"\t N,v,r,h,s,b=label,B=filename,i=filename,\n"
"\t spc=n,fat=n,nsect=n,ntrack=n,nofdisk,size=n,\n"
"\t reserve=n,hidden=n\n\n"));
gettext("'Special' should specify a raw diskette "
"or raw fixed disk device. \"Fixed\"\n"
"disks (which include high-capacity removable "
"media such as Zip disks)\n"
"may be further qualified with a logical "
"drive specifier.\n"
exit(1);
}
static
int
yes(void)
{
char *a = affirmative;
int b;
b = getchar();
b = getchar();
while (*a) {
if (b == (int)*a)
break;
a++;
}
return (*a);
}
static
int
{
/*
* 4228473 - No way to non-interactively make a pcfs filesystem
*
* If we don't have an input TTY, or we aren't really doing
* anything, then don't ask questions. Assume a yes answer
* to any questions we would ask.
*/
return (1);
(void) printf(
return (yes());
}
/*
* store_16_bits
* Save the lower 16 bits of a 32 bit value (v) into the provided
* buffer (pointed at by *bp), and increment the buffer pointer
* as well. This way the routine can be called multiple times in
* succession to fill buffers. The value is stored in little-endian
* order.
*/
static
void
{
*l++ = v & 0xff;
*l = (v >> 8) & 0xff;
*bp += 2;
}
/*
* store_32_bits
* Save the 32 bit value (v) into the provided buffer (pointed
* at by *bp), and increment the buffer pointer as well. This way
* the routine can be called multiple times in succession to fill
* buffers. The value is stored in little-endian order.
*/
static
void
{
int b;
for (b = 0; b < 4; b++) {
*l++ = v & 0xff;
v = v >> 8;
}
*bp += 4;
}
/*
* dump_bytes -- display bytes as hex numbers.
* b is the pointer to the byte buffer
* n is the number of bytes in the buffer
*/
/* Note: BPL = bytes to display per line */
static
void
{
int cd = n;
int cu = 0;
int o = 0;
int bl;
int ac;
/* Display offset, 16 bytes per line, and printable ascii version */
while (cd > 0) {
ac = 0;
(void) printf("\n%06x: ", o);
ac++;
}
else
(void) printf(" ");
}
else
(void) printf(".");
}
}
(void) printf("\n\n");
}
/*
* header_for_dump -- display simple header over what will be output.
*/
static
void
header_for_dump(void)
{
int bl;
(void) printf("\n ");
(void) printf("\n ");
while (bl-- > 0)
(void) printf("-");
}
/*
* parse_drvnum
* Convert a partition name into a drive number.
*/
static
int
{
int drvnum;
/*
* Determine logical drive to seek after.
*/
char *d;
int v, m, c;
v = 0;
d = pn;
while (*d && *d >= '0' && *d <= '9') {
c = strlen(d);
m = 1;
while (--c)
m *= 10;
v += m * (*d - '0');
d++;
}
if (*d || v > 24) {
gettext("%s: bogus logical drive specification.\n"),
pn);
return (-1);
}
drvnum = v;
drvnum = 99;
} else {
return (-1);
}
return (drvnum);
}
/*
* Define some special logical drives we use.
*/
/*
* isDosDrive()
* Boolean function. Give it the systid field for an fdisk partition
* and it decides if that's a systid that describes a DOS drive. We
*/
static int
{
}
/*
* isDosExtended()
* Boolean function. Give it the systid field for an fdisk partition
* and it decides if that's a systid that describes an extended DOS
* partition.
*/
static int
{
}
/*
* isBootPart()
* Boolean function. Give it the systid field for an fdisk partition
* and it decides if that's a systid that describes a Solaris boot
* partition.
*/
static int
{
}
static
int
{
return (assigned);
/*
* 4228473 - No way to non-interactively make a pcfs filesystem
*
* If we don't have an input TTY, or we aren't really doing
* anything, then don't ask questions. Assume a yes answer
* to any questions we would ask.
*/
"\nbut value obtained from the %s is %d.\n"
"Using user supplied value.\n"),
return (assigned);
}
"\nThe value obtained from the %s is %d.\n"),
(void) printf(
gettext("Continue with value given on command line (y/n)? "));
if (yes())
return (assigned);
else
exit(2);
/*NOTREACHED*/
}
static
void
{
/*
* ExtFlags means (according to MSDN BPB (FAT32) document)
*
* Bit 8 indicates info written to the active FAT is written
* to all copies of the FAT. (I think they mean bit 7, with
* numbering starting at 0)
*
* Lowest 4 bits of field are the 0 based FAT number of the
* Active FAT. (only meaningful if bit 8 is set)
*
* Field contains combination of these values:
*
* VALUE DESCRIPTION
* BGBPB_F_ActiveFATMsk Mask for low four bits
* (0x000F)
* BGBPB_F_NoFATMirror If set FAT mirroring disabled.
* (0x0080) If clear, FAT mirroring enabled.
*
* We set the value based on what I've seen on all the FAT32 drives
* I've seen created by Windows.
*
*/
/*
* No real explanation of the fs_vers file in the BPB doc. The
* high byte is supposed to be the major version and the low the
* minor version. Again I set according to what I've seen on Windows.
*/
/*
* The convention appears to be to place the fs info sector
* immediately after the boot sector, and that the backup boot
* sector should be at sector 6. (based on what I see with
* Windows)
*/
}
static
void
{
if (GetFsParams || GetSize) {
if (Verbose) {
(void) printf(
gettext("Partition size (from FDISK table) "
"= %d sectors.\n"), usesize);
}
} else {
gettext("length of partition (in sectors)"),
gettext("FDISK table"),
}
if (GetFsParams) {
} else {
if (usesize > 0xffff)
else
}
if (GetFsParams) {
} else {
}
}
/*
* lookup_FAT_size
*
* Given the FDISK partition file system identifier, return the
* expected FAT size for the partition.
*/
static
int
{
int rval;
switch (partid) {
case DOSOS12:
rval = 12;
break;
case DOSOS16:
case DOSHUGE:
case FDISK_FAT95:
case X86BOOT:
rval = 16;
break;
case FDISK_WINDOWS:
case FDISK_EXT_WIN:
rval = 32;
break;
case EXTDOS:
case FDISK_EXTLBA:
default:
rval = -1;
break;
}
return (rval);
}
/*
* seek_partn
*
* Seek to the beginning of the partition where we need to install
* the new FAT. Zero return for any error, but print error
* messages here.
*/
static
int
{
int logicalDriveCount = 0;
int drvnum;
int driveIndex;
int i;
/*
* Count of drives in the current extended partition's
* FDISK table, and indexes of the drives themselves.
*/
int numDrives = 0;
/*
* Count of drives (beyond primary) in master boot record's
* FDISK table, and indexes of the drives themselves.
*/
int numExtraDrives = 0;
return (PART_NOT_FOUND);
gettext("Couldn't read a Master Boot Record?!\n"));
return (PART_NOT_FOUND);
}
gettext("Bad Sig on master boot record!\n"));
return (PART_NOT_FOUND);
}
*seekto = 0;
/*
* Copy partition table into memory
*/
/*
* Get a summary of what is in the Master FDISK table.
* Normally we expect to find one partition marked as a DOS drive.
* This partition is the one Windows calls the primary dos partition.
* If the machine has any logical drives then we also expect
* to find a partition marked as an extended DOS partition.
*
* Sometimes we'll find multiple partitions marked as DOS drives.
* The Solaris fdisk program allows these partitions
* to be created, but Windows fdisk no longer does. We still need
* to support these, though, since Windows does. We also need to fix
* our fdisk to behave like the Windows version.
*
* It turns out that some off-the-shelf media have *only* an
* Extended partition, so we need to deal with that case as
* well.
*
* Only a single (the first) Extended or Boot Partition will
* be recognized. Any others will be ignored.
*/
for (i = 0; i < FD_NUMPART; i++) {
if (primaryPart < 0) {
primaryPart = i;
} else {
extraDrives[numExtraDrives++] = i;
}
continue;
}
extendedPart = i;
continue;
}
bootPart = i;
continue;
}
}
if (drvnum == BOOT_PARTITION_DRIVE) {
if (bootPart < 0) {
gettext("No boot partition found on drive\n"));
return (PART_NOT_FOUND);
}
"A boot partition starting\nat sector 0 would "
"collide with the FDISK table!\n"));
return (PART_NOT_FOUND);
}
if (Verbose)
perror("");
return (PART_NOT_FOUND);
}
return (PART_FOUND);
}
"A partition starting\nat sector 0 would "
"collide with the FDISK table!\n"));
return (PART_NOT_FOUND);
}
if (Verbose)
perror("");
return (PART_NOT_FOUND);
}
return (PART_FOUND);
}
/*
* We are not looking for the C: drive (or there was no primary
* drive found), so we had better have an extended partition or
* extra drives in the Master FDISK table.
*/
if ((extendedPart < 0) && (numExtraDrives == 0)) {
gettext("No such logical drive "
"(missing extended partition entry)\n"));
return (PART_NOT_FOUND);
}
if (extendedPart >= 0) {
do {
/*
* If the seek would not cause us to change
* position on the drive, then we're out of
* extended partitions to examine.
*/
break;
/*
* Seek the next extended partition, and find
* logical drives within it.
*/
sizeof (extmboot)) {
"partition record"));
return (PART_NOT_FOUND);
}
gettext("Bad signature on "
"extended partition\n"));
return (PART_NOT_FOUND);
}
/*
* Count up drives, and track where the next
* extended partition is in case we need it. We
* are expecting only one extended partition. If
* there is more than one we'll only go to the
* first one we see, but warn about ignoring.
*/
numDrives = 0;
for (i = 0; i < FD_NUMPART; i++) {
extndDrives[numDrives++] = i;
continue;
/*
* Already found an extended
* partition in this table.
*/
gettext("WARNING: "
"Ignoring unexpected "
"additional extended "
"partition"));
continue;
}
nextseek = xstartsect +
continue;
}
}
/*
* The number of logical drives we've found thus
* far is enough to get us to the one we were
* searching for.
*/
*seekto =
gettext("Bogus FDISK entry? A logical "
"drive starting at\nsector 0x%llx would "
"collide with the\nFDISK information in "
"that sector.\n"), *seekto);
return (PART_NOT_FOUND);
} else if (*seekto <= xstartsect ||
gettext("Bogus FDISK entry? "
"Logical drive start sector (0x%llx)\n"
"not within extended partition! "
"(Expected in range 0x%x - 0x%x)\n"),
return (PART_NOT_FOUND);
}
*seekto);
if (Verbose)
perror("");
return (PART_NOT_FOUND);
}
return (PART_FOUND);
} else {
/*
* We ran out of extended dos partition
* drives. The only hope now is to go
* back to extra drives defined in the master
* fdisk table. But we overwrote that table
* already, so we must load it in again.
*/
}
}
/*
* Still haven't found the drive, is it an extra
* drive defined in the main FDISK table?
*/
if (*seekto == 0) {
"A partition starting\nat sector 0 would "
"collide with the FDISK table!\n"));
return (PART_NOT_FOUND);
}
if (Verbose)
perror("");
return (PART_NOT_FOUND);
}
return (PART_FOUND);
}
return (PART_NOT_FOUND);
}
/*
* seek_nofdisk
*
* User is asking us to trust them that they know best.
* We basically won't do much seeking here, the only seeking we'll do
* is if the 'hidden' parameter was given.
*/
static
int
{
if (TotSize > 0xffff)
else
if (Verbose)
perror("");
return (PART_NOT_FOUND);
}
return (PART_FOUND);
}
/*
* set_fat_string
*
* Fill in the type string of the FAT
*/
static
void
{
if (fatsize == 12) {
} else if (fatsize == 16) {
} else {
}
}
/*
* prepare_image_file
*
* Open the file that will hold the image (as opposed to the image
* being written to the boot sector of an actual disk).
*/
static
int
{
int fd;
exit(2);
}
if (Imagesize == 5) {
/* Disk image of a 1.2M floppy */
} else {
/* Disk image of a 1.44M floppy */
}
/*
* Make a holey file, with length the exact
* size of the floppy image.
*/
exit(2);
}
exit(2);
}
exit(2);
}
return (fd);
}
/*
* partn_lecture
*
* Give a brief sermon on dev_name user should pass to
* the program from the command line.
*
*/
static
void
{
gettext("\nDevice %s was assumed to be a diskette.\n"
"A diskette specific operation failed on this device.\n"
"If the device is a hard disk, provide the name of "
"the full physical disk,\n"
"and qualify that name with a logical drive specifier.\n\n"
"Hint: the device is usually something similar to\n\n"
"The drive specifier is appended to the device name."
" For example:\n\n"
}
static
void
warn_funky_floppy(void)
{
gettext("Use the 'nofdisk' option to create file systems\n"
"on non-standard floppies.\n\n"));
exit(4);
}
static
void
warn_funky_fatsize(void)
{
gettext("Non-standard FAT size requested for floppy.\n"
"The 'nofdisk' option must be used to\n"
"override the 12 bit floppy default.\n\n"));
exit(4);
}
static
void
{
switch (diam) {
case 3:
switch (hds) {
case 2:
switch (spt) {
case 9:
break;
case 18:
break;
case 36:
break;
default:
gettext("Unknown diskette parameters! "
"3.5'' diskette with %d heads "
}
break;
case 1:
default:
gettext("Unknown diskette parameters! "
"3.5'' diskette with %d heads "), hds);
}
break;
case 5:
switch (hds) {
case 2:
switch (spt) {
case 15:
break;
case 9:
break;
case 8:
break;
default:
gettext("Unknown diskette parameters! "
"5.25'' diskette with %d heads "
}
break;
case 1:
switch (spt) {
case 9:
break;
case 8:
break;
default:
gettext("Unknown diskette parameters! "
"5.25'' diskette with %d heads "
}
break;
default:
gettext("Unknown diskette parameters! "
"5.25'' diskette with %d heads."), hds);
}
break;
default:
gettext("\nUnknown diskette type. Only know about "
"5.25'' and 3.5'' diskettes.\n"));
}
}
/*
* lookup_floppy
*
* Look up a media descriptor byte and other crucial BPB values
* based on floppy characteristics.
*/
static
void
{
if (GetFsParams)
if (GetSize) {
} else {
gettext("length of partition (in sectors)"),
}
if (GetSPT) {
} else {
gettext("sectors per track"),
}
if (GetTPC) {
} else {
gettext("number of heads"),
}
}
}
/*
* compute_cluster_size
*
*
* Based on values from the Hardware White Paper
* from Microsoft.
* "Microsoft Extensible Firmware Initiative
* FAT32 File System Specification
* FAT: General Overview of On-Disk Format"
*
* Version 1.03, December 6, 2000
*
*/
static
void
{
/* compute volume size in sectors. */
if (GetSPC) {
/*
* User indicated what sort of FAT to create,
* make sure it is valid with the given size
* and compute an SPC value.
*/
if (!MakeFAT32) { /* FAT16 */
/* volsize is in sectors */
if (volsize < FAT12_MAX_CLUSTERS) {
gettext("Requested size is too "
"small for FAT16.\n"));
exit(4);
}
/* SPC must be a power of 2 */
break;
}
gettext("Requested size is too "
"large for FAT16.\n"));
exit(4);
}
} else { /* FAT32 */
/* volsize is in sectors */
if (volsize < FAT16_MAX_CLUSTERS) {
gettext("Requested size is too "
"small for FAT32.\n"));
exit(4);
}
/* SPC must be a power of 2 */
break;
}
gettext("Requested size is too "
"large for FAT32.\n"));
exit(4);
}
}
} else {
/*
* User gave the SPC as an explicit option,
* make sure it will work with the requested
* volume size.
*/
int nclust;
spc = SecPerClust;
"small for FAT32.\n"));
exit(4);
}
if (!MakeFAT32) {
/* Determine if FAT12 or FAT16 */
if (nclust < FAT12_MAX_CLUSTERS)
newfat = 12;
else if (nclust < FAT16_MAX_CLUSTERS)
newfat = 16;
else {
gettext("Requested size is too "
"small for FAT32.\n"));
exit(4);
}
}
}
/*
* RootDirSectors = ((BPB_RootEntCnt * 32) +
* (BPB_BytsPerSec 1)) / BPB_BytsPerSec;
*/
if (GetBPF) {
if (MakeFAT32)
Fatentsize = 32;
else
Fatentsize = newfat;
} else {
if (Fatentsize == 12 &&
/*
* If we don't have an input TTY, or we aren't
* really doing anything, then don't ask
* questions. Assume a yes answer to any
* questions we would ask.
*/
(void) printf(
gettext("Volume too large for 12 bit FAT,"
" increasing to 16 bit FAT size.\n"));
Fatentsize = 16;
} else {
(void) printf(
gettext("Volume too large for a 12 bit FAT.\n"
"Increase to 16 bit FAT "
"and continue (y/n)? "));
if (yes())
Fatentsize = 16;
else
exit(5);
}
}
}
if (!GetFsParams && FdiskFATsize < 0) {
(void) printf(
"entry size (%d bits) with FDISK table.\n"
"FDISK table has an unknown file system "
"type for this device. Giving up...\n"),
exit(6);
(void) printf(
"does not match FDISK table (%d bits).\n"),
(void) printf(
gettext("Use -o fat=%d to build a FAT "
"that matches the FDISK entry.\n"), FdiskFATsize);
exit(6);
}
/*
* Compure the FAT sizes according to algorithm from Microsoft:
*
* RootDirSectors = ((BPB_RootEntCnt * 32) +
* (BPB_BytsPerSec 1)) / BPB_BytsPerSec;
* TmpVal1 = DskSize - (BPB_ResvdSecCnt + RootDirSectors);
* TmpVal2 = (256 * BPB_SecPerClus) + BPB_NumFATs;
* If (FATType == FAT32)
* TmpVal2 = TmpVal2 / 2;
* FATSz = (TMPVal1 + (TmpVal2 1)) / TmpVal2;
* If (FATType == FAT32) {
* BPB_FATSz16 = 0;
* BPB_FATSz32 = FATSz;
* } else {
* BPB_FATSz16 = LOWORD(FATSz);
* // there is no BPB_FATSz32 in a FAT16 BPB
* }
*/
if (Fatentsize == 32)
switch (Fatentsize) {
case 32:
if (Verbose)
(void) printf("compute_cluster_size: Sectors per "
break;
case 12:
default: /* 16 bit FAT */
if (Verbose)
(void) printf("compute_cluster_size: Sectors per "
break;
}
}
static
void
{
/*
* Look up the last remaining bits of info we need
* that is specific to the hard drive using a disk ioctl.
*/
gettext("Drive geometry lookup (need "
exit(2);
}
}
if (Verbose) {
if (GetTPC) {
(void) printf(
gettext("DKIOCG determined number of heads = %d\n"),
}
if (GetSPT) {
(void) printf(
gettext("DKIOCG determined sectors per track"
}
}
/*
* XXX - MAY need an additional flag (or flags) to set media
* and physical drive number fields. That in the case of weird
* floppies that have to go through 'nofdisk' route for formatting.
*/
if (MakeFAT32)
else
}
static
char *
{
char *actualdisk;
/*
* Device named on command line doesn't exist. That
* probably means there is a partition-specifying
* suffix attached to the actual disk name.
*/
(*suffix)++;
exit(2);
}
} else {
}
return (actualdisk);
}
static
void
{
int FATSz;
int TotSec;
int DataSec;
int RootDirSectors =
/*
* Good old FAT12 or FAT16
*/
} else {
/*
* FAT32
*/
}
/*
* Now change sectors to clusters
*/
if (Verbose)
"allocation units,\neach with %d sectors = %d "
}
#ifndef i386
/*
* swap_pack_{bpb,bpb32,sebpb}cpy
*
* If not on an x86 we assume the structures making up the bpb
* were not packed and that longs and shorts need to be byte swapped
* (we've kept everything in host order up until now). A new architecture
* might not need to swap or might not need to pack, in which case
* new routines will have to be written. Of course if an architecture
* supports both packing and little-endian host order, it can follow the
* same path as the x86 code.
*/
static
void
{
fillp += 11;
}
static
void
{
int r;
for (r = 0; r < 6; r++)
fillp += 11;
}
static
void
{
}
static
void
{
grabp += 11;
}
static
void
{
}
static
void
{
}
#endif /* ! i386 */
static
void
{
gettext("This media does not appear to be "
"formatted with a FAT file system.\n"));
exit(6);
}
/*
* read_existing_bpb
*
* Grab the first sector, which we think is a bios parameter block.
* If it looks bad, bail. Otherwise fill in the parameter struct
* fields that matter.
*/
static
void
{
"from previously formatted media"));
exit(6);
}
dashm_bail(fd);
}
#ifdef i386
#else
#endif
if (SunBPBfields) {
#ifdef i386
#else
#endif
}
gettext("Bogus bytes per sector value.\n"));
gettext("The device name may be missing a "
"logical drive specifier.\n"));
exit(6);
} else {
gettext("Do not know how to build FATs with a\n"
"non-standard sector size. Standard "
"size is %d bytes,\nyour sector size "
"is %d bytes.\n"), BPSEC,
exit(6);
}
}
gettext("Bogus sectors per cluster value.\n"));
gettext("The device name may be missing a "
"logical drive specifier.\n"));
exit(6);
}
#ifdef i386
#else
#endif
MakeFAT32 = 1;
} else {
dashm_bail(fd);
}
} else {
}
}
/*
* compare_existing_with_computed
*
* We use this function when we the user specifies the -m option.
* We compute and look up things like we would if they had asked
* us to make the fs, and compare that to what's already layed down
* in the existing fs. If there's a difference we can tell them what
* options to specify in order to reproduce their existing layout.
* Note that they still may not get an exact duplicate, because we
* don't, for example, preserve their existing boot code. We think
* we've got all the fields that matter covered, though.
*
* XXX - We're basically ignoring sbpb at this point. I'm unsure
* if we'll ever care about those fields, in terms of the -m option.
*/
static
void
{
int fd_ioctl_worked = 0;
int fatents;
/*
* For all non-floppy cases we expect to find a 16-bit FAT
*/
if (!suffix) {
expectfatsize = 12;
}
}
if (fd_ioctl_worked) {
#ifdef sparc
#endif
(*prtntrk)++;
(*dashos)++;
}
(*prtnsect)++;
(*dashos)++;
}
} else {
if (!suffix) {
(*prtfdisk)++;
(*prtsize)++;
*dashos += 2;
}
*dashos += 2;
dk_ioctl_worked = 0;
}
if (dk_ioctl_worked) {
(*prtntrk)++;
(*dashos)++;
}
(*prtnsect)++;
(*dashos)++;
}
}
}
(*dashos)++;
(*prtsize)++;
}
(*dashos)++;
(*prtspc)++;
}
(*dashos)++;
(*prthidden)++;
}
(*dashos)++;
(*prtrsrvd)++;
}
/*
* Compute approximate Fatentsize. It's approximate because the
* size of the FAT may not be exactly a multiple of the number of
* clusters. It should be close, though.
*/
if (MakeFAT32) {
Fatentsize = 32;
(*dashos)++;
(*prtbpf)++;
} else {
Fatentsize = 12;
else
Fatentsize = 16;
if (Fatentsize != expectfatsize) {
(*dashos)++;
(*prtbpf)++;
}
}
}
static
void
{
int needcomma = 0;
int prthidden = 0;
int prtrsrvd = 0;
int prtfdisk = 0;
int prtnsect = 0;
int prtntrk = 0;
int prtsize = 0;
int prtbpf = 0;
int prtspc = 0;
int dashos = 0;
int ll, i;
/*
* Print out the command line they can use to reproduce the
* file system.
*/
(void) printf("mkfs -F pcfs");
/*
* First, eliminate trailing spaces. Now compare the name against
* our default label. If there's a match we don't need to print
* any label info.
*/
i = ll;
;
ll = i;
for (i = ll; i >= 0; i--) {
if (cmpbuf[i] !=
break;
}
}
if (i < 0)
ll = i;
}
if (ll >= 0) {
(void) printf(" -o ");
(void) printf("b=\"");
for (i = 0; i <= ll; i++) {
}
(void) printf("\"");
needcomma++;
} else if (dashos) {
(void) printf(" -o ");
}
while (dashos) {
if (needcomma) {
(void) printf(",");
needcomma = 0;
}
if (prtfdisk) {
(void) printf("nofdisk");
prtfdisk--;
}
if (prtsize) {
prtsize--;
}
if (prtnsect) {
prtnsect--;
}
if (prtspc) {
prtspc--;
}
if (prtntrk) {
prtntrk--;
}
if (prtbpf) {
prtbpf--;
}
if (prthidden) {
prthidden--;
}
if (prtrsrvd) {
prtrsrvd--;
}
}
}
/*
* open_and_examine
*
* Open the requested 'dev_name'. Seek to point where
* we'd expect to find boot sectors, etc., based on any ':partition'
* attachments to the dev_name.
*
* Examine the fields of any existing boot sector and display best
* approximation of how this fs could be reproduced with this command.
*/
static
int
{
int fd;
if (Verbose)
/*
* Destination exists, now find more about it.
*/
gettext("\n%s: device name must be a "
"character special device.\n"), actualdisk);
exit(2);
exit(2);
}
/*
* Check the media sector size
*/
if (dkminfo.dki_lbsize != 0 &&
gettext("The device sector size %u is not "
exit(1);
}
}
/*
* Find appropriate partition if we were requested to do so.
*/
exit(2);
}
return (fd);
}
/*
* open_and_seek
*
* Open the requested 'dev_name'. Seek to point where
* we'll write boot sectors, etc., based on any ':partition'
* attachments to the dev_name.
*
* By the time we are finished here, the entire BPB will be
* filled in, excepting the volume label.
*/
static
int
{
int fd;
if (Verbose)
/*
* We hold these truths to be self evident, all BPBs we create
* will have these values in these fields.
*/
/*
* Assign or use supplied numbers for hidden and
* reserved sectors in the file system.
*/
if (GetResrvd)
if (MakeFAT32)
else
else
if (MakeFAT32)
/*
* If all output goes to a simple file, call a routine to setup
* that scenario. Otherwise, try to find the device.
*/
if (Outputtofile)
/*
* Sanity check. If we've been provided a partition-specifying
* suffix, we shouldn't also have been told to ignore the
* fdisk table.
*/
if (DontUseFdisk && suffix) {
gettext("Using 'nofdisk' option precludes "
"appending logical drive\nspecifier "
"to the device name.\n"));
exit(2);
}
/*
* Destination exists, now find more about it.
*/
gettext("\n%s: device name must indicate a "
"character special device.\n"), actualdisk);
exit(2);
exit(2);
}
/*
* Check the media sector size
*/
if (dkminfo.dki_lbsize != 0 &&
gettext("The device sector size %u is not "
exit(1);
}
}
/*
* Find appropriate partition if we were requested to do so.
*/
exit(2);
}
if (!suffix) {
/*
* We have one of two possibilities. Chances are we have
* a floppy drive. But the user may be trying to format
* some weird drive that we don't know about and is supplying
* all the important values. In that case, they should have set
* the 'nofdisk' flag.
*
* If 'nofdisk' isn't set, do a floppy-specific ioctl to
* get the remainder of our info. If the ioctl fails, we have
* a good idea that they aren't really on a floppy. In that
* case, they should have given us a partition specifier.
*/
if (DontUseFdisk) {
exit(2);
}
/*
* It is possible that we are trying to use floppy
* specific FDIOGCHAR ioctl on USB floppy. Since sd
* driver, by which USB floppy is handled, doesn't
* support it, we can try to use disk DKIOCGGEOM ioctl
* to retrieve data we need. sd driver itself
* determines floppy disk by number of blocks
* (<=0x1000), then it sets geometry to 80 cylinders,
* 2 heads.
*
* Note that DKIOCGGEOM cannot supply us with type
* of media (e.g. 3.5" or 5.25"). We will set it to
* 3 (3.5") which is most probable value.
*/
} else {
exit(2);
}
}
} else {
#ifdef sparc
#endif
}
} else {
}
return (fd);
}
/*
* The following is a copy of MS-DOS 4.0 boot block.
* It consists of the BIOS parameter block, and a disk
* bootstrap program.
*
* The BIOS parameter block contains the right values
* for the 3.5" high-density 1.44MB floppy format.
*
* This will be our default boot sector, if the user
* didn't point us at a different one.
*
*/
static
0xeb, 0x3c, 0x90, /* 8086 short jump + displacement + NOP */
'M', 'S', 'D', 'O', 'S', '4', '.', '0', /* OEM name & version */
0x00, 0x02, 0x01, 0x01, 0x00,
0x02, 0xe0, 0x00, 0x40, 0x0b,
0xf0, 0x09, 0x00, 0x12, 0x00,
0x02, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
0x29, 0x00, 0x00, 0x00, 0x00,
'N', 'O', 'N', 'A', 'M', 'E', ' ', ' ', ' ', ' ', ' ',
'F', 'A', 'T', '1', '2', ' ', ' ', ' ',
0xfa, 0x33,
0xc0, 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0x16, 0x07,
0xbb, 0x78, 0x00, 0x36, 0xc5, 0x37, 0x1e, 0x56,
0x16, 0x53, 0xbf, 0x3e, 0x7c, 0xb9, 0x0b, 0x00,
0xfc, 0xf3, 0xa4, 0x06, 0x1f, 0xc6, 0x45, 0xfe,
0x0f, 0x8b, 0x0e, 0x18, 0x7c, 0x88, 0x4d, 0xf9,
0x89, 0x47, 0x02, 0xc7, 0x07, 0x3e, 0x7c, 0xfb,
0xcd, 0x13, 0x72, 0x7c, 0x33, 0xc0, 0x39, 0x06,
0x13, 0x7c, 0x74, 0x08, 0x8b, 0x0e, 0x13, 0x7c,
0x89, 0x0e, 0x20, 0x7c, 0xa0, 0x10, 0x7c, 0xf7,
0x26, 0x16, 0x7c, 0x03, 0x06, 0x1c, 0x7c, 0x13,
0x16, 0x1e, 0x7c, 0x03, 0x06, 0x0e, 0x7c, 0x83,
0xd2, 0x00, 0xa3, 0x50, 0x7c, 0x89, 0x16, 0x52,
0x7c, 0xa3, 0x49, 0x7c, 0x89, 0x16, 0x4b, 0x7c,
0xb8, 0x20, 0x00, 0xf7, 0x26, 0x11, 0x7c, 0x8b,
0x1e, 0x0b, 0x7c, 0x03, 0xc3, 0x48, 0xf7, 0xf3,
0x01, 0x06, 0x49, 0x7c, 0x83, 0x16, 0x4b, 0x7c,
0x00, 0xbb, 0x00, 0x05, 0x8b, 0x16, 0x52, 0x7c,
0xa1, 0x50, 0x7c, 0xe8, 0x87, 0x00, 0x72, 0x20,
0xb0, 0x01, 0xe8, 0xa1, 0x00, 0x72, 0x19, 0x8b,
0xfb, 0xb9, 0x0b, 0x00, 0xbe, 0xdb, 0x7d, 0xf3,
0xa6, 0x75, 0x0d, 0x8d, 0x7f, 0x20, 0xbe, 0xe6,
0x7d, 0xb9, 0x0b, 0x00, 0xf3, 0xa6, 0x74, 0x18,
0xbe, 0x93, 0x7d, 0xe8, 0x51, 0x00, 0x32, 0xe4,
0xcd, 0x16, 0x5e, 0x1f, 0x8f, 0x04, 0x8f, 0x44,
0x02, 0xcd, 0x19, 0x58, 0x58, 0x58, 0xeb, 0xe8,
0xbb, 0x00, 0x07, 0xb9, 0x03, 0x00, 0xa1, 0x49,
0x7c, 0x8b, 0x16, 0x4b, 0x7c, 0x50, 0x52, 0x51,
0xe8, 0x3a, 0x00, 0x72, 0xe6, 0xb0, 0x01, 0xe8,
0x54, 0x00, 0x59, 0x5a, 0x58, 0x72, 0xc9, 0x05,
0x01, 0x00, 0x83, 0xd2, 0x00, 0x03, 0x1e, 0x0b,
0x7c, 0xe2, 0xe2, 0x8a, 0x2e, 0x15, 0x7c, 0x8a,
0x16, 0x24, 0x7c, 0x8b, 0x1e, 0x49, 0x7c, 0xa1,
0x4b, 0x7c, 0xea, 0x00, 0x00, 0x70, 0x00, 0xac,
0x0a, 0xc0, 0x74, 0x29, 0xb4, 0x0e, 0xbb, 0x07,
0x00, 0xcd, 0x10, 0xeb, 0xf2, 0x3b, 0x16, 0x18,
0x7c, 0x73, 0x19, 0xf7, 0x36, 0x18, 0x7c, 0xfe,
0xc2, 0x88, 0x16, 0x4f, 0x7c, 0x33, 0xd2, 0xf7,
0x36, 0x1a, 0x7c, 0x88, 0x16, 0x25, 0x7c, 0xa3,
0x4d, 0x7c, 0xf8, 0xc3, 0xf9, 0xc3, 0xb4, 0x02,
0x8b, 0x16, 0x4d, 0x7c, 0xb1, 0x06, 0xd2, 0xe6,
0x0a, 0x36, 0x4f, 0x7c, 0x8b, 0xca, 0x86, 0xe9,
0x8a, 0x16, 0x24, 0x7c, 0x8a, 0x36, 0x25, 0x7c,
0xcd, 0x13, 0xc3, 0x0d, 0x0a, 0x4e, 0x6f, 0x6e,
0x2d, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20,
0x64, 0x69, 0x73, 0x6b, 0x20, 0x6f, 0x72, 0x20,
0x64, 0x69, 0x73, 0x6b, 0x20, 0x65, 0x72, 0x72,
0x6f, 0x72, 0x0d, 0x0a, 0x52, 0x65, 0x70, 0x6c,
0x61, 0x63, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20,
0x70, 0x72, 0x65, 0x73, 0x73, 0x20, 0x61, 0x6e,
0x79, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x77, 0x68,
0x65, 0x6e, 0x20, 0x72, 0x65, 0x61, 0x64, 0x79,
0x0d, 0x0a, 0x00, 0x49, 0x4f, 0x20, 0x20, 0x20,
0x20, 0x20, 0x20, 0x53, 0x59, 0x53, 0x4d, 0x53,
0x44, 0x4f, 0x53, 0x20, 0x20, 0x20, 0x53, 0x59,
0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xaa
};
/*
* verify_bootblkfile
*
* We were provided with the name of a file containing the bootblk
* to install. Verify it has a valid boot sector as best we can. Any
* errors and we return a bad file descriptor. Otherwise we fill up the
* provided buffer with the boot sector, return the file
* descriptor for later use and leave the file pointer just
* past the boot sector part of the boot block file.
*/
static
int
{
bsfd = -1;
} else {
#ifdef i386
#else
#endif
/* CSTYLED */
) {
bsfd = -1;
}
}
return (bsfd);
}
/*
* verify_firstfile
*
* We were provided with the name of a file to be the first file
* installed on the disk. We just need to verify it exists and
* find out how big it is. If it doesn't exist, we print a warning
* message about how the file wasn't found. We don't exit fatally,
* though, rather we return a size of 0 and the FAT will be built
* without installing any first file. They can then presumably
* install the correct first file by hand.
*/
static
int
{
*filesize = 0;
gettext("Could not access requested file. It will not\n"
"be installed in the new file system.\n"));
} else {
}
return (fd);
}
/*
* label_volume
*
* Fill in BPB with volume label.
*/
static
void
{
int ll, i;
/* Put a volume label into our BPB. */
if (!lbl)
lbl = DEFAULT_LABEL;
for (i = 0; i < ll; i++) {
}
for (; i < 11; i++) {
}
}
static
int
{
"block file %s.\n"), fn);
else if (Verbose)
/*
* If they want to install their own boot block, sanity check
* that block.
*/
if (fn) {
if (bsfd < 0) {
exit(3);
}
} else {
*bootblksize = BPSEC;
}
return (bsfd);
}
/*
* mark_cluster
*
* This routine fills a FAT entry with the value supplied to it as an
* argument. The fatp argument is assumed to be a pointer to the FAT's
* 0th entry. The clustnum is the cluster entry that should be updated.
* The value is the new value for the entry.
*/
static
void
{
if (Fatentsize == 32) {
} else if (Fatentsize == 16) {
} else {
if (clustnum & 1) {
ep++;
} else {
}
}
}
static
uchar_t *
{
int remclust;
/* Alloc space for a FAT and then null it out. */
if (Verbose) {
}
if (MakeFAT32) {
} else {
}
exit(4);
} else {
}
/* Build in-memory FAT */
if (Fatentsize == 16) {
} else if (Fatentsize == 32) {
}
/*
* Keep track of clusters used.
*/
nextfree = 2;
/*
* Get info on first file to install, if any.
*/
if (ffn)
/*
* Compute number of clusters to preserve for bootblk overage.
* Remember that we already wrote the first sector of the boot block.
* These clusters are marked BAD to prevent them from being deleted
* or used. The first available cluster is 2, so we always offset
* the clusters.
*/
numclust);
/*
* Reserve a cluster for the root directory on a FAT32.
*/
if (MakeFAT32) {
remclust--;
}
/*
* Compute and preserve number of clusters for first file.
*/
if (*fffd >= 0) {
*ffstartclust = nextfree;
gettext("Requested first file too large to be\n"
"installed in the new file system.\n"));
*fffd = -1;
goto finish;
}
if (Verbose)
"cluster(s).\n"), numclust);
}
if (Verbose) {
}
return (fatp);
}
static
void
{
/* get the time & day into DOS format */
}
static
void
{
int nl, i;
/*
* We spread the volume label across both the NAME and EXT fields
*/
for (i = 0; i < nl; i++) {
}
if (i < PCFNAMESIZE) {
for (; i < PCFNAMESIZE; i++)
for (i = 0; i < PCFEXTSIZE; i++)
return;
}
for (i = 0; i < nl; i++)
if (i < PCFEXTSIZE) {
for (; i < PCFEXTSIZE; i++)
}
}
static
void
{
int nl, i;
fname++;
} else {
}
fext++;
} else {
fext = "";
}
for (i = 0; i < nl; i++) {
}
for (; i < PCFNAMESIZE; i++) {
}
for (i = 0; i < nl; i++) {
}
for (; i < PCFEXTSIZE; i++) {
}
}
static
uchar_t *
{
/*
* Build a root directory. It will have at least one entry,
* the volume label and a second if the first file was defined.
*/
if (MakeFAT32) {
/*
* We devote an entire cluster to the root
* directory on FAT32.
*/
} else {
}
exit(4);
} else {
}
/* Create directory entry for first file, if there is one */
if (fffd >= 0) {
if (MakeFAT32) {
}
entry++;
}
/* Create directory entry for volume label, if there is one */
entry->pcd_scluster_lo = 0;
if (MakeFAT32) {
}
entry++;
}
if (Verbose) {
}
}
/*
* write_rest
*
* Write all the bytes from the current file pointer to end of file
* in the source file out to the destination file. The writes should
* be padded to whole clusters with 0's if necessary.
*/
static
void
{
int doneread = 0;
int rstat;
/*
* Compute number of clusters required to contain remaining bytes.
*/
for (s = 0; s < wnumsect; s++) {
if (!doneread) {
doneread = 1;
rstat = 0;
} else if (rstat == 0) {
doneread = 1;
}
}
}
}
}
static
void
{
if (Verbose) {
}
if (!Notreally) {
/*
* FAT32's have an FS info sector, then a backup of the boot
* sector, and a modified backup of the FS Info sector.
*/
exit(4);
}
exit(4);
}
exit(4);
}
}
/*
* Second copy of fs info sector is modified to have "don't know"
* as the number of free clusters
*/
if (Verbose) {
}
if (!Notreally) {
exit(4);
}
}
}
static
void
{
if (MakeFAT32) {
/* Copy our BPB into bootsec structure */
#ifdef i386
#else
#endif
} else {
/* Copy our BPB into bootsec structure */
#ifdef i386
#else
#endif
/* Copy SUN BPB extensions into bootsec structure */
if (SunBPBfields) {
#ifdef i386
#else
#endif
}
}
/* Write boot sector */
exit(4);
}
if (Verbose) {
}
if (MakeFAT32)
}
static
void
{
if (Verbose)
exit(4);
}
/* Write FAT */
if (Verbose)
if (!Notreally) {
exit(4);
} else {
if (Verbose)
(void) printf(
}
}
if (Verbose)
/*
* In non FAT32, root directory exists outside of the file area
*/
if (!MakeFAT32) {
if (Verbose)
"%d bytes.\n"), rdirsize);
if (!Notreally) {
exit(4);
}
}
}
/*
* Now write anything that needs to be in the file space.
*/
if (bootblksize > BPSEC) {
if (Verbose)
"boot block.\n"));
if (!Notreally)
}
if (MakeFAT32) {
if (Verbose)
"%d bytes.\n"), rdirsize);
if (!Notreally) {
exit(4);
}
}
}
if (fffd >= 0) {
if (Verbose)
if (!Notreally)
}
}
static
char *LegalOpts[] = {
#define NFLAG 0
"N",
"v",
"r",
"h",
"s",
"S",
"b",
"B",
"i",
"size",
"nsect",
"ntrack",
"spc",
"fat",
"f",
"d",
"nofdisk",
"reserve",
"hidden",
};
static
void
{
usage();
exit(2);
}
static
void
{
usage();
exit(3);
}
static
void
{
char *value;
int c;
while (*optsstr != '\0') {
case NFLAG:
Notreally++;
break;
case VFLAG:
Verbose++;
break;
case RFLAG:
Firstfileattr |= 0x01;
break;
case HFLAG:
Firstfileattr |= 0x02;
break;
case SFLAG:
Firstfileattr |= 0x04;
break;
case SUNFLAG:
SunBPBfields = 1;
break;
case LABFLAG:
missing_arg(LegalOpts[c]);
} else {
}
break;
case BTRFLAG:
missing_arg(LegalOpts[c]);
} else {
}
break;
case INITFLAG:
missing_arg(LegalOpts[c]);
} else {
}
break;
case SZFLAG:
missing_arg(LegalOpts[c]);
} else {
GetSize = 0;
}
break;
case SECTFLAG:
missing_arg(LegalOpts[c]);
} else {
GetSPT = 0;
}
break;
case TRKFLAG:
missing_arg(LegalOpts[c]);
} else {
GetTPC = 0;
}
break;
case SPCFLAG:
missing_arg(LegalOpts[c]);
} else {
GetSPC = 0;
}
break;
case BPFFLAG:
missing_arg(LegalOpts[c]);
} else {
GetBPF = 0;
}
break;
case NOFDISKFLAG:
DontUseFdisk = 1;
break;
case RESRVFLAG:
missing_arg(LegalOpts[c]);
} else {
GetResrvd = 0;
}
break;
case HIDDENFLAG:
missing_arg(LegalOpts[c]);
} else {
GetOffset = 0;
}
break;
case FFLAG:
missing_arg(LegalOpts[c]);
} else {
Outputtofile = 1;
}
break;
case DFLAG:
missing_arg(LegalOpts[c]);
} else {
}
break;
default:
break;
}
}
}
static
void
{
if (GetFsParams) {
usage();
return;
}
if (DontUseFdisk && GetOffset) {
/* Set default relative offset of zero */
RelOffset = 0;
}
if (BitsPerFAT == 32)
MakeFAT32 = 1;
usage();
} else if (Outputtofile && !DiskName) {
usage();
usage();
} else if (SunBPBfields && !BootBlkFn) {
gettext("Use of the 'S' option requires that\n"
"the 'B=' option also be used.\n\n"));
usage();
gettext("Use of the 'r', 'h', or 's' options requires\n"
"that the 'i=' option also be used.\n\n"));
usage();
} else if (!GetOffset && !DontUseFdisk) {
gettext("Use of the 'hidden' option requires that\n"
"the 'nofdisk' option also be used.\n\n"));
usage();
} else if (DontUseFdisk && GetSize) {
gettext("Use of the 'nofdisk' option requires that\n"
"the 'size=' option also be used.\n\n"));
usage();
} else if (!GetBPF &&
" Must be 12, 16 or 32.\n"));
exit(2);
"power of 2 between 1 and 128.\n"));
exit(2);
gettext("Invalid number of reserved sectors. "
"Must be at least 1 but\nno larger than 65535."));
exit(2);
gettext("Invalid number of reserved sectors. "
"Must be at least 32 but\nno larger than 65535."));
exit(2);
usage();
}
}
int
{
char *string;
int fd;
int c;
#if !defined(TEXT_DOMAIN)
#endif
(void) textdomain(TEXT_DOMAIN);
switch (c) {
case 'F':
usage();
break;
case 'V':
{
char *opt_text;
int opt_count;
gettext("mkfs -F pcfs "));
opt_count++) {
if (opt_text)
" %s ", opt_text);
}
}
break;
case 'm':
GetFsParams++;
break;
case 'o':
break;
}
}
if (!Outputtofile)
if (GetFsParams) {
} else {
if (ask_nicely(DiskName))
FirstFn, &dskparamblk);
}
return (0);
}