Module Name:    src
Committed By:   pooka
Date:           Thu Mar 26 08:39:24 UTC 2009

Modified Files:
        src/sbin/newfs_msdos: newfs_msdos.8 newfs_msdos.c

Log Message:
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.


To generate a diff of this commit:
cvs rdiff -u -r1.15 -r1.16 src/sbin/newfs_msdos/newfs_msdos.8
cvs rdiff -u -r1.30 -r1.31 src/sbin/newfs_msdos/newfs_msdos.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sbin/newfs_msdos/newfs_msdos.8
diff -u src/sbin/newfs_msdos/newfs_msdos.8:1.15 src/sbin/newfs_msdos/newfs_msdos.8:1.16
--- src/sbin/newfs_msdos/newfs_msdos.8:1.15	Sat Nov 25 12:29:33 2006
+++ src/sbin/newfs_msdos/newfs_msdos.8	Thu Mar 26 08:39:24 2009
@@ -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 @@
 .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 @@
 .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 @@
 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 @@
 .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

Index: src/sbin/newfs_msdos/newfs_msdos.c
diff -u src/sbin/newfs_msdos/newfs_msdos.c:1.30 src/sbin/newfs_msdos/newfs_msdos.c:1.31
--- src/sbin/newfs_msdos/newfs_msdos.c:1.30	Tue Feb 17 00:16:35 2009
+++ src/sbin/newfs_msdos/newfs_msdos.c	Thu Mar 26 08:39:24 2009
@@ -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 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 @@
 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 @@
     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 @@
     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 @@
 	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 @@
 		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 @@
  */
 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 @@
     }
     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");
 
@@ -862,6 +914,56 @@
 }
 
 /*
+ * 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.
  */
 static int

Reply via email to