Some useful operational extensions to newfs_msdos, especially

when preparing images for emulators or flash devices:

+ option '-C size' to create the underlying image file with given size.
  Saves doing a 'dd' before, and especially it creates a sparse file

+ option '-@ offset' to build the FAT image at the specified offset
  in the image file or device;

+ make the cluster size adaptive on the filesystem size.
  Previously the default was 4k which is really unconvenient with
  large media; now it goes from 512 bytes to 32k depending on
  filesystem size (i still need to check whether it makes sense
  to go further up, to 64k or above);

+ fix default geometry when not specified on the command line,
  use 63 sectors/255 heads by default.
  Also trim the size so it exactly a multiple of a track, to avoid
  complaints in some filesystem code.

+ document all the above, plus some manual page clarifications.

MFC after:	4 weeks
This commit is contained in:
Luigi Rizzo 2008-12-03 18:22:36 +00:00
parent 7d464bbf38
commit b87d1601b6
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=185587
2 changed files with 151 additions and 17 deletions

View File

@ -34,7 +34,9 @@
.Sh SYNOPSIS
.Nm
.Op Fl N
.Op Fl @ Ar offset
.Op Fl B Ar boot
.Op Fl C Ar create-size
.Op Fl F Ar FAT-type
.Op Fl I Ar volid
.Op Fl L Ar label
@ -59,7 +61,7 @@
.Sh DESCRIPTION
The
.Nm
utility creates a FAT12, FAT16, or FAT32 file system on device
utility creates a FAT12, FAT16, or FAT32 file system on device or file named
.Ar special ,
using
.Xr disktab 5
@ -67,16 +69,39 @@ entry
.Ar disktype
to determine geometry, if required.
.Pp
If
.Ar special
does not contain a
.Ar / ,
it is assumed to be a device name and
.Ar /dev
is prepended to the name to construct the actual device name.
To work a file in the current directory use
.Ar ./filename
.Pp
The options are as follow:
.Bl -tag -width indent
.It Fl N
Do not create a file system: just print out parameters.
.It Fl @ Ar offset
Build the filesystem at the specified offset in bytes in the device or file.
A suffix s, k, m, g (lower or upper case)
appended to the offset specifies that the
number is in sectors, kilobytes, megabytes or gigabytes, respectively.
.It Fl B Ar boot
Get bootstrap from file.
.It Fl C Ar create-size
Create the image file with the specified size. A suffix character appended
to the size is interpreted as for the
.Fl @
option. The file is created by truncating any existing file with the
same name, seeking just before the required size and writing
a single 0 byte. As a consequence, the space occupied on disk
may be smaller than the size specified as a parameter.
.It Fl F Ar FAT-type
FAT type (one of 12, 16, or 32).
.It Fl I Ar volid
Volume ID.
Volume ID, a 32 bit number in decimal or hexadecimal (0x...) format.
.It Fl L Ar label
Volume label (up to 11 characters).
The label should consist of
@ -99,6 +124,9 @@ acceptable number of sectors per cluster (see below).
Sectors per cluster.
Acceptable values are powers of 2 in the range
1 through 128.
If the block or cluster size are not specified, the code
uses a cluster between 512 bytes and 32K depending on
the filesystem size.
.It Fl e Ar dirents
Number of root directory entries (FAT12 and FAT16 only).
.It Fl f Ar format
@ -132,6 +160,15 @@ File system size.
Number of sectors per track.
.El
.Sh NOTES
If some parameters (e.g. size, number of sectors, etc.) are not specified
through options or disktype, the program tries to generate them
automatically. In particular, the size is determined as the
device or file size minus the offset specified with the
.Fl @
option. When the geometry is not available, it is assumed to be
63 sectors, 255 heads. The size is then rounded to become
a multiple of the track size and avoid complaints by some filesystem code.
.Pp
FAT file system parameters occupy a "Boot Sector BPB (BIOS Parameter
Block)" in the first of the "reserved" sectors which precede the actual
file system.
@ -167,20 +204,25 @@ The maximum file size is 4GB, even if the file system itself is bigger.
.Sh EXIT STATUS
Exit status is 0 on success and 1 on error.
.Sh EXAMPLES
Create a file system, using default parameters, on
.Pa /dev/ad0s1 :
.Bd -literal -offset indent
newfs_msdos /dev/ad0s1
.Ed
.Pp
Create a file system, using default parameters, on
.Pa /dev/ad0s1 .
.Bd -literal -offset indent
newfs_msdos -f 1440 -L foo fd0
.Ed
.Pp
Create a standard 1.44M file system, with volume label
.Ar foo ,
on
.Pa /dev/fd0 .
.Pa /dev/fd0 :
.Bd -literal -offset indent
newfs_msdos -f 1440 -L foo fd0
.Ed
.Pp
Create a 30MB image file, with the FAT partition starting
63 sectors within the image file:
.Bd -literal -offset indent
newfs_msdos -C 30M -@63s ./somefile
.Ed
.Sh SEE ALSO
.Xr disktab 5 ,
.Xr disklabel 8 ,

View File

@ -219,6 +219,7 @@ static void getdiskinfo(int, const char *, const char *, int,
static void print_bpb(struct bpb *);
static u_int ckgeom(const char *, u_int, const char *);
static u_int argtou(const char *, u_int, u_int, const char *);
static off_t argtooff(const char *, const char *);
static int oklabel(const char *);
static void mklabel(u_int8_t *, const char *);
static void setstr(u_int8_t *, const char *, size_t);
@ -230,7 +231,7 @@ static void usage(void);
int
main(int argc, char *argv[])
{
static char opts[] = "NB:F:I:L:O:S:a:b:c:e:f:h:i:k:m:n:o:r:s:u:";
static char opts[] = "@:NB:C:F:I:L:O:S:a:b:c:e:f:h:i:k:m:n:o:r:s:u:";
static const char *opt_B, *opt_L, *opt_O, *opt_f;
static u_int opt_F, opt_I, opt_S, opt_a, opt_b, opt_c, opt_e;
static u_int opt_h, opt_i, opt_k, opt_m, opt_n, opt_o, opt_r;
@ -253,15 +254,22 @@ main(int argc, char *argv[])
time_t now;
u_int fat, bss, rds, cls, dir, lsn, x, x1, x2;
int ch, fd, fd1;
static off_t opt_create=0, opt_ofs=0;
while ((ch = getopt(argc, argv, opts)) != -1)
switch (ch) {
case '@':
opt_ofs = argtooff(optarg, "offset");
break;
case 'N':
opt_N = 1;
break;
case 'B':
opt_B = optarg;
break;
case 'C':
opt_create = argtooff(optarg, "create size");
break;
case 'F':
if (strcmp(optarg, "12") &&
strcmp(optarg, "16") &&
@ -346,13 +354,27 @@ main(int argc, char *argv[])
err(1, NULL);
}
dtype = *argv;
if ((fd = open(fname, opt_N ? O_RDONLY : O_RDWR)) == -1 ||
if (opt_create) {
off_t pos;
if (opt_N)
errx(1, "create (-C) is incompatible with -N");
fd = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0644);
if (fd == -1)
errx(1, "failed to create %s", fname);
pos = lseek(fd, opt_create - 1, SEEK_SET);
if (write(fd, "\0", 1) != 1)
errx(1, "failed to initialize %lld bytes", opt_create);
pos = lseek(fd, 0, SEEK_SET);
} else if ((fd = open(fname, opt_N ? O_RDONLY : O_RDWR)) == -1 ||
fstat(fd, &sb))
err(1, "%s", fname);
if (!opt_N)
check_mounted(fname, sb.st_mode);
if (!S_ISCHR(sb.st_mode))
warnx("warning: %s is not a character device", fname);
warnx("warning, %s is not a character device", fname);
if (opt_ofs && opt_ofs != lseek(fd, opt_ofs, SEEK_SET))
errx(1, "cannot seek to %lld", opt_ofs);
memset(&bpb, 0, sizeof(bpb));
if (opt_f) {
getstdfmt(opt_f, &bpb);
@ -371,8 +393,29 @@ main(int argc, char *argv[])
bpb.bsec = opt_s;
if (oflag)
bpb.hid = opt_o;
if (!(opt_f || (opt_h && opt_u && opt_S && opt_s && oflag)))
if (!(opt_f || (opt_h && opt_u && opt_S && opt_s && oflag))) {
off_t delta;
getdiskinfo(fd, fname, dtype, oflag, &bpb);
bpb.bsec -= (opt_ofs / bpb.bps);
delta = bpb.bsec % bpb.spt;
if (delta != 0) {
warnx("trim %d sectors to adjust to a multiple of %d",
(int)delta, bpb.spt);
bpb.bsec -= delta;
}
if (bpb.spc == 0) { /* set defaults */
if (bpb.bsec <= 6000) /* about 3MB -> 512 bytes */
bpb.spc = 1;
else if (bpb.bsec <= (1<<17)) /* 64M -> 4k */
bpb.spc = 8;
else if (bpb.bsec <= (1<<19)) /* 256M -> 8k */
bpb.spc = 16;
else if (bpb.bsec <= (1<<21)) /* 1G -> 16k */
bpb.spc = 32;
else
bpb.spc = 64; /* otherwise 32k */
}
}
if (!powerof2(bpb.bps))
errx(1, "bytes/sector (%u) is not a power of 2", bpb.bps);
if (bpb.bps < MINBPS)
@ -561,7 +604,7 @@ main(int argc, char *argv[])
fat == 32 && bpb.bkbs != MAXU16 &&
bss <= bpb.bkbs && x >= bpb.bkbs) {
x -= bpb.bkbs;
if (!x && lseek(fd1, 0, SEEK_SET))
if (!x && lseek(fd1, opt_ofs, SEEK_SET))
err(1, "%s", bname);
}
if (opt_B && x < bss) {
@ -728,14 +771,13 @@ getdiskinfo(int fd, const char *fname, const char *dtype, __unused int oflag,
if (ioctl(fd, DIOCGMEDIASIZE, &ms) == -1) {
struct stat st;
bzero(&st, sizeof(st));
if (fstat(fd, &st))
err(1, "Cannot get disk size");
/* create a fake geometry for a file image */
ms = st.st_size;
dlp.d_secsize = 512;
dlp.d_nsectors = 64;
dlp.d_ntracks = 32;
dlp.d_nsectors = 63;
dlp.d_ntracks = 255;
dlp.d_secperunit = ms / dlp.d_secsize;
lp = &dlp;
} else if (ioctl(fd, FD_GTYPE, &type) != -1) {
@ -832,6 +874,56 @@ argtou(const char *arg, u_int lo, u_int hi, const char *msg)
return x;
}
/*
* Same for off_t, with optional skmgpP suffix
*/
static off_t
argtooff(const char *arg, const char *msg)
{
char *s;
off_t x;
x = strtoll(arg, &s, 0);
/* allow at most one extra char */
if (errno || x < 0 || (s[0] && s[1]) )
errx(1, "%s: bad %s", arg, msg);
if (*s) { /* the extra char is the multiplier */
switch (*s) {
default:
errx(1, "%s: bad %s", arg, msg);
/* notreached */
case 's': /* sector */
case 'S':
x <<= 9; /* times 512 */
break;
case 'k': /* kilobyte */
case 'K':
x <<= 10; /* times 1024 */
break;
case 'm': /* megabyte */
case 'M':
x <<= 20; /* times 1024*1024 */
break;
case 'g': /* gigabyte */
case 'G':
x <<= 30; /* times 1024*1024*1024 */
break;
case 'p': /* partition start */
case 'P': /* partition start */
case 'l': /* partition length */
case 'L': /* partition length */
errx(1, "%s: not supported yet %s", arg, msg);
/* notreached */
}
}
return x;
}
/*
* Check a volume label.
*/