Home | History | Annotate | Line # | Download | only in newfs_msdos
newfs_msdos.c revision 1.1.1.1
      1 /*
      2  * Copyright (c) 1998 Robert Nordier
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in
     12  *    the documentation and/or other materials provided with the
     13  *    distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
     16  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY
     19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
     21  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
     23  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
     25  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #ifndef lint
     29 static const char rcsid[] =
     30   "$FreeBSD: src/sbin/newfs_msdos/newfs_msdos.c,v 1.15 2000/10/10 01:49:37 wollman Exp $";
     31 #endif /* not lint */
     32 
     33 #include <sys/param.h>
     34 #include <sys/diskslice.h>
     35 #include <sys/disklabel.h>
     36 #include <sys/mount.h>
     37 #include <sys/stat.h>
     38 #include <sys/time.h>
     39 
     40 #include <ctype.h>
     41 #include <err.h>
     42 #include <errno.h>
     43 #include <fcntl.h>
     44 #include <paths.h>
     45 #include <stdio.h>
     46 #include <stdlib.h>
     47 #include <string.h>
     48 #include <time.h>
     49 #include <unistd.h>
     50 
     51 #define MAXU16	  0xffff	/* maximum unsigned 16-bit quantity */
     52 #define BPN	  4		/* bits per nibble */
     53 #define NPB	  2		/* nibbles per byte */
     54 
     55 #define DOSMAGIC  0xaa55	/* DOS magic number */
     56 #define MINBPS	  128		/* minimum bytes per sector */
     57 #define MAXSPC	  128		/* maximum sectors per cluster */
     58 #define MAXNFT	  16		/* maximum number of FATs */
     59 #define DEFBLK	  4096		/* default block size */
     60 #define DEFBLK16  2048		/* default block size FAT16 */
     61 #define DEFRDE	  512		/* default root directory entries */
     62 #define RESFTE	  2		/* reserved FAT entries */
     63 #define MINCLS12  1		/* minimum FAT12 clusters */
     64 #define MINCLS16  0x1000	/* minimum FAT16 clusters */
     65 #define MINCLS32  2		/* minimum FAT32 clusters */
     66 #define MAXCLS12  0xfed 	/* maximum FAT12 clusters */
     67 #define MAXCLS16  0xfff5	/* maximum FAT16 clusters */
     68 #define MAXCLS32  0xffffff5	/* maximum FAT32 clusters */
     69 
     70 #define mincls(fat)  ((fat) == 12 ? MINCLS12 :	\
     71 		      (fat) == 16 ? MINCLS16 :	\
     72 				    MINCLS32)
     73 
     74 #define maxcls(fat)  ((fat) == 12 ? MAXCLS12 :	\
     75 		      (fat) == 16 ? MAXCLS16 :	\
     76 				    MAXCLS32)
     77 
     78 #define mk1(p, x)				\
     79     (p) = (u_int8_t)(x)
     80 
     81 #define mk2(p, x)				\
     82     (p)[0] = (u_int8_t)(x),			\
     83     (p)[1] = (u_int8_t)((x) >> 010)
     84 
     85 #define mk4(p, x)				\
     86     (p)[0] = (u_int8_t)(x),			\
     87     (p)[1] = (u_int8_t)((x) >> 010),		\
     88     (p)[2] = (u_int8_t)((x) >> 020),		\
     89     (p)[3] = (u_int8_t)((x) >> 030)
     90 
     91 #define argto1(arg, lo, msg)  argtou(arg, lo, 0xff, msg)
     92 #define argto2(arg, lo, msg)  argtou(arg, lo, 0xffff, msg)
     93 #define argto4(arg, lo, msg)  argtou(arg, lo, 0xffffffff, msg)
     94 #define argtox(arg, lo, msg)  argtou(arg, lo, UINT_MAX, msg)
     95 
     96 struct bs {
     97     u_int8_t jmp[3];		/* bootstrap entry point */
     98     u_int8_t oem[8];		/* OEM name and version */
     99 };
    100 
    101 struct bsbpb {
    102     u_int8_t bps[2];		/* bytes per sector */
    103     u_int8_t spc;		/* sectors per cluster */
    104     u_int8_t res[2];		/* reserved sectors */
    105     u_int8_t nft;		/* number of FATs */
    106     u_int8_t rde[2];		/* root directory entries */
    107     u_int8_t sec[2];		/* total sectors */
    108     u_int8_t mid;		/* media descriptor */
    109     u_int8_t spf[2];		/* sectors per FAT */
    110     u_int8_t spt[2];		/* sectors per track */
    111     u_int8_t hds[2];		/* drive heads */
    112     u_int8_t hid[4];		/* hidden sectors */
    113     u_int8_t bsec[4];		/* big total sectors */
    114 };
    115 
    116 struct bsxbpb {
    117     u_int8_t bspf[4];		/* big sectors per FAT */
    118     u_int8_t xflg[2];		/* FAT control flags */
    119     u_int8_t vers[2];		/* file system version */
    120     u_int8_t rdcl[4];		/* root directory start cluster */
    121     u_int8_t infs[2];		/* file system info sector */
    122     u_int8_t bkbs[2];		/* backup boot sector */
    123     u_int8_t rsvd[12];		/* reserved */
    124 };
    125 
    126 struct bsx {
    127     u_int8_t drv;		/* drive number */
    128     u_int8_t rsvd;		/* reserved */
    129     u_int8_t sig;		/* extended boot signature */
    130     u_int8_t volid[4];		/* volume ID number */
    131     u_int8_t label[11]; 	/* volume label */
    132     u_int8_t type[8];		/* file system type */
    133 };
    134 
    135 struct de {
    136     u_int8_t namext[11];	/* name and extension */
    137     u_int8_t attr;		/* attributes */
    138     u_int8_t rsvd[10];		/* reserved */
    139     u_int8_t time[2];		/* creation time */
    140     u_int8_t date[2];		/* creation date */
    141     u_int8_t clus[2];		/* starting cluster */
    142     u_int8_t size[4];		/* size */
    143 };
    144 
    145 struct bpb {
    146     u_int bps;			/* bytes per sector */
    147     u_int spc;			/* sectors per cluster */
    148     u_int res;			/* reserved sectors */
    149     u_int nft;			/* number of FATs */
    150     u_int rde;			/* root directory entries */
    151     u_int sec;			/* total sectors */
    152     u_int mid;			/* media descriptor */
    153     u_int spf;			/* sectors per FAT */
    154     u_int spt;			/* sectors per track */
    155     u_int hds;			/* drive heads */
    156     u_int hid;			/* hidden sectors */
    157     u_int bsec; 		/* big total sectors */
    158     u_int bspf; 		/* big sectors per FAT */
    159     u_int rdcl; 		/* root directory start cluster */
    160     u_int infs; 		/* file system info sector */
    161     u_int bkbs; 		/* backup boot sector */
    162 };
    163 
    164 static struct {
    165     const char *name;
    166     struct bpb bpb;
    167 } stdfmt[] = {
    168     {"160",  {512, 1, 1, 2,  64,  320, 0xfe, 1,  8, 1}},
    169     {"180",  {512, 1, 1, 2,  64,  360, 0xfc, 2,  9, 1}},
    170     {"320",  {512, 2, 1, 2, 112,  640, 0xff, 1,  8, 2}},
    171     {"360",  {512, 2, 1, 2, 112,  720, 0xfd, 2,  9, 2}},
    172     {"640",  {512, 2, 1, 2, 112, 1280, 0xfb, 2,  8, 2}},
    173     {"720",  {512, 2, 1, 2, 112, 1440, 0xf9, 3,  9, 2}},
    174     {"1200", {512, 1, 1, 2, 224, 2400, 0xf9, 7, 15, 2}},
    175     {"1232", {1024,1, 1, 2, 192, 1232, 0xfe, 2,  8, 2}},
    176     {"1440", {512, 1, 1, 2, 224, 2880, 0xf0, 9, 18, 2}},
    177     {"2880", {512, 2, 1, 2, 240, 5760, 0xf0, 9, 36, 2}}
    178 };
    179 
    180 static u_int8_t bootcode[] = {
    181     0xfa,			/* cli		    */
    182     0x31, 0xc0, 		/* xor	   ax,ax    */
    183     0x8e, 0xd0, 		/* mov	   ss,ax    */
    184     0xbc, 0x00, 0x7c,		/* mov	   sp,7c00h */
    185     0xfb,			/* sti		    */
    186     0x8e, 0xd8, 		/* mov	   ds,ax    */
    187     0xe8, 0x00, 0x00,		/* call    $ + 3    */
    188     0x5e,			/* pop	   si	    */
    189     0x83, 0xc6, 0x19,		/* add	   si,+19h  */
    190     0xbb, 0x07, 0x00,		/* mov	   bx,0007h */
    191     0xfc,			/* cld		    */
    192     0xac,			/* lodsb	    */
    193     0x84, 0xc0, 		/* test    al,al    */
    194     0x74, 0x06, 		/* jz	   $ + 8    */
    195     0xb4, 0x0e, 		/* mov	   ah,0eh   */
    196     0xcd, 0x10, 		/* int	   10h	    */
    197     0xeb, 0xf5, 		/* jmp	   $ - 9    */
    198     0x30, 0xe4, 		/* xor	   ah,ah    */
    199     0xcd, 0x16, 		/* int	   16h	    */
    200     0xcd, 0x19, 		/* int	   19h	    */
    201     0x0d, 0x0a,
    202     'N', 'o', 'n', '-', 's', 'y', 's', 't',
    203     'e', 'm', ' ', 'd', 'i', 's', 'k',
    204     0x0d, 0x0a,
    205     'P', 'r', 'e', 's', 's', ' ', 'a', 'n',
    206     'y', ' ', 'k', 'e', 'y', ' ', 't', 'o',
    207     ' ', 'r', 'e', 'b', 'o', 'o', 't',
    208     0x0d, 0x0a,
    209     0
    210 };
    211 
    212 static void check_mounted(const char *, mode_t);
    213 static void getstdfmt(const char *, struct bpb *);
    214 static void getdiskinfo(int, const char *, const char *, int,
    215 			struct bpb *);
    216 static void print_bpb(struct bpb *);
    217 static u_int ckgeom(const char *, u_int, const char *);
    218 static u_int argtou(const char *, u_int, u_int, const char *);
    219 static int oklabel(const char *);
    220 static void mklabel(u_int8_t *, const char *);
    221 static void setstr(u_int8_t *, const char *, size_t);
    222 static void usage(void);
    223 
    224 /*
    225  * Construct a FAT12, FAT16, or FAT32 file system.
    226  */
    227 int
    228 main(int argc, char *argv[])
    229 {
    230     static char opts[] = "NB:F:I:L:O:S:a:b:c:e:f:h:i:k:m:n:o:r:s:u:";
    231     static const char *opt_B, *opt_L, *opt_O, *opt_f;
    232     static u_int opt_F, opt_I, opt_S, opt_a, opt_b, opt_c, opt_e;
    233     static u_int opt_h, opt_i, opt_k, opt_m, opt_n, opt_o, opt_r;
    234     static u_int opt_s, opt_u;
    235     static int opt_N;
    236     static int Iflag, mflag, oflag;
    237     char buf[MAXPATHLEN];
    238     struct stat sb;
    239     struct timeval tv;
    240     struct bpb bpb;
    241     struct tm *tm;
    242     struct bs *bs;
    243     struct bsbpb *bsbpb;
    244     struct bsxbpb *bsxbpb;
    245     struct bsx *bsx;
    246     struct de *de;
    247     u_int8_t *img;
    248     const char *fname, *dtype, *bname;
    249     ssize_t n;
    250     time_t now;
    251     u_int fat, bss, rds, cls, dir, lsn, x, x1, x2;
    252     int ch, fd, fd1;
    253 
    254     while ((ch = getopt(argc, argv, opts)) != -1)
    255 	switch (ch) {
    256 	case 'N':
    257 	    opt_N = 1;
    258 	    break;
    259 	case 'B':
    260 	    opt_B = optarg;
    261 	    break;
    262 	case 'F':
    263 	    if (strcmp(optarg, "12") &&
    264 		strcmp(optarg, "16") &&
    265 		strcmp(optarg, "32"))
    266 		errx(1, "%s: bad FAT type", optarg);
    267 	    opt_F = atoi(optarg);
    268 	    break;
    269 	case 'I':
    270 	    opt_I = argto4(optarg, 0, "volume ID");
    271 	    Iflag = 1;
    272 	    break;
    273 	case 'L':
    274 	    if (!oklabel(optarg))
    275 		errx(1, "%s: bad volume label", optarg);
    276 	    opt_L = optarg;
    277 	    break;
    278 	case 'O':
    279 	    if (strlen(optarg) > 8)
    280 		errx(1, "%s: bad OEM string", optarg);
    281 	    opt_O = optarg;
    282 	    break;
    283 	case 'S':
    284 	    opt_S = argto2(optarg, 1, "bytes/sector");
    285 	    break;
    286 	case 'a':
    287 	    opt_a = argto4(optarg, 1, "sectors/FAT");
    288 	    break;
    289 	case 'b':
    290 	    opt_b = argtox(optarg, 1, "block size");
    291 	    opt_c = 0;
    292 	    break;
    293 	case 'c':
    294 	    opt_c = argto1(optarg, 1, "sectors/cluster");
    295 	    opt_b = 0;
    296 	    break;
    297 	case 'e':
    298 	    opt_e = argto2(optarg, 1, "directory entries");
    299 	    break;
    300 	case 'f':
    301 	    opt_f = optarg;
    302 	    break;
    303 	case 'h':
    304 	    opt_h = argto2(optarg, 1, "drive heads");
    305 	    break;
    306 	case 'i':
    307 	    opt_i = argto2(optarg, 1, "info sector");
    308 	    break;
    309 	case 'k':
    310 	    opt_k = argto2(optarg, 1, "backup sector");
    311 	    break;
    312 	case 'm':
    313 	    opt_m = argto1(optarg, 0, "media descriptor");
    314 	    mflag = 1;
    315 	    break;
    316 	case 'n':
    317 	    opt_n = argto1(optarg, 1, "number of FATs");
    318 	    break;
    319 	case 'o':
    320 	    opt_o = argto4(optarg, 0, "hidden sectors");
    321 	    oflag = 1;
    322 	    break;
    323 	case 'r':
    324 	    opt_r = argto2(optarg, 1, "reserved sectors");
    325 	    break;
    326 	case 's':
    327 	    opt_s = argto4(optarg, 1, "file system size");
    328 	    break;
    329 	case 'u':
    330 	    opt_u = argto2(optarg, 1, "sectors/track");
    331 	    break;
    332 	default:
    333 	    usage();
    334 	}
    335     argc -= optind;
    336     argv += optind;
    337     if (argc < 1 || argc > 2)
    338 	usage();
    339     fname = *argv++;
    340     if (!strchr(fname, '/')) {
    341 	snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname);
    342 	if (!(fname = strdup(buf)))
    343 	    err(1, NULL);
    344     }
    345     dtype = *argv;
    346     if ((fd = open(fname, opt_N ? O_RDONLY : O_RDWR)) == -1 ||
    347 	fstat(fd, &sb))
    348 	err(1, "%s", fname);
    349     if (!opt_N)
    350 	check_mounted(fname, sb.st_mode);
    351     if (!S_ISCHR(sb.st_mode))
    352 	warnx("warning: %s is not a character device", fname);
    353     memset(&bpb, 0, sizeof(bpb));
    354     if (opt_f) {
    355 	getstdfmt(opt_f, &bpb);
    356 	bpb.bsec = bpb.sec;
    357 	bpb.sec = 0;
    358 	bpb.bspf = bpb.spf;
    359 	bpb.spf = 0;
    360     }
    361     if (opt_h)
    362 	bpb.hds = opt_h;
    363     if (opt_u)
    364 	bpb.spt = opt_u;
    365     if (opt_S)
    366 	bpb.bps = opt_S;
    367     if (opt_s)
    368 	bpb.bsec = opt_s;
    369     if (oflag)
    370 	bpb.hid = opt_o;
    371     if (!(opt_f || (opt_h && opt_u && opt_S && opt_s && oflag)))
    372 	getdiskinfo(fd, fname, dtype, oflag, &bpb);
    373     if (!powerof2(bpb.bps))
    374 	errx(1, "bytes/sector (%u) is not a power of 2", bpb.bps);
    375     if (bpb.bps < MINBPS)
    376 	errx(1, "bytes/sector (%u) is too small; minimum is %u",
    377 	     bpb.bps, MINBPS);
    378     if (!(fat = opt_F)) {
    379 	if (opt_f)
    380 	    fat = 12;
    381 	else if (!opt_e && (opt_i || opt_k))
    382 	    fat = 32;
    383     }
    384     if ((fat == 32 && opt_e) || (fat != 32 && (opt_i || opt_k)))
    385 	errx(1, "-%c is not a legal FAT%s option",
    386 	     fat == 32 ? 'e' : opt_i ? 'i' : 'k',
    387 	     fat == 32 ? "32" : "12/16");
    388     if (opt_f && fat == 32)
    389 	bpb.rde = 0;
    390     if (opt_b) {
    391 	if (!powerof2(opt_b))
    392 	    errx(1, "block size (%u) is not a power of 2", opt_b);
    393 	if (opt_b < bpb.bps)
    394 	    errx(1, "block size (%u) is too small; minimum is %u",
    395 		 opt_b, bpb.bps);
    396 	if (opt_b > bpb.bps * MAXSPC)
    397 	    errx(1, "block size (%u) is too large; maximum is %u",
    398 		 opt_b, bpb.bps * MAXSPC);
    399 	bpb.spc = opt_b / bpb.bps;
    400     }
    401     if (opt_c) {
    402 	if (!powerof2(opt_c))
    403 	    errx(1, "sectors/cluster (%u) is not a power of 2", opt_c);
    404 	bpb.spc = opt_c;
    405     }
    406     if (opt_r)
    407 	bpb.res = opt_r;
    408     if (opt_n) {
    409 	if (opt_n > MAXNFT)
    410 	    errx(1, "number of FATs (%u) is too large; maximum is %u",
    411 		 opt_n, MAXNFT);
    412 	bpb.nft = opt_n;
    413     }
    414     if (opt_e)
    415 	bpb.rde = opt_e;
    416     if (mflag) {
    417 	if (opt_m < 0xf0)
    418 	    errx(1, "illegal media descriptor (%#x)", opt_m);
    419 	bpb.mid = opt_m;
    420     }
    421     if (opt_a)
    422 	bpb.bspf = opt_a;
    423     if (opt_i)
    424 	bpb.infs = opt_i;
    425     if (opt_k)
    426 	bpb.bkbs = opt_k;
    427     bss = 1;
    428     bname = NULL;
    429     fd1 = -1;
    430     if (opt_B) {
    431 	bname = opt_B;
    432 	if (!strchr(bname, '/')) {
    433 	    snprintf(buf, sizeof(buf), "/boot/%s", bname);
    434 	    if (!(bname = strdup(buf)))
    435 		err(1, NULL);
    436 	}
    437 	if ((fd1 = open(bname, O_RDONLY)) == -1 || fstat(fd1, &sb))
    438 	    err(1, "%s", bname);
    439 	if (!S_ISREG(sb.st_mode) || sb.st_size % bpb.bps ||
    440 	    sb.st_size < bpb.bps || sb.st_size > bpb.bps * MAXU16)
    441 	    errx(1, "%s: inappropriate file type or format", bname);
    442 	bss = sb.st_size / bpb.bps;
    443     }
    444     if (!bpb.nft)
    445 	bpb.nft = 2;
    446     if (!fat) {
    447 	if (bpb.bsec < (bpb.res ? bpb.res : bss) +
    448 	    howmany((RESFTE + (bpb.spc ? MINCLS16 : MAXCLS12 + 1)) *
    449 		    ((bpb.spc ? 16 : 12) / BPN), bpb.bps * NPB) *
    450 	    bpb.nft +
    451 	    howmany(bpb.rde ? bpb.rde : DEFRDE,
    452 		    bpb.bps / sizeof(struct de)) +
    453 	    (bpb.spc ? MINCLS16 : MAXCLS12 + 1) *
    454 	    (bpb.spc ? bpb.spc : howmany(DEFBLK, bpb.bps)))
    455 	    fat = 12;
    456 	else if (bpb.rde || bpb.bsec <
    457 		 (bpb.res ? bpb.res : bss) +
    458 		 howmany((RESFTE + MAXCLS16) * 2, bpb.bps) * bpb.nft +
    459 		 howmany(DEFRDE, bpb.bps / sizeof(struct de)) +
    460 		 (MAXCLS16 + 1) *
    461 		 (bpb.spc ? bpb.spc : howmany(8192, bpb.bps)))
    462 	    fat = 16;
    463 	else
    464 	    fat = 32;
    465     }
    466     x = bss;
    467     if (fat == 32) {
    468 	if (!bpb.infs) {
    469 	    if (x == MAXU16 || x == bpb.bkbs)
    470 		errx(1, "no room for info sector");
    471 	    bpb.infs = x;
    472 	}
    473 	if (bpb.infs != MAXU16 && x <= bpb.infs)
    474 	    x = bpb.infs + 1;
    475 	if (!bpb.bkbs) {
    476 	    if (x == MAXU16)
    477 		errx(1, "no room for backup sector");
    478 	    bpb.bkbs = x;
    479 	} else if (bpb.bkbs != MAXU16 && bpb.bkbs == bpb.infs)
    480 	    errx(1, "backup sector would overwrite info sector");
    481 	if (bpb.bkbs != MAXU16 && x <= bpb.bkbs)
    482 	    x = bpb.bkbs + 1;
    483     }
    484     if (!bpb.res)
    485 	bpb.res = fat == 32 ? MAX(x, MAX(16384 / bpb.bps, 4)) : x;
    486     else if (bpb.res < x)
    487 	errx(1, "too few reserved sectors");
    488     if (fat != 32 && !bpb.rde)
    489 	bpb.rde = DEFRDE;
    490     rds = howmany(bpb.rde, bpb.bps / sizeof(struct de));
    491     if (!bpb.spc)
    492 	for (bpb.spc = howmany(fat == 16 ? DEFBLK16 : DEFBLK, bpb.bps);
    493 	     bpb.spc < MAXSPC &&
    494 	     bpb.res +
    495 	     howmany((RESFTE + maxcls(fat)) * (fat / BPN),
    496 		     bpb.bps * NPB) * bpb.nft +
    497 	     rds +
    498 	     (u_int64_t)(maxcls(fat) + 1) * bpb.spc <= bpb.bsec;
    499 	     bpb.spc <<= 1);
    500     if (fat != 32 && bpb.bspf > MAXU16)
    501 	errx(1, "too many sectors/FAT for FAT12/16");
    502     x1 = bpb.res + rds;
    503     x = bpb.bspf ? bpb.bspf : 1;
    504     if (x1 + (u_int64_t)x * bpb.nft > bpb.bsec)
    505 	errx(1, "meta data exceeds file system size");
    506     x1 += x * bpb.nft;
    507     x = (u_int64_t)(bpb.bsec - x1) * bpb.bps * NPB /
    508 	(bpb.spc * bpb.bps * NPB + fat / BPN * bpb.nft);
    509     x2 = howmany((RESFTE + MIN(x, maxcls(fat))) * (fat / BPN),
    510 		 bpb.bps * NPB);
    511     if (!bpb.bspf) {
    512 	bpb.bspf = x2;
    513 	x1 += (bpb.bspf - 1) * bpb.nft;
    514     }
    515     cls = (bpb.bsec - x1) / bpb.spc;
    516     x = (u_int64_t)bpb.bspf * bpb.bps * NPB / (fat / BPN) - RESFTE;
    517     if (cls > x)
    518 	cls = x;
    519     if (bpb.bspf < x2)
    520 	warnx("warning: sectors/FAT limits file system to %u clusters",
    521 	      cls);
    522     if (cls < mincls(fat))
    523 	errx(1, "%u clusters too few clusters for FAT%u, need %u", cls, fat,
    524 	    mincls(fat));
    525     if (cls > maxcls(fat)) {
    526 	cls = maxcls(fat);
    527 	bpb.bsec = x1 + (cls + 1) * bpb.spc - 1;
    528 	warnx("warning: FAT type limits file system to %u sectors",
    529 	      bpb.bsec);
    530     }
    531     printf("%s: %u sector%s in %u FAT%u cluster%s "
    532 	   "(%u bytes/cluster)\n", fname, cls * bpb.spc,
    533 	   cls * bpb.spc == 1 ? "" : "s", cls, fat,
    534 	   cls == 1 ? "" : "s", bpb.bps * bpb.spc);
    535     if (!bpb.mid)
    536 	bpb.mid = !bpb.hid ? 0xf0 : 0xf8;
    537     if (fat == 32)
    538 	bpb.rdcl = RESFTE;
    539     if (bpb.hid + bpb.bsec <= MAXU16) {
    540 	bpb.sec = bpb.bsec;
    541 	bpb.bsec = 0;
    542     }
    543     if (fat != 32) {
    544 	bpb.spf = bpb.bspf;
    545 	bpb.bspf = 0;
    546     }
    547     print_bpb(&bpb);
    548     if (!opt_N) {
    549 	gettimeofday(&tv, NULL);
    550 	now = tv.tv_sec;
    551 	tm = localtime(&now);
    552 	if (!(img = malloc(bpb.bps)))
    553 	    err(1, NULL);
    554 	dir = bpb.res + (bpb.spf ? bpb.spf : bpb.bspf) * bpb.nft;
    555 	for (lsn = 0; lsn < dir + (fat == 32 ? bpb.spc : rds); lsn++) {
    556 	    x = lsn;
    557 	    if (opt_B &&
    558 		fat == 32 && bpb.bkbs != MAXU16 &&
    559 		bss <= bpb.bkbs && x >= bpb.bkbs) {
    560 		x -= bpb.bkbs;
    561 		if (!x && lseek(fd1, 0, SEEK_SET))
    562 		    err(1, "%s", bname);
    563 	    }
    564 	    if (opt_B && x < bss) {
    565 		if ((n = read(fd1, img, bpb.bps)) == -1)
    566 		    err(1, "%s", bname);
    567 		if (n != bpb.bps)
    568 		    errx(1, "%s: can't read sector %u", bname, x);
    569 	    } else
    570 		memset(img, 0, bpb.bps);
    571 	    if (!lsn ||
    572 	      (fat == 32 && bpb.bkbs != MAXU16 && lsn == bpb.bkbs)) {
    573 		x1 = sizeof(struct bs);
    574 		bsbpb = (struct bsbpb *)(img + x1);
    575 		mk2(bsbpb->bps, bpb.bps);
    576 		mk1(bsbpb->spc, bpb.spc);
    577 		mk2(bsbpb->res, bpb.res);
    578 		mk1(bsbpb->nft, bpb.nft);
    579 		mk2(bsbpb->rde, bpb.rde);
    580 		mk2(bsbpb->sec, bpb.sec);
    581 		mk1(bsbpb->mid, bpb.mid);
    582 		mk2(bsbpb->spf, bpb.spf);
    583 		mk2(bsbpb->spt, bpb.spt);
    584 		mk2(bsbpb->hds, bpb.hds);
    585 		mk4(bsbpb->hid, bpb.hid);
    586 		mk4(bsbpb->bsec, bpb.bsec);
    587 		x1 += sizeof(struct bsbpb);
    588 		if (fat == 32) {
    589 		    bsxbpb = (struct bsxbpb *)(img + x1);
    590 		    mk4(bsxbpb->bspf, bpb.bspf);
    591 		    mk2(bsxbpb->xflg, 0);
    592 		    mk2(bsxbpb->vers, 0);
    593 		    mk4(bsxbpb->rdcl, bpb.rdcl);
    594 		    mk2(bsxbpb->infs, bpb.infs);
    595 		    mk2(bsxbpb->bkbs, bpb.bkbs);
    596 		    x1 += sizeof(struct bsxbpb);
    597 		}
    598 		bsx = (struct bsx *)(img + x1);
    599 		mk1(bsx->sig, 0x29);
    600 		if (Iflag)
    601 		    x = opt_I;
    602 		else
    603 		    x = (((u_int)(1 + tm->tm_mon) << 8 |
    604 			  (u_int)tm->tm_mday) +
    605 			 ((u_int)tm->tm_sec << 8 |
    606 			  (u_int)(tv.tv_usec / 10))) << 16 |
    607 			((u_int)(1900 + tm->tm_year) +
    608 			 ((u_int)tm->tm_hour << 8 |
    609 			  (u_int)tm->tm_min));
    610 		mk4(bsx->volid, x);
    611 		mklabel(bsx->label, opt_L ? opt_L : "NO NAME");
    612 		sprintf(buf, "FAT%u", fat);
    613 		setstr(bsx->type, buf, sizeof(bsx->type));
    614 		if (!opt_B) {
    615 		    x1 += sizeof(struct bsx);
    616 		    bs = (struct bs *)img;
    617 		    mk1(bs->jmp[0], 0xeb);
    618 		    mk1(bs->jmp[1], x1 - 2);
    619 		    mk1(bs->jmp[2], 0x90);
    620 		    setstr(bs->oem, opt_O ? opt_O : "BSD  4.4",
    621 			   sizeof(bs->oem));
    622 		    memcpy(img + x1, bootcode, sizeof(bootcode));
    623 		    mk2(img + bpb.bps - 2, DOSMAGIC);
    624 		}
    625 	    } else if (fat == 32 && bpb.infs != MAXU16 &&
    626 		       (lsn == bpb.infs ||
    627 			(bpb.bkbs != MAXU16 &&
    628 			 lsn == bpb.bkbs + bpb.infs))) {
    629 		mk4(img, 0x41615252);
    630 		mk4(img + bpb.bps - 28, 0x61417272);
    631 		mk4(img + bpb.bps - 24, 0xffffffff);
    632 		mk4(img + bpb.bps - 20, bpb.rdcl);
    633 		mk2(img + bpb.bps - 2, DOSMAGIC);
    634 	    } else if (lsn >= bpb.res && lsn < dir &&
    635 		       !((lsn - bpb.res) %
    636 			 (bpb.spf ? bpb.spf : bpb.bspf))) {
    637 		mk1(img[0], bpb.mid);
    638 		for (x = 1; x < fat * (fat == 32 ? 3 : 2) / 8; x++)
    639 		    mk1(img[x], fat == 32 && x % 4 == 3 ? 0x0f : 0xff);
    640 	    } else if (lsn == dir && opt_L) {
    641 		de = (struct de *)img;
    642 		mklabel(de->namext, opt_L);
    643 		mk1(de->attr, 050);
    644 		x = (u_int)tm->tm_hour << 11 |
    645 		    (u_int)tm->tm_min << 5 |
    646 		    (u_int)tm->tm_sec >> 1;
    647 		mk2(de->time, x);
    648 		x = (u_int)(tm->tm_year - 80) << 9 |
    649 		    (u_int)(tm->tm_mon + 1) << 5 |
    650 		    (u_int)tm->tm_mday;
    651 		mk2(de->date, x);
    652 	    }
    653 	    if ((n = write(fd, img, bpb.bps)) == -1)
    654 		err(1, "%s", fname);
    655 	    if (n != bpb.bps)
    656 		errx(1, "%s: can't write sector %u", fname, lsn);
    657 	}
    658     }
    659     return 0;
    660 }
    661 
    662 /*
    663  * Exit with error if file system is mounted.
    664  */
    665 static void
    666 check_mounted(const char *fname, mode_t mode)
    667 {
    668     struct statfs *mp;
    669     const char *s1, *s2;
    670     size_t len;
    671     int n, r;
    672 
    673     if (!(n = getmntinfo(&mp, MNT_NOWAIT)))
    674 	err(1, "getmntinfo");
    675     len = strlen(_PATH_DEV);
    676     s1 = fname;
    677     if (!strncmp(s1, _PATH_DEV, len))
    678 	s1 += len;
    679     r = S_ISCHR(mode) && s1 != fname && *s1 == 'r';
    680     for (; n--; mp++) {
    681 	s2 = mp->f_mntfromname;
    682 	if (!strncmp(s2, _PATH_DEV, len))
    683 	    s2 += len;
    684 	if ((r && s2 != mp->f_mntfromname && !strcmp(s1 + 1, s2)) ||
    685 	    !strcmp(s1, s2))
    686 	    errx(1, "%s is mounted on %s", fname, mp->f_mntonname);
    687     }
    688 }
    689 
    690 /*
    691  * Get a standard format.
    692  */
    693 static void
    694 getstdfmt(const char *fmt, struct bpb *bpb)
    695 {
    696     u_int x, i;
    697 
    698     x = sizeof(stdfmt) / sizeof(stdfmt[0]);
    699     for (i = 0; i < x && strcmp(fmt, stdfmt[i].name); i++);
    700     if (i == x)
    701 	errx(1, "%s: unknown standard format", fmt);
    702     *bpb = stdfmt[i].bpb;
    703 }
    704 
    705 /*
    706  * Get disk slice, partition, and geometry information.
    707  */
    708 static void
    709 getdiskinfo(int fd, const char *fname, const char *dtype, int oflag,
    710 	    struct bpb *bpb)
    711 {
    712     struct diskslices ds;
    713     struct disklabel dl, *lp;
    714     const char *s1, *s2;
    715     char *s;
    716     int slice, part, fd1, i, e;
    717 
    718     slice = part = -1;
    719     s1 = fname;
    720     if ((s2 = strrchr(s1, '/')))
    721 	s1 = s2 + 1;
    722     for (s2 = s1; *s2 && !isdigit(*s2); s2++);
    723     if (!*s2 || s2 == s1)
    724 	s2 = NULL;
    725     else
    726 	while (isdigit(*++s2));
    727     s1 = s2;
    728     if (s2 && *s2 == 's') {
    729 	slice = strtol(s2 + 1, &s, 10);
    730 	if (slice < 1 || slice > MAX_SLICES - BASE_SLICE)
    731 	    s2 = NULL;
    732 	else {
    733 	    slice = BASE_SLICE + slice - 1;
    734 	    s2 = s;
    735 	}
    736     }
    737     if (s2 && *s2 >= 'a' && *s2 <= 'a' + MAXPARTITIONS - 1) {
    738 	if (slice == -1)
    739 	    slice = COMPATIBILITY_SLICE;
    740 	part = *s2++ - 'a';
    741     }
    742     if (!s2 || (*s2 && *s2 != '.'))
    743 	errx(1, "%s: can't figure out partition info", fname);
    744     if (slice != -1 && (!oflag || (!bpb->bsec && part == -1))) {
    745 	if (ioctl(fd, DIOCGSLICEINFO, &ds) == -1) {
    746 	    warn("ioctl (GSLICEINFO)");
    747 	    errx(1, "%s: can't get slice info", fname);
    748 	}
    749 	if (slice >= ds.dss_nslices || !ds.dss_slices[slice].ds_size)
    750 	    errx(1, "%s: slice is unavailable", fname);
    751 	if (!oflag)
    752 	    bpb->hid = ds.dss_slices[slice].ds_offset;
    753 	if (!bpb->bsec && part == -1)
    754 	    bpb->bsec = ds.dss_slices[slice].ds_size;
    755     }
    756     if (((slice == -1 || part != -1) &&
    757 	 ((!oflag && part != -1) || !bpb->bsec)) ||
    758 	!bpb->bps || !bpb->spt || !bpb->hds) {
    759 	lp = &dl;
    760 	i = ioctl(fd, DIOCGDINFO, lp);
    761 	if (i == -1 && slice != -1 && part == -1) {
    762 	    e = errno;
    763 	    if (!(s = strdup(fname)))
    764 		err(1, NULL);
    765 	    s[s1 - fname] = 0;
    766 	    if ((fd1 = open(s, O_RDONLY)) != -1) {
    767 		i = ioctl(fd1, DIOCGDINFO, lp);
    768 		close(fd1);
    769 	    }
    770 	    free(s);
    771 	    errno = e;
    772 	}
    773 	if (i == -1) {
    774 	    if (!dtype) {
    775 		warn("ioctl (GDINFO)");
    776 		errx(1, "%s: can't read disk label; "
    777 		     "disk type must be specified", fname);
    778 	    } else if (!(lp = getdiskbyname(dtype)))
    779 		errx(1, "%s: unknown disk type", dtype);
    780 	}
    781 	if (slice == -1 || part != -1) {
    782 	    if (part == -1)
    783 		part = RAW_PART;
    784 	    if (part >= lp->d_npartitions ||
    785 		!lp->d_partitions[part].p_size)
    786 		errx(1, "%s: partition is unavailable", fname);
    787 	    if (!oflag && part != -1)
    788 		bpb->hid += lp->d_partitions[part].p_offset;
    789 	    if (!bpb->bsec)
    790 		bpb->bsec = lp->d_partitions[part].p_size;
    791 	}
    792 	if (!bpb->bps)
    793 	    bpb->bps = ckgeom(fname, lp->d_secsize, "bytes/sector");
    794 	if (!bpb->spt)
    795 	    bpb->spt = ckgeom(fname, lp->d_nsectors, "sectors/track");
    796 	if (!bpb->hds)
    797 	    bpb->hds = ckgeom(fname, lp->d_ntracks, "drive heads");
    798     }
    799 }
    800 
    801 /*
    802  * Print out BPB values.
    803  */
    804 static void
    805 print_bpb(struct bpb *bpb)
    806 {
    807     printf("bps=%u spc=%u res=%u nft=%u", bpb->bps, bpb->spc, bpb->res,
    808 	   bpb->nft);
    809     if (bpb->rde)
    810 	printf(" rde=%u", bpb->rde);
    811     if (bpb->sec)
    812 	printf(" sec=%u", bpb->sec);
    813     printf(" mid=%#x", bpb->mid);
    814     if (bpb->spf)
    815 	printf(" spf=%u", bpb->spf);
    816     printf(" spt=%u hds=%u hid=%u", bpb->spt, bpb->hds, bpb->hid);
    817     if (bpb->bsec)
    818 	printf(" bsec=%u", bpb->bsec);
    819     if (!bpb->spf) {
    820 	printf(" bspf=%u rdcl=%u", bpb->bspf, bpb->rdcl);
    821 	printf(" infs=");
    822 	printf(bpb->infs == MAXU16 ? "%#x" : "%u", bpb->infs);
    823 	printf(" bkbs=");
    824 	printf(bpb->bkbs == MAXU16 ? "%#x" : "%u", bpb->bkbs);
    825     }
    826     printf("\n");
    827 }
    828 
    829 /*
    830  * Check a disk geometry value.
    831  */
    832 static u_int
    833 ckgeom(const char *fname, u_int val, const char *msg)
    834 {
    835     if (!val)
    836 	errx(1, "%s: no default %s", fname, msg);
    837     if (val > MAXU16)
    838 	errx(1, "%s: illegal %s", fname, msg);
    839     return val;
    840 }
    841 
    842 /*
    843  * Convert and check a numeric option argument.
    844  */
    845 static u_int
    846 argtou(const char *arg, u_int lo, u_int hi, const char *msg)
    847 {
    848     char *s;
    849     u_long x;
    850 
    851     errno = 0;
    852     x = strtoul(arg, &s, 0);
    853     if (errno || !*arg || *s || x < lo || x > hi)
    854 	errx(1, "%s: bad %s", arg, msg);
    855     return x;
    856 }
    857 
    858 /*
    859  * Check a volume label.
    860  */
    861 static int
    862 oklabel(const char *src)
    863 {
    864     int c, i;
    865 
    866     for (i = 0; i <= 11; i++) {
    867 	c = (u_char)*src++;
    868 	if (c < ' ' + !i || strchr("\"*+,./:;<=>?[\\]|", c))
    869 	    break;
    870     }
    871     return i && !c;
    872 }
    873 
    874 /*
    875  * Make a volume label.
    876  */
    877 static void
    878 mklabel(u_int8_t *dest, const char *src)
    879 {
    880     int c, i;
    881 
    882     for (i = 0; i < 11; i++) {
    883 	c = *src ? toupper(*src++) : ' ';
    884 	*dest++ = !i && c == '\xe5' ? 5 : c;
    885     }
    886 }
    887 
    888 /*
    889  * Copy string, padding with spaces.
    890  */
    891 static void
    892 setstr(u_int8_t *dest, const char *src, size_t len)
    893 {
    894     while (len--)
    895 	*dest++ = *src ? *src++ : ' ';
    896 }
    897 
    898 /*
    899  * Print usage message.
    900  */
    901 static void
    902 usage(void)
    903 {
    904     fprintf(stderr,
    905 	    "usage: newfs_msdos [ -options ] special [disktype]\n");
    906     fprintf(stderr, "where the options are:\n");
    907     fprintf(stderr, "\t-N don't create file system: "
    908 	    "just print out parameters\n");
    909     fprintf(stderr, "\t-B get bootstrap from file\n");
    910     fprintf(stderr, "\t-F FAT type (12, 16, or 32)\n");
    911     fprintf(stderr, "\t-I volume ID\n");
    912     fprintf(stderr, "\t-L volume label\n");
    913     fprintf(stderr, "\t-O OEM string\n");
    914     fprintf(stderr, "\t-S bytes/sector\n");
    915     fprintf(stderr, "\t-a sectors/FAT\n");
    916     fprintf(stderr, "\t-b block size\n");
    917     fprintf(stderr, "\t-c sectors/cluster\n");
    918     fprintf(stderr, "\t-e root directory entries\n");
    919     fprintf(stderr, "\t-f standard format\n");
    920     fprintf(stderr, "\t-h drive heads\n");
    921     fprintf(stderr, "\t-i file system info sector\n");
    922     fprintf(stderr, "\t-k backup boot sector\n");
    923     fprintf(stderr, "\t-m media descriptor\n");
    924     fprintf(stderr, "\t-n number of FATs\n");
    925     fprintf(stderr, "\t-o hidden sectors\n");
    926     fprintf(stderr, "\t-r reserved sectors\n");
    927     fprintf(stderr, "\t-s file system size (sectors)\n");
    928     fprintf(stderr, "\t-u sectors/track\n");
    929     exit(1);
    930 }
    931