Apply revisions 1.23 and 1.24 from FreeBSD to autocalculate the

necessary geometry when creating a file system directly to a file.

In addition, when creating, do not complain about the file not
being char special and do not try to execute device ioctl's on it.
This commit is contained in:
pooka 2009-03-26 08:39:24 +00:00
parent 02040931ba
commit 32852ecef0
2 changed files with 153 additions and 17 deletions

View File

@ -1,4 +1,4 @@
.\" $NetBSD: newfs_msdos.8,v 1.15 2006/11/25 12:29:33 scw Exp $
.\" $NetBSD: newfs_msdos.8,v 1.16 2009/03/26 08:39:24 pooka Exp $
.\"
.\" Copyright (c) 1998 Robert Nordier
.\" All rights reserved.
@ -27,7 +27,7 @@
.\"
.\" From: $FreeBSD: src/sbin/newfs_msdos/newfs_msdos.8,v 1.13 2001/08/14 10:01:48 ru Exp $
.\"
.Dd November 25, 2006
.Dd March 26, 2009
.Dt NEWFS_MSDOS 8
.Os
.Sh NAME
@ -36,7 +36,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
@ -61,7 +63,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
@ -73,8 +75,23 @@ The options are as follow:
.Bl -tag -width indent
.It Fl N
Don't 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
@ -101,6 +118,9 @@ per cluster (see below).
.It Fl c Ar cluster-size
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
@ -144,6 +164,15 @@ a line will be written to the standard error output indicating
the name of the device currently being formatted, the sector
number being written, and the total number of sectors to be written.
.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.
@ -188,6 +217,11 @@ Create a standard 1.44M file system, with volume label
.Ar foo ,
on
.Pa /dev/rfd0a .
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 DIAGNOSTICS
Exit status is 0 on success and 1 on error.
.Sh SEE ALSO

View File

@ -1,4 +1,4 @@
/* $NetBSD: newfs_msdos.c,v 1.30 2009/02/17 00:16:35 christos Exp $ */
/* $NetBSD: newfs_msdos.c,v 1.31 2009/03/26 08:39:24 pooka Exp $ */
/*
* Copyright (c) 1998 Robert Nordier
@ -33,7 +33,7 @@
static const char rcsid[] =
"$FreeBSD: src/sbin/newfs_msdos/newfs_msdos.c,v 1.15 2000/10/10 01:49:37 wollman Exp $";
#else
__RCSID("$NetBSD: newfs_msdos.c,v 1.30 2009/02/17 00:16:35 christos Exp $");
__RCSID("$NetBSD: newfs_msdos.c,v 1.31 2009/03/26 08:39:24 pooka Exp $");
#endif
#endif /* not lint */
@ -229,10 +229,11 @@ static int got_siginfo = 0; /* received a SIGINFO */
static void check_mounted(const char *, mode_t);
static void getstdfmt(const char *, struct bpb *);
static void getbpbinfo(int, const char *, const char *, int, struct bpb *);
static void getbpbinfo(int, const char *, const char *, int, struct bpb *, 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);
@ -245,7 +246,7 @@ static void infohandler(int sig);
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;
@ -268,15 +269,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") &&
@ -355,19 +363,33 @@ main(int argc, char *argv[])
if (argc < 1 || argc > 2)
usage();
fname = *argv++;
if (!strchr(fname, '/')) {
if (!strchr(fname, '/') && !opt_create) {
snprintf(buf, sizeof(buf), "%sr%s", _PATH_DEV, fname);
if (!(fname = strdup(buf)))
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);
if (!S_ISCHR(sb.st_mode) && !opt_create)
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);
@ -386,8 +408,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)))
getbpbinfo(fd, fname, dtype, oflag, &bpb);
if (!(opt_f || (opt_h && opt_u && opt_S && opt_s && oflag))) {
off_t delta;
getbpbinfo(fd, fname, dtype, oflag, &bpb, opt_create != 0);
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)
@ -606,7 +649,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) {
@ -755,7 +798,7 @@ getstdfmt(const char *fmt, struct bpb *bpb)
*/
static void
getbpbinfo(int fd, const char *fname, const char *dtype, int oflag,
struct bpb *bpb)
struct bpb *bpb, int create)
{
struct disk_geom geo;
struct dkwedge_info dkw;
@ -781,8 +824,17 @@ getbpbinfo(int fd, const char *fname, const char *dtype, int oflag,
}
if (((part != -1) && ((!oflag && part != -1) || !bpb->bsec)) ||
!bpb->bps || !bpb->spt || !bpb->hds) {
if (getdiskinfo(fname, fd, NULL, &geo, &dkw) == -1)
errx(1, "Can't read disk label for `%s'", fname);
if (create || getdiskinfo(fname, fd, NULL, &geo, &dkw) == -1) {
struct stat st;
if (fstat(fd, &st) == -1)
errx(1, "Can't get disk size for `%s'", fname);
/* create a fake geometry for a file image */
geo.dg_secsize = 512;
geo.dg_nsectors = 63;
geo.dg_ntracks = 255;
dkw.dkw_size = st.st_size / geo.dg_secsize;
}
if (!bpb->bps)
bpb->bps = ckgeom(fname, geo.dg_secsize, "bytes/sector");
@ -861,6 +913,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.
*/