Author: luigi
Date: Wed Dec  3 18:22:36 2008
New Revision: 185587
URL: http://svn.freebsd.org/changeset/base/185587

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

Modified:
  head/sbin/newfs_msdos/newfs_msdos.8
  head/sbin/newfs_msdos/newfs_msdos.c

Modified: head/sbin/newfs_msdos/newfs_msdos.8
==============================================================================
--- head/sbin/newfs_msdos/newfs_msdos.8 Wed Dec  3 17:54:09 2008        
(r185586)
+++ head/sbin/newfs_msdos/newfs_msdos.8 Wed Dec  3 18:22:36 2008        
(r185587)
@@ -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
 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 th
 .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 .
+Create a standard 1.44M file system, with volume label
+.Ar foo ,
+on
+.Pa /dev/fd0 :
 .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 .
+Create a 30MB image file, with the FAT partition starting
+63 sectors within the image file:
+.Bd -literal -offset indent
+newfs_msdos -C 30M [EMAIL PROTECTED] ./somefile
+.Ed
 .Sh SEE ALSO
 .Xr disktab 5 ,
 .Xr disklabel 8 ,

Modified: head/sbin/newfs_msdos/newfs_msdos.c
==============================================================================
--- head/sbin/newfs_msdos/newfs_msdos.c Wed Dec  3 17:54:09 2008        
(r185586)
+++ head/sbin/newfs_msdos/newfs_msdos.c Wed Dec  3 18:22:36 2008        
(r185587)
@@ -219,6 +219,7 @@ static void getdiskinfo(int, const char 
 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, c
        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) {
@@ -833,6 +875,56 @@ argtou(const char *arg, u_int lo, u_int 
 }
 
 /*
+ * 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
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "[EMAIL PROTECTED]"

Reply via email to