diff --git a/sbin/newfs_msdos/newfs_msdos.8 b/sbin/newfs_msdos/newfs_msdos.8 index 0057bf5fd48c..213b09dad8ee 100644 --- a/sbin/newfs_msdos/newfs_msdos.8 +++ b/sbin/newfs_msdos/newfs_msdos.8 @@ -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 , diff --git a/sbin/newfs_msdos/newfs_msdos.c b/sbin/newfs_msdos/newfs_msdos.c index a29448c3a699..b95b6e49dc59 100644 --- a/sbin/newfs_msdos/newfs_msdos.c +++ b/sbin/newfs_msdos/newfs_msdos.c @@ -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. */