newfs_msdos.c revision 190930
113978Smrkam/* 213978Smrkam * Copyright (c) 1998 Robert Nordier 313978Smrkam * All rights reserved. 413978Smrkam * 513978Smrkam * Redistribution and use in source and binary forms, with or without 613978Smrkam * modification, are permitted provided that the following conditions 713978Smrkam * are met: 813978Smrkam * 1. Redistributions of source code must retain the above copyright 913978Smrkam * notice, this list of conditions and the following disclaimer. 1013978Smrkam * 2. Redistributions in binary form must reproduce the above copyright 1113978Smrkam * notice, this list of conditions and the following disclaimer in 1213978Smrkam * the documentation and/or other materials provided with the 1313978Smrkam * distribution. 1413978Smrkam * 1513978Smrkam * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS 1613978Smrkam * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 1713978Smrkam * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1813978Smrkam * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY 1913978Smrkam * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2013978Smrkam * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 2113978Smrkam * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2213978Smrkam * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 2313978Smrkam * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 2413978Smrkam * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 2513978Smrkam * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2613978Smrkam */ 2713978Smrkam 2813978Smrkam#ifndef lint 2913978Smrkamstatic const char rcsid[] = 3013978Smrkam "$FreeBSD: head/sbin/newfs_msdos/newfs_msdos.c 190930 2009-04-11 14:43:22Z ed $"; 3113978Smrkam#endif /* not lint */ 3213978Smrkam 3313978Smrkam#include <sys/param.h> 3413978Smrkam#include <sys/fdcio.h> 3513978Smrkam#include <sys/disk.h> 3613978Smrkam#include <sys/disklabel.h> 3713978Smrkam#include <sys/mount.h> 3813978Smrkam#include <sys/stat.h> 3913978Smrkam#include <sys/time.h> 4013978Smrkam 4113978Smrkam#include <ctype.h> 4213978Smrkam#include <err.h> 4313978Smrkam#include <errno.h> 4413978Smrkam#include <fcntl.h> 4513978Smrkam#include <inttypes.h> 4613978Smrkam#include <paths.h> 4713978Smrkam#include <stdio.h> 4813978Smrkam#include <stdlib.h> 4913978Smrkam#include <string.h> 5013978Smrkam#include <time.h> 5113978Smrkam#include <unistd.h> 5213978Smrkam 5313978Smrkam#define MAXU16 0xffff /* maximum unsigned 16-bit quantity */ 5413978Smrkam#define BPN 4 /* bits per nibble */ 5513978Smrkam#define NPB 2 /* nibbles per byte */ 5613978Smrkam 5713978Smrkam#define DOSMAGIC 0xaa55 /* DOS magic number */ 5813978Smrkam#define MINBPS 512 /* minimum bytes per sector */ 5913978Smrkam#define MAXSPC 128 /* maximum sectors per cluster */ 6013978Smrkam#define MAXNFT 16 /* maximum number of FATs */ 6113978Smrkam#define DEFBLK 4096 /* default block size */ 6213978Smrkam#define DEFBLK16 2048 /* default block size FAT16 */ 6313978Smrkam#define DEFRDE 512 /* default root directory entries */ 6413978Smrkam#define RESFTE 2 /* reserved FAT entries */ 6513978Smrkam#define MINCLS12 1 /* minimum FAT12 clusters */ 6613978Smrkam#define MINCLS16 0x1000 /* minimum FAT16 clusters */ 6713978Smrkam#define MINCLS32 2 /* minimum FAT32 clusters */ 6813978Smrkam#define MAXCLS12 0xfed /* maximum FAT12 clusters */ 6913978Smrkam#define MAXCLS16 0xfff5 /* maximum FAT16 clusters */ 7013978Smrkam#define MAXCLS32 0xffffff5 /* maximum FAT32 clusters */ 7113978Smrkam 7213978Smrkam#define mincls(fat) ((fat) == 12 ? MINCLS12 : \ 7313978Smrkam (fat) == 16 ? MINCLS16 : \ 7413978Smrkam MINCLS32) 7513978Smrkam 7613978Smrkam#define maxcls(fat) ((fat) == 12 ? MAXCLS12 : \ 7713978Smrkam (fat) == 16 ? MAXCLS16 : \ 7813978Smrkam MAXCLS32) 7913978Smrkam 8013978Smrkam#define mk1(p, x) \ 8113978Smrkam (p) = (u_int8_t)(x) 8213978Smrkam 8313978Smrkam#define mk2(p, x) \ 8413978Smrkam (p)[0] = (u_int8_t)(x), \ 8513978Smrkam (p)[1] = (u_int8_t)((x) >> 010) 8613978Smrkam 8713978Smrkam#define mk4(p, x) \ 8813978Smrkam (p)[0] = (u_int8_t)(x), \ 8913978Smrkam (p)[1] = (u_int8_t)((x) >> 010), \ 9013978Smrkam (p)[2] = (u_int8_t)((x) >> 020), \ 9113978Smrkam (p)[3] = (u_int8_t)((x) >> 030) 9213978Smrkam 9313978Smrkam#define argto1(arg, lo, msg) argtou(arg, lo, 0xff, msg) 9413978Smrkam#define argto2(arg, lo, msg) argtou(arg, lo, 0xffff, msg) 9513978Smrkam#define argto4(arg, lo, msg) argtou(arg, lo, 0xffffffff, msg) 9613978Smrkam#define argtox(arg, lo, msg) argtou(arg, lo, UINT_MAX, msg) 9713978Smrkam 9813978Smrkamstruct bs { 9913978Smrkam u_int8_t jmp[3]; /* bootstrap entry point */ 10013978Smrkam u_int8_t oem[8]; /* OEM name and version */ 10113978Smrkam}; 10213978Smrkam 10313978Smrkamstruct bsbpb { 10413978Smrkam u_int8_t bps[2]; /* bytes per sector */ 10513978Smrkam u_int8_t spc; /* sectors per cluster */ 10613978Smrkam u_int8_t res[2]; /* reserved sectors */ 10713978Smrkam u_int8_t nft; /* number of FATs */ 10813978Smrkam u_int8_t rde[2]; /* root directory entries */ 10913978Smrkam u_int8_t sec[2]; /* total sectors */ 11013978Smrkam u_int8_t mid; /* media descriptor */ 11113978Smrkam u_int8_t spf[2]; /* sectors per FAT */ 11213978Smrkam u_int8_t spt[2]; /* sectors per track */ 11313978Smrkam u_int8_t hds[2]; /* drive heads */ 11413978Smrkam u_int8_t hid[4]; /* hidden sectors */ 11513978Smrkam u_int8_t bsec[4]; /* big total sectors */ 11613978Smrkam}; 11713978Smrkam 11813978Smrkamstruct bsxbpb { 11913978Smrkam u_int8_t bspf[4]; /* big sectors per FAT */ 12013978Smrkam u_int8_t xflg[2]; /* FAT control flags */ 12113978Smrkam u_int8_t vers[2]; /* file system version */ 12213978Smrkam u_int8_t rdcl[4]; /* root directory start cluster */ 12313978Smrkam u_int8_t infs[2]; /* file system info sector */ 12413978Smrkam u_int8_t bkbs[2]; /* backup boot sector */ 12513978Smrkam u_int8_t rsvd[12]; /* reserved */ 12613978Smrkam}; 12713978Smrkam 12813978Smrkamstruct bsx { 12913978Smrkam u_int8_t drv; /* drive number */ 13013978Smrkam u_int8_t rsvd; /* reserved */ 13113978Smrkam u_int8_t sig; /* extended boot signature */ 13213978Smrkam u_int8_t volid[4]; /* volume ID number */ 13313978Smrkam u_int8_t label[11]; /* volume label */ 13413978Smrkam u_int8_t type[8]; /* file system type */ 13513978Smrkam}; 13613978Smrkam 13713978Smrkamstruct de { 13813978Smrkam u_int8_t namext[11]; /* name and extension */ 13913978Smrkam u_int8_t attr; /* attributes */ 14013978Smrkam u_int8_t rsvd[10]; /* reserved */ 14113978Smrkam u_int8_t time[2]; /* creation time */ 14213978Smrkam u_int8_t date[2]; /* creation date */ 14313978Smrkam u_int8_t clus[2]; /* starting cluster */ 14413978Smrkam u_int8_t size[4]; /* size */ 14513978Smrkam}; 14613978Smrkam 14713978Smrkamstruct bpb { 14813978Smrkam u_int bps; /* bytes per sector */ 14913978Smrkam u_int spc; /* sectors per cluster */ 15013978Smrkam u_int res; /* reserved sectors */ 15113978Smrkam u_int nft; /* number of FATs */ 15213978Smrkam u_int rde; /* root directory entries */ 15313978Smrkam u_int sec; /* total sectors */ 15413978Smrkam u_int mid; /* media descriptor */ 15513978Smrkam u_int spf; /* sectors per FAT */ 15613978Smrkam u_int spt; /* sectors per track */ 15713978Smrkam u_int hds; /* drive heads */ 15813978Smrkam u_int hid; /* hidden sectors */ 15913978Smrkam u_int bsec; /* big total sectors */ 16013978Smrkam u_int bspf; /* big sectors per FAT */ 16113978Smrkam u_int rdcl; /* root directory start cluster */ 16213978Smrkam u_int infs; /* file system info sector */ 16313978Smrkam u_int bkbs; /* backup boot sector */ 16413978Smrkam}; 16513978Smrkam 16613978Smrkam#define BPBGAP 0, 0, 0, 0, 0, 0 16713978Smrkam 16813978Smrkamstatic struct { 16913978Smrkam const char *name; 17013978Smrkam struct bpb bpb; 17113978Smrkam} const stdfmt[] = { 17213978Smrkam {"160", {512, 1, 1, 2, 64, 320, 0xfe, 1, 8, 1, BPBGAP}}, 17313978Smrkam {"180", {512, 1, 1, 2, 64, 360, 0xfc, 2, 9, 1, BPBGAP}}, 17413978Smrkam {"320", {512, 2, 1, 2, 112, 640, 0xff, 1, 8, 2, BPBGAP}}, 17513978Smrkam {"360", {512, 2, 1, 2, 112, 720, 0xfd, 2, 9, 2, BPBGAP}}, 17613978Smrkam {"640", {512, 2, 1, 2, 112, 1280, 0xfb, 2, 8, 2, BPBGAP}}, 17713978Smrkam {"720", {512, 2, 1, 2, 112, 1440, 0xf9, 3, 9, 2, BPBGAP}}, 17813978Smrkam {"1200", {512, 1, 1, 2, 224, 2400, 0xf9, 7, 15, 2, BPBGAP}}, 17913978Smrkam {"1232", {1024,1, 1, 2, 192, 1232, 0xfe, 2, 8, 2, BPBGAP}}, 18013978Smrkam {"1440", {512, 1, 1, 2, 224, 2880, 0xf0, 9, 18, 2, BPBGAP}}, 18113978Smrkam {"2880", {512, 2, 1, 2, 240, 5760, 0xf0, 9, 36, 2, BPBGAP}} 18213978Smrkam}; 18313978Smrkam 18413978Smrkamstatic const u_int8_t bootcode[] = { 18513978Smrkam 0xfa, /* cli */ 18613978Smrkam 0x31, 0xc0, /* xor ax,ax */ 18713978Smrkam 0x8e, 0xd0, /* mov ss,ax */ 18813978Smrkam 0xbc, 0x00, 0x7c, /* mov sp,7c00h */ 18913978Smrkam 0xfb, /* sti */ 19013978Smrkam 0x8e, 0xd8, /* mov ds,ax */ 19113978Smrkam 0xe8, 0x00, 0x00, /* call $ + 3 */ 19213978Smrkam 0x5e, /* pop si */ 19313978Smrkam 0x83, 0xc6, 0x19, /* add si,+19h */ 19413978Smrkam 0xbb, 0x07, 0x00, /* mov bx,0007h */ 19513978Smrkam 0xfc, /* cld */ 19613978Smrkam 0xac, /* lodsb */ 19713978Smrkam 0x84, 0xc0, /* test al,al */ 19813978Smrkam 0x74, 0x06, /* jz $ + 8 */ 19913978Smrkam 0xb4, 0x0e, /* mov ah,0eh */ 20013978Smrkam 0xcd, 0x10, /* int 10h */ 20113978Smrkam 0xeb, 0xf5, /* jmp $ - 9 */ 20213978Smrkam 0x30, 0xe4, /* xor ah,ah */ 20313978Smrkam 0xcd, 0x16, /* int 16h */ 20413978Smrkam 0xcd, 0x19, /* int 19h */ 20513978Smrkam 0x0d, 0x0a, 20613978Smrkam 'N', 'o', 'n', '-', 's', 'y', 's', 't', 20713978Smrkam 'e', 'm', ' ', 'd', 'i', 's', 'k', 20813978Smrkam 0x0d, 0x0a, 20913978Smrkam 'P', 'r', 'e', 's', 's', ' ', 'a', 'n', 21013978Smrkam 'y', ' ', 'k', 'e', 'y', ' ', 't', 'o', 21113978Smrkam ' ', 'r', 'e', 'b', 'o', 'o', 't', 21213978Smrkam 0x0d, 0x0a, 21313978Smrkam 0 21413978Smrkam}; 21513978Smrkam 21613978Smrkamstatic void check_mounted(const char *, mode_t); 21713978Smrkamstatic void getstdfmt(const char *, struct bpb *); 21813978Smrkamstatic void getdiskinfo(int, const char *, const char *, int, 21913978Smrkam struct bpb *); 22013978Smrkamstatic void print_bpb(struct bpb *); 22113978Smrkamstatic u_int ckgeom(const char *, u_int, const char *); 22213978Smrkamstatic u_int argtou(const char *, u_int, u_int, const char *); 22313978Smrkamstatic off_t argtooff(const char *, const char *); 22413978Smrkamstatic int oklabel(const char *); 22513978Smrkamstatic void mklabel(u_int8_t *, const char *); 22613978Smrkamstatic void setstr(u_int8_t *, const char *, size_t); 22713978Smrkamstatic void usage(void); 22813978Smrkam 22913978Smrkam/* 23013978Smrkam * Construct a FAT12, FAT16, or FAT32 file system. 23113978Smrkam */ 23213978Smrkamint 23313978Smrkammain(int argc, char *argv[]) 23413978Smrkam{ 23513978Smrkam static const char opts[] = "@:NB:C:F:I:L:O:S:a:b:c:e:f:h:i:k:m:n:o:r:s:u:"; 23613978Smrkam const char *opt_B = NULL, *opt_L = NULL, *opt_O = NULL, *opt_f = NULL; 23713978Smrkam u_int opt_F = 0, opt_I = 0, opt_S = 0, opt_a = 0, opt_b = 0, opt_c = 0; 23813978Smrkam u_int opt_e = 0, opt_h = 0, opt_i = 0, opt_k = 0, opt_m = 0, opt_n = 0; 23913978Smrkam u_int opt_o = 0, opt_r = 0, opt_s = 0, opt_u = 0; 24013978Smrkam int opt_N = 0; 24113978Smrkam int Iflag = 0, mflag = 0, oflag = 0; 24213978Smrkam char buf[MAXPATHLEN]; 24313978Smrkam struct stat sb; 24413978Smrkam struct timeval tv; 24513978Smrkam struct bpb bpb; 24613978Smrkam struct tm *tm; 24713978Smrkam struct bs *bs; 24813978Smrkam struct bsbpb *bsbpb; 24913978Smrkam struct bsxbpb *bsxbpb; 25013978Smrkam struct bsx *bsx; 25113978Smrkam struct de *de; 25213978Smrkam u_int8_t *img; 25313978Smrkam const char *fname, *dtype, *bname; 25413978Smrkam ssize_t n; 25513978Smrkam time_t now; 25613978Smrkam u_int fat, bss, rds, cls, dir, lsn, x, x1, x2; 25713978Smrkam int ch, fd, fd1; 25813978Smrkam off_t opt_create = 0, opt_ofs = 0; 25913978Smrkam 26013978Smrkam while ((ch = getopt(argc, argv, opts)) != -1) 26113978Smrkam switch (ch) { 26213978Smrkam case '@': 26313978Smrkam opt_ofs = argtooff(optarg, "offset"); 26413978Smrkam break; 26513978Smrkam case 'N': 26613978Smrkam opt_N = 1; 26713978Smrkam break; 26813978Smrkam case 'B': 26913978Smrkam opt_B = optarg; 27013978Smrkam break; 27113978Smrkam case 'C': 27213978Smrkam opt_create = argtooff(optarg, "create size"); 27313978Smrkam break; 27413978Smrkam case 'F': 27513978Smrkam if (strcmp(optarg, "12") && 27613978Smrkam strcmp(optarg, "16") && 27713978Smrkam strcmp(optarg, "32")) 27813978Smrkam errx(1, "%s: bad FAT type", optarg); 27913978Smrkam opt_F = atoi(optarg); 28013978Smrkam break; 28113978Smrkam case 'I': 28213978Smrkam opt_I = argto4(optarg, 0, "volume ID"); 28313978Smrkam Iflag = 1; 28413978Smrkam break; 28513978Smrkam case 'L': 28613978Smrkam if (!oklabel(optarg)) 28713978Smrkam errx(1, "%s: bad volume label", optarg); 28813978Smrkam opt_L = optarg; 28913978Smrkam break; 29013978Smrkam case 'O': 29113978Smrkam if (strlen(optarg) > 8) 29213978Smrkam errx(1, "%s: bad OEM string", optarg); 29313978Smrkam opt_O = optarg; 29413978Smrkam break; 29513978Smrkam case 'S': 29613978Smrkam opt_S = argto2(optarg, 1, "bytes/sector"); 29713978Smrkam break; 29813978Smrkam case 'a': 29913978Smrkam opt_a = argto4(optarg, 1, "sectors/FAT"); 30013978Smrkam break; 30113978Smrkam case 'b': 30213978Smrkam opt_b = argtox(optarg, 1, "block size"); 30313978Smrkam opt_c = 0; 30413978Smrkam break; 30513978Smrkam case 'c': 30613978Smrkam opt_c = argto1(optarg, 1, "sectors/cluster"); 30713978Smrkam opt_b = 0; 30813978Smrkam break; 30913978Smrkam case 'e': 31013978Smrkam opt_e = argto2(optarg, 1, "directory entries"); 31113978Smrkam break; 31213978Smrkam case 'f': 31313978Smrkam opt_f = optarg; 31413978Smrkam break; 31513978Smrkam case 'h': 31613978Smrkam opt_h = argto2(optarg, 1, "drive heads"); 31713978Smrkam break; 31813978Smrkam case 'i': 31913978Smrkam opt_i = argto2(optarg, 1, "info sector"); 32013978Smrkam break; 32113978Smrkam case 'k': 32213978Smrkam opt_k = argto2(optarg, 1, "backup sector"); 32313978Smrkam break; 32413978Smrkam case 'm': 32513978Smrkam opt_m = argto1(optarg, 0, "media descriptor"); 32613978Smrkam mflag = 1; 32713978Smrkam break; 32813978Smrkam case 'n': 32913978Smrkam opt_n = argto1(optarg, 1, "number of FATs"); 33013978Smrkam break; 33113978Smrkam case 'o': 33213978Smrkam opt_o = argto4(optarg, 0, "hidden sectors"); 33313978Smrkam oflag = 1; 33413978Smrkam break; 33513978Smrkam case 'r': 33613978Smrkam opt_r = argto2(optarg, 1, "reserved sectors"); 33713978Smrkam break; 33813978Smrkam case 's': 33913978Smrkam opt_s = argto4(optarg, 1, "file system size"); 34013978Smrkam break; 34113978Smrkam case 'u': 34213978Smrkam opt_u = argto2(optarg, 1, "sectors/track"); 34313978Smrkam break; 34413978Smrkam default: 34513978Smrkam usage(); 34613978Smrkam } 34713978Smrkam argc -= optind; 34813978Smrkam argv += optind; 34913978Smrkam if (argc < 1 || argc > 2) 35013978Smrkam usage(); 35113978Smrkam fname = *argv++; 35213978Smrkam if (!strchr(fname, '/')) { 35313978Smrkam snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname); 35413978Smrkam if (!(fname = strdup(buf))) 35513978Smrkam err(1, NULL); 35613978Smrkam } 35713978Smrkam dtype = *argv; 35813978Smrkam if (opt_create) { 35913978Smrkam if (opt_N) 36013978Smrkam errx(1, "create (-C) is incompatible with -N"); 36113978Smrkam fd = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0644); 36213978Smrkam if (fd == -1) 36313978Smrkam errx(1, "failed to create %s", fname); 36413978Smrkam if (ftruncate(fd, opt_create)) 36513978Smrkam errx(1, "failed to initialize %jd bytes", (intmax_t)opt_create); 36613978Smrkam } else if ((fd = open(fname, opt_N ? O_RDONLY : O_RDWR)) == -1) 36713978Smrkam err(1, "%s", fname); 36813978Smrkam if (fstat(fd, &sb)) 36913978Smrkam err(1, "%s", fname); 37013978Smrkam if (!opt_N) 37113978Smrkam check_mounted(fname, sb.st_mode); 37213978Smrkam if (!S_ISCHR(sb.st_mode)) 37313978Smrkam warnx("warning, %s is not a character device", fname); 37413978Smrkam if (opt_ofs && opt_ofs != lseek(fd, opt_ofs, SEEK_SET)) 37513978Smrkam errx(1, "cannot seek to %jd", (intmax_t)opt_ofs); 37613978Smrkam memset(&bpb, 0, sizeof(bpb)); 37713978Smrkam if (opt_f) { 37813978Smrkam getstdfmt(opt_f, &bpb); 37913978Smrkam bpb.bsec = bpb.sec; 38013978Smrkam bpb.sec = 0; 38113978Smrkam bpb.bspf = bpb.spf; 38213978Smrkam bpb.spf = 0; 38313978Smrkam } 38413978Smrkam if (opt_h) 38513978Smrkam bpb.hds = opt_h; 38613978Smrkam if (opt_u) 38713978Smrkam bpb.spt = opt_u; 38813978Smrkam if (opt_S) 38913978Smrkam bpb.bps = opt_S; 39013978Smrkam if (opt_s) 39113978Smrkam bpb.bsec = opt_s; 39213978Smrkam if (oflag) 39313978Smrkam bpb.hid = opt_o; 39413978Smrkam if (!(opt_f || (opt_h && opt_u && opt_S && opt_s && oflag))) { 39513978Smrkam off_t delta; 39613978Smrkam getdiskinfo(fd, fname, dtype, oflag, &bpb); 39713978Smrkam bpb.bsec -= (opt_ofs / bpb.bps); 39813978Smrkam delta = bpb.bsec % bpb.spt; 39913978Smrkam if (delta != 0) { 40013978Smrkam warnx("trim %d sectors to adjust to a multiple of %d", 40113978Smrkam (int)delta, bpb.spt); 40213978Smrkam bpb.bsec -= delta; 40313978Smrkam } 40413978Smrkam if (bpb.spc == 0) { /* set defaults */ 40513978Smrkam if (bpb.bsec <= 6000) /* about 3MB -> 512 bytes */ 40613978Smrkam bpb.spc = 1; 40713978Smrkam else if (bpb.bsec <= (1<<17)) /* 64M -> 4k */ 40813978Smrkam bpb.spc = 8; 40913978Smrkam else if (bpb.bsec <= (1<<19)) /* 256M -> 8k */ 41013978Smrkam bpb.spc = 16; 41113978Smrkam else if (bpb.bsec <= (1<<21)) /* 1G -> 16k */ 41213978Smrkam bpb.spc = 32; 41313978Smrkam else 41413978Smrkam bpb.spc = 64; /* otherwise 32k */ 41513978Smrkam } 41613978Smrkam } 41713978Smrkam if (!powerof2(bpb.bps)) 41813978Smrkam errx(1, "bytes/sector (%u) is not a power of 2", bpb.bps); 41913978Smrkam if (bpb.bps < MINBPS) 42013978Smrkam errx(1, "bytes/sector (%u) is too small; minimum is %u", 42113978Smrkam bpb.bps, MINBPS); 42213978Smrkam if (!(fat = opt_F)) { 42313978Smrkam if (opt_f) 42413978Smrkam fat = 12; 42513978Smrkam else if (!opt_e && (opt_i || opt_k)) 42613978Smrkam fat = 32; 42713978Smrkam } 42813978Smrkam if ((fat == 32 && opt_e) || (fat != 32 && (opt_i || opt_k))) 42913978Smrkam errx(1, "-%c is not a legal FAT%s option", 43013978Smrkam fat == 32 ? 'e' : opt_i ? 'i' : 'k', 43113978Smrkam fat == 32 ? "32" : "12/16"); 43213978Smrkam if (opt_f && fat == 32) 43313978Smrkam bpb.rde = 0; 43413978Smrkam if (opt_b) { 43513978Smrkam if (!powerof2(opt_b)) 43613978Smrkam errx(1, "block size (%u) is not a power of 2", opt_b); 43713978Smrkam if (opt_b < bpb.bps) 43813978Smrkam errx(1, "block size (%u) is too small; minimum is %u", 43913978Smrkam opt_b, bpb.bps); 44013978Smrkam if (opt_b > bpb.bps * MAXSPC) 44113978Smrkam errx(1, "block size (%u) is too large; maximum is %u", 44213978Smrkam opt_b, bpb.bps * MAXSPC); 44313978Smrkam bpb.spc = opt_b / bpb.bps; 44413978Smrkam } 44513978Smrkam if (opt_c) { 44613978Smrkam if (!powerof2(opt_c)) 44713978Smrkam errx(1, "sectors/cluster (%u) is not a power of 2", opt_c); 44813978Smrkam bpb.spc = opt_c; 44913978Smrkam } 45013978Smrkam if (opt_r) 45113978Smrkam bpb.res = opt_r; 45213978Smrkam if (opt_n) { 45313978Smrkam if (opt_n > MAXNFT) 45413978Smrkam errx(1, "number of FATs (%u) is too large; maximum is %u", 45513978Smrkam opt_n, MAXNFT); 45613978Smrkam bpb.nft = opt_n; 45713978Smrkam } 45813978Smrkam if (opt_e) 45913978Smrkam bpb.rde = opt_e; 46013978Smrkam if (mflag) { 46113978Smrkam if (opt_m < 0xf0) 46213978Smrkam errx(1, "illegal media descriptor (%#x)", opt_m); 46313978Smrkam bpb.mid = opt_m; 46413978Smrkam } 46513978Smrkam if (opt_a) 46613978Smrkam bpb.bspf = opt_a; 46713978Smrkam if (opt_i) 46813978Smrkam bpb.infs = opt_i; 46913978Smrkam if (opt_k) 47013978Smrkam bpb.bkbs = opt_k; 47113978Smrkam bss = 1; 47213978Smrkam bname = NULL; 47313978Smrkam fd1 = -1; 47413978Smrkam if (opt_B) { 47513978Smrkam bname = opt_B; 47613978Smrkam if (!strchr(bname, '/')) { 47713978Smrkam snprintf(buf, sizeof(buf), "/boot/%s", bname); 47813978Smrkam if (!(bname = strdup(buf))) 47913978Smrkam err(1, NULL); 48013978Smrkam } 48113978Smrkam if ((fd1 = open(bname, O_RDONLY)) == -1 || fstat(fd1, &sb)) 48213978Smrkam err(1, "%s", bname); 48313978Smrkam if (!S_ISREG(sb.st_mode) || sb.st_size % bpb.bps || 48413978Smrkam sb.st_size < bpb.bps || sb.st_size > bpb.bps * MAXU16) 48513978Smrkam errx(1, "%s: inappropriate file type or format", bname); 48613978Smrkam bss = sb.st_size / bpb.bps; 48713978Smrkam } 48813978Smrkam if (!bpb.nft) 48913978Smrkam bpb.nft = 2; 49013978Smrkam if (!fat) { 49113978Smrkam if (bpb.bsec < (bpb.res ? bpb.res : bss) + 49213978Smrkam howmany((RESFTE + (bpb.spc ? MINCLS16 : MAXCLS12 + 1)) * 49313978Smrkam ((bpb.spc ? 16 : 12) / BPN), bpb.bps * NPB) * 49413978Smrkam bpb.nft + 49513978Smrkam howmany(bpb.rde ? bpb.rde : DEFRDE, 49613978Smrkam bpb.bps / sizeof(struct de)) + 49713978Smrkam (bpb.spc ? MINCLS16 : MAXCLS12 + 1) * 49813978Smrkam (bpb.spc ? bpb.spc : howmany(DEFBLK, bpb.bps))) 49913978Smrkam fat = 12; 50013978Smrkam else if (bpb.rde || bpb.bsec < 50113978Smrkam (bpb.res ? bpb.res : bss) + 50213978Smrkam howmany((RESFTE + MAXCLS16) * 2, bpb.bps) * bpb.nft + 50313978Smrkam howmany(DEFRDE, bpb.bps / sizeof(struct de)) + 50413978Smrkam (MAXCLS16 + 1) * 50513978Smrkam (bpb.spc ? bpb.spc : howmany(8192, bpb.bps))) 50613978Smrkam fat = 16; 50713978Smrkam else 50813978Smrkam fat = 32; 50913978Smrkam } 51013978Smrkam x = bss; 51113978Smrkam if (fat == 32) { 51213978Smrkam if (!bpb.infs) { 51313978Smrkam if (x == MAXU16 || x == bpb.bkbs) 51413978Smrkam errx(1, "no room for info sector"); 51513978Smrkam bpb.infs = x; 51613978Smrkam } 51713978Smrkam if (bpb.infs != MAXU16 && x <= bpb.infs) 51813978Smrkam x = bpb.infs + 1; 51913978Smrkam if (!bpb.bkbs) { 52013978Smrkam if (x == MAXU16) 52113978Smrkam errx(1, "no room for backup sector"); 52213978Smrkam bpb.bkbs = x; 52313978Smrkam } else if (bpb.bkbs != MAXU16 && bpb.bkbs == bpb.infs) 52413978Smrkam errx(1, "backup sector would overwrite info sector"); 52513978Smrkam if (bpb.bkbs != MAXU16 && x <= bpb.bkbs) 52613978Smrkam x = bpb.bkbs + 1; 52713978Smrkam } 52813978Smrkam if (!bpb.res) 52913978Smrkam bpb.res = fat == 32 ? MAX(x, MAX(16384 / bpb.bps, 4)) : x; 53013978Smrkam else if (bpb.res < x) 53113978Smrkam errx(1, "too few reserved sectors"); 53213978Smrkam if (fat != 32 && !bpb.rde) 53313978Smrkam bpb.rde = DEFRDE; 53413978Smrkam rds = howmany(bpb.rde, bpb.bps / sizeof(struct de)); 53513978Smrkam if (!bpb.spc) 53613978Smrkam for (bpb.spc = howmany(fat == 16 ? DEFBLK16 : DEFBLK, bpb.bps); 53713978Smrkam bpb.spc < MAXSPC && 53813978Smrkam bpb.res + 53913978Smrkam howmany((RESFTE + maxcls(fat)) * (fat / BPN), 54013978Smrkam bpb.bps * NPB) * bpb.nft + 54113978Smrkam rds + 54213978Smrkam (u_int64_t)(maxcls(fat) + 1) * bpb.spc <= bpb.bsec; 54313978Smrkam bpb.spc <<= 1); 54413978Smrkam if (fat != 32 && bpb.bspf > MAXU16) 54513978Smrkam errx(1, "too many sectors/FAT for FAT12/16"); 54613978Smrkam x1 = bpb.res + rds; 54713978Smrkam x = bpb.bspf ? bpb.bspf : 1; 54813978Smrkam if (x1 + (u_int64_t)x * bpb.nft > bpb.bsec) 54913978Smrkam errx(1, "meta data exceeds file system size"); 55013978Smrkam x1 += x * bpb.nft; 55113978Smrkam x = (u_int64_t)(bpb.bsec - x1) * bpb.bps * NPB / 55213978Smrkam (bpb.spc * bpb.bps * NPB + fat / BPN * bpb.nft); 55313978Smrkam x2 = howmany((RESFTE + MIN(x, maxcls(fat))) * (fat / BPN), 55413978Smrkam bpb.bps * NPB); 55513978Smrkam if (!bpb.bspf) { 55613978Smrkam bpb.bspf = x2; 55713978Smrkam x1 += (bpb.bspf - 1) * bpb.nft; 55813978Smrkam } 55913978Smrkam cls = (bpb.bsec - x1) / bpb.spc; 56013978Smrkam x = (u_int64_t)bpb.bspf * bpb.bps * NPB / (fat / BPN) - RESFTE; 56113978Smrkam if (cls > x) 56213978Smrkam cls = x; 56313978Smrkam if (bpb.bspf < x2) 56413978Smrkam warnx("warning: sectors/FAT limits file system to %u clusters", 56513978Smrkam cls); 56613978Smrkam if (cls < mincls(fat)) 56713978Smrkam errx(1, "%u clusters too few clusters for FAT%u, need %u", cls, fat, 56813978Smrkam mincls(fat)); 56913978Smrkam if (cls > maxcls(fat)) { 57013978Smrkam cls = maxcls(fat); 57113978Smrkam bpb.bsec = x1 + (cls + 1) * bpb.spc - 1; 57213978Smrkam warnx("warning: FAT type limits file system to %u sectors", 57313978Smrkam bpb.bsec); 57413978Smrkam } 57513978Smrkam printf("%s: %u sector%s in %u FAT%u cluster%s " 57613978Smrkam "(%u bytes/cluster)\n", fname, cls * bpb.spc, 57713978Smrkam cls * bpb.spc == 1 ? "" : "s", cls, fat, 57813978Smrkam cls == 1 ? "" : "s", bpb.bps * bpb.spc); 57913978Smrkam if (!bpb.mid) 58013978Smrkam bpb.mid = !bpb.hid ? 0xf0 : 0xf8; 58113978Smrkam if (fat == 32) 58213978Smrkam bpb.rdcl = RESFTE; 58313978Smrkam if (bpb.hid + bpb.bsec <= MAXU16) { 58413978Smrkam bpb.sec = bpb.bsec; 58513978Smrkam bpb.bsec = 0; 58613978Smrkam } 58713978Smrkam if (fat != 32) { 58813978Smrkam bpb.spf = bpb.bspf; 58913978Smrkam bpb.bspf = 0; 59013978Smrkam } 59113978Smrkam print_bpb(&bpb); 59213978Smrkam if (!opt_N) { 59313978Smrkam gettimeofday(&tv, NULL); 59413978Smrkam now = tv.tv_sec; 59513978Smrkam tm = localtime(&now); 59613978Smrkam if (!(img = malloc(bpb.bps))) 59713978Smrkam err(1, NULL); 59813978Smrkam dir = bpb.res + (bpb.spf ? bpb.spf : bpb.bspf) * bpb.nft; 59913978Smrkam for (lsn = 0; lsn < dir + (fat == 32 ? bpb.spc : rds); lsn++) { 60013978Smrkam x = lsn; 60113978Smrkam if (opt_B && 60213978Smrkam fat == 32 && bpb.bkbs != MAXU16 && 60313978Smrkam bss <= bpb.bkbs && x >= bpb.bkbs) { 60413978Smrkam x -= bpb.bkbs; 60513978Smrkam if (!x && lseek(fd1, opt_ofs, SEEK_SET)) 60613978Smrkam err(1, "%s", bname); 60713978Smrkam } 60813978Smrkam if (opt_B && x < bss) { 60913978Smrkam if ((n = read(fd1, img, bpb.bps)) == -1) 61013978Smrkam err(1, "%s", bname); 61113978Smrkam if ((unsigned)n != bpb.bps) 61213978Smrkam errx(1, "%s: can't read sector %u", bname, x); 61313978Smrkam } else 61413978Smrkam memset(img, 0, bpb.bps); 61513978Smrkam if (!lsn || 61613978Smrkam (fat == 32 && bpb.bkbs != MAXU16 && lsn == bpb.bkbs)) { 61713978Smrkam x1 = sizeof(struct bs); 61813978Smrkam bsbpb = (struct bsbpb *)(img + x1); 61913978Smrkam mk2(bsbpb->bps, bpb.bps); 62013978Smrkam mk1(bsbpb->spc, bpb.spc); 62113978Smrkam mk2(bsbpb->res, bpb.res); 62213978Smrkam mk1(bsbpb->nft, bpb.nft); 62313978Smrkam mk2(bsbpb->rde, bpb.rde); 62413978Smrkam mk2(bsbpb->sec, bpb.sec); 62513978Smrkam mk1(bsbpb->mid, bpb.mid); 62613978Smrkam mk2(bsbpb->spf, bpb.spf); 62713978Smrkam mk2(bsbpb->spt, bpb.spt); 62813978Smrkam mk2(bsbpb->hds, bpb.hds); 62913978Smrkam mk4(bsbpb->hid, bpb.hid); 63013978Smrkam mk4(bsbpb->bsec, bpb.bsec); 63113978Smrkam x1 += sizeof(struct bsbpb); 63213978Smrkam if (fat == 32) { 63313978Smrkam bsxbpb = (struct bsxbpb *)(img + x1); 63413978Smrkam mk4(bsxbpb->bspf, bpb.bspf); 63513978Smrkam mk2(bsxbpb->xflg, 0); 63613978Smrkam mk2(bsxbpb->vers, 0); 63713978Smrkam mk4(bsxbpb->rdcl, bpb.rdcl); 63813978Smrkam mk2(bsxbpb->infs, bpb.infs); 63913978Smrkam mk2(bsxbpb->bkbs, bpb.bkbs); 64013978Smrkam x1 += sizeof(struct bsxbpb); 64113978Smrkam } 64213978Smrkam bsx = (struct bsx *)(img + x1); 64313978Smrkam mk1(bsx->sig, 0x29); 64413978Smrkam if (Iflag) 64513978Smrkam x = opt_I; 64613978Smrkam else 64713978Smrkam x = (((u_int)(1 + tm->tm_mon) << 8 | 64813978Smrkam (u_int)tm->tm_mday) + 64913978Smrkam ((u_int)tm->tm_sec << 8 | 65013978Smrkam (u_int)(tv.tv_usec / 10))) << 16 | 65113978Smrkam ((u_int)(1900 + tm->tm_year) + 65213978Smrkam ((u_int)tm->tm_hour << 8 | 65313978Smrkam (u_int)tm->tm_min)); 65413978Smrkam mk4(bsx->volid, x); 65513978Smrkam mklabel(bsx->label, opt_L ? opt_L : "NO NAME"); 65613978Smrkam sprintf(buf, "FAT%u", fat); 65713978Smrkam setstr(bsx->type, buf, sizeof(bsx->type)); 65813978Smrkam if (!opt_B) { 65913978Smrkam x1 += sizeof(struct bsx); 66013978Smrkam bs = (struct bs *)img; 66113978Smrkam mk1(bs->jmp[0], 0xeb); 66213978Smrkam mk1(bs->jmp[1], x1 - 2); 66313978Smrkam mk1(bs->jmp[2], 0x90); 66413978Smrkam setstr(bs->oem, opt_O ? opt_O : "BSD 4.4", 66513978Smrkam sizeof(bs->oem)); 66613978Smrkam memcpy(img + x1, bootcode, sizeof(bootcode)); 66713978Smrkam mk2(img + MINBPS - 2, DOSMAGIC); 66813978Smrkam } 66913978Smrkam } else if (fat == 32 && bpb.infs != MAXU16 && 67013978Smrkam (lsn == bpb.infs || 67113978Smrkam (bpb.bkbs != MAXU16 && 67213978Smrkam lsn == bpb.bkbs + bpb.infs))) { 67313978Smrkam mk4(img, 0x41615252); 67413978Smrkam mk4(img + MINBPS - 28, 0x61417272); 67513978Smrkam mk4(img + MINBPS - 24, 0xffffffff); 67613978Smrkam mk4(img + MINBPS - 20, bpb.rdcl); 67713978Smrkam mk2(img + MINBPS - 2, DOSMAGIC); 67813978Smrkam } else if (lsn >= bpb.res && lsn < dir && 67913978Smrkam !((lsn - bpb.res) % 68013978Smrkam (bpb.spf ? bpb.spf : bpb.bspf))) { 68113978Smrkam mk1(img[0], bpb.mid); 68213978Smrkam for (x = 1; x < fat * (fat == 32 ? 3 : 2) / 8; x++) 68313978Smrkam mk1(img[x], fat == 32 && x % 4 == 3 ? 0x0f : 0xff); 68413978Smrkam } else if (lsn == dir && opt_L) { 68513978Smrkam de = (struct de *)img; 68613978Smrkam mklabel(de->namext, opt_L); 68713978Smrkam mk1(de->attr, 050); 68813978Smrkam x = (u_int)tm->tm_hour << 11 | 68913978Smrkam (u_int)tm->tm_min << 5 | 69013978Smrkam (u_int)tm->tm_sec >> 1; 69113978Smrkam mk2(de->time, x); 69213978Smrkam x = (u_int)(tm->tm_year - 80) << 9 | 69313978Smrkam (u_int)(tm->tm_mon + 1) << 5 | 69413978Smrkam (u_int)tm->tm_mday; 69513978Smrkam mk2(de->date, x); 69613978Smrkam } 69713978Smrkam if ((n = write(fd, img, bpb.bps)) == -1) 69813978Smrkam err(1, "%s", fname); 69913978Smrkam if ((unsigned)n != bpb.bps) 70013978Smrkam errx(1, "%s: can't write sector %u", fname, lsn); 70113978Smrkam } 70213978Smrkam } 70313978Smrkam return 0; 70413978Smrkam} 70513978Smrkam 70613978Smrkam/* 70713978Smrkam * Exit with error if file system is mounted. 70813978Smrkam */ 70913978Smrkamstatic void 71013978Smrkamcheck_mounted(const char *fname, mode_t mode) 71113978Smrkam{ 71213978Smrkam struct statfs *mp; 71313978Smrkam const char *s1, *s2; 71413978Smrkam size_t len; 71513978Smrkam int n, r; 71613978Smrkam 71713978Smrkam if (!(n = getmntinfo(&mp, MNT_NOWAIT))) 71813978Smrkam err(1, "getmntinfo"); 71913978Smrkam len = strlen(_PATH_DEV); 72013978Smrkam s1 = fname; 72113978Smrkam if (!strncmp(s1, _PATH_DEV, len)) 72213978Smrkam s1 += len; 72313978Smrkam r = S_ISCHR(mode) && s1 != fname && *s1 == 'r'; 72413978Smrkam for (; n--; mp++) { 72513978Smrkam s2 = mp->f_mntfromname; 72613978Smrkam if (!strncmp(s2, _PATH_DEV, len)) 72713978Smrkam s2 += len; 72813978Smrkam if ((r && s2 != mp->f_mntfromname && !strcmp(s1 + 1, s2)) || 72913978Smrkam !strcmp(s1, s2)) 73013978Smrkam errx(1, "%s is mounted on %s", fname, mp->f_mntonname); 73113978Smrkam } 73213978Smrkam} 73313978Smrkam 73413978Smrkam/* 73513978Smrkam * Get a standard format. 73613978Smrkam */ 73713978Smrkamstatic void 73813978Smrkamgetstdfmt(const char *fmt, struct bpb *bpb) 73913978Smrkam{ 74013978Smrkam u_int x, i; 74113978Smrkam 74213978Smrkam x = sizeof(stdfmt) / sizeof(stdfmt[0]); 74313978Smrkam for (i = 0; i < x && strcmp(fmt, stdfmt[i].name); i++); 74413978Smrkam if (i == x) 74513978Smrkam errx(1, "%s: unknown standard format", fmt); 74613978Smrkam *bpb = stdfmt[i].bpb; 74713978Smrkam} 74813978Smrkam 74913978Smrkam/* 75013978Smrkam * Get disk slice, partition, and geometry information. 75113978Smrkam */ 75213978Smrkamstatic void 75313978Smrkamgetdiskinfo(int fd, const char *fname, const char *dtype, __unused int oflag, 75413978Smrkam struct bpb *bpb) 75513978Smrkam{ 75613978Smrkam struct disklabel *lp, dlp; 75713978Smrkam struct fd_type type; 75813978Smrkam off_t ms, hs = 0; 75913978Smrkam 76013978Smrkam lp = NULL; 76113978Smrkam 76213978Smrkam /* If the user specified a disk type, try to use that */ 76313978Smrkam if (dtype != NULL) { 76413978Smrkam lp = getdiskbyname(dtype); 76513978Smrkam } 76613978Smrkam 76713978Smrkam /* Maybe it's a floppy drive */ 76813978Smrkam if (lp == NULL) { 76913978Smrkam if (ioctl(fd, DIOCGMEDIASIZE, &ms) == -1) { 77013978Smrkam struct stat st; 77113978Smrkam 77213978Smrkam if (fstat(fd, &st)) 77313978Smrkam err(1, "Cannot get disk size"); 77413978Smrkam /* create a fake geometry for a file image */ 77513978Smrkam ms = st.st_size; 77613978Smrkam dlp.d_secsize = 512; 77713978Smrkam dlp.d_nsectors = 63; 77813978Smrkam dlp.d_ntracks = 255; 77913978Smrkam dlp.d_secperunit = ms / dlp.d_secsize; 78013978Smrkam lp = &dlp; 78113978Smrkam } else if (ioctl(fd, FD_GTYPE, &type) != -1) { 78213978Smrkam dlp.d_secsize = 128 << type.secsize; 78313978Smrkam dlp.d_nsectors = type.sectrac; 78413978Smrkam dlp.d_ntracks = type.heads; 78513978Smrkam dlp.d_secperunit = ms / dlp.d_secsize; 78613978Smrkam lp = &dlp; 78713978Smrkam } 78813978Smrkam } 78913978Smrkam 79013978Smrkam /* Maybe it's a fixed drive */ 79113978Smrkam if (lp == NULL) { 79213978Smrkam if (ioctl(fd, DIOCGDINFO, &dlp) == -1) { 79313978Smrkam if (bpb->bps == 0 && ioctl(fd, DIOCGSECTORSIZE, &dlp.d_secsize) == -1) 79413978Smrkam errx(1, "Cannot get sector size, %s", strerror(errno)); 79513978Smrkam 79613978Smrkam /* XXX Should we use bpb->bps if it's set? */ 79713978Smrkam dlp.d_secperunit = ms / dlp.d_secsize; 79813978Smrkam 79913978Smrkam if (bpb->spt == 0 && ioctl(fd, DIOCGFWSECTORS, &dlp.d_nsectors) == -1) { 80013978Smrkam warnx("Cannot get number of sectors per track, %s", strerror(errno)); 80113978Smrkam dlp.d_nsectors = 63; 80213978Smrkam } 80313978Smrkam if (bpb->hds == 0 && ioctl(fd, DIOCGFWHEADS, &dlp.d_ntracks) == -1) { 80413978Smrkam warnx("Cannot get number of heads, %s", strerror(errno)); 80513978Smrkam if (dlp.d_secperunit <= 63*1*1024) 80613978Smrkam dlp.d_ntracks = 1; 80713978Smrkam else if (dlp.d_secperunit <= 63*16*1024) 80813978Smrkam dlp.d_ntracks = 16; 80913978Smrkam else 81013978Smrkam dlp.d_ntracks = 255; 81113978Smrkam } 81213978Smrkam } 81313978Smrkam 81413978Smrkam hs = (ms / dlp.d_secsize) - dlp.d_secperunit; 81513978Smrkam lp = &dlp; 81613978Smrkam } 81713978Smrkam 81813978Smrkam if (bpb->bps == 0) 81913978Smrkam bpb->bps = ckgeom(fname, lp->d_secsize, "bytes/sector"); 82013978Smrkam if (bpb->spt == 0) 82113978Smrkam bpb->spt = ckgeom(fname, lp->d_nsectors, "sectors/track"); 82213978Smrkam if (bpb->hds == 0) 82313978Smrkam bpb->hds = ckgeom(fname, lp->d_ntracks, "drive heads"); 82413978Smrkam if (bpb->bsec == 0) 82513978Smrkam bpb->bsec = lp->d_secperunit; 82613978Smrkam if (bpb->hid == 0) 82713978Smrkam bpb->hid = hs; 82813978Smrkam} 82913978Smrkam 83013978Smrkam/* 83113978Smrkam * Print out BPB values. 83213978Smrkam */ 83313978Smrkamstatic void 83413978Smrkamprint_bpb(struct bpb *bpb) 83513978Smrkam{ 83613978Smrkam printf("bps=%u spc=%u res=%u nft=%u", bpb->bps, bpb->spc, bpb->res, 83713978Smrkam bpb->nft); 83813978Smrkam if (bpb->rde) 83913978Smrkam printf(" rde=%u", bpb->rde); 84013978Smrkam if (bpb->sec) 84113978Smrkam printf(" sec=%u", bpb->sec); 84213978Smrkam printf(" mid=%#x", bpb->mid); 84313978Smrkam if (bpb->spf) 84413978Smrkam printf(" spf=%u", bpb->spf); 84513978Smrkam printf(" spt=%u hds=%u hid=%u", bpb->spt, bpb->hds, bpb->hid); 84613978Smrkam if (bpb->bsec) 84713978Smrkam printf(" bsec=%u", bpb->bsec); 84813978Smrkam if (!bpb->spf) { 84913978Smrkam printf(" bspf=%u rdcl=%u", bpb->bspf, bpb->rdcl); 85013978Smrkam printf(" infs="); 85113978Smrkam printf(bpb->infs == MAXU16 ? "%#x" : "%u", bpb->infs); 85213978Smrkam printf(" bkbs="); 85313978Smrkam printf(bpb->bkbs == MAXU16 ? "%#x" : "%u", bpb->bkbs); 85413978Smrkam } 85513978Smrkam printf("\n"); 85613978Smrkam} 85713978Smrkam 85813978Smrkam/* 85913978Smrkam * Check a disk geometry value. 86013978Smrkam */ 86113978Smrkamstatic u_int 86213978Smrkamckgeom(const char *fname, u_int val, const char *msg) 86313978Smrkam{ 86413978Smrkam if (!val) 86513978Smrkam errx(1, "%s: no default %s", fname, msg); 86613978Smrkam if (val > MAXU16) 86713978Smrkam errx(1, "%s: illegal %s %d", fname, msg, val); 86813978Smrkam return val; 86913978Smrkam} 87013978Smrkam 87113978Smrkam/* 87213978Smrkam * Convert and check a numeric option argument. 87313978Smrkam */ 87413978Smrkamstatic u_int 87513978Smrkamargtou(const char *arg, u_int lo, u_int hi, const char *msg) 87613978Smrkam{ 87713978Smrkam char *s; 87813978Smrkam u_long x; 87913978Smrkam 88013978Smrkam errno = 0; 88113978Smrkam x = strtoul(arg, &s, 0); 88213978Smrkam if (errno || !*arg || *s || x < lo || x > hi) 88313978Smrkam errx(1, "%s: bad %s", arg, msg); 88413978Smrkam return x; 88513978Smrkam} 88613978Smrkam 88713978Smrkam/* 88813978Smrkam * Same for off_t, with optional skmgpP suffix 88913978Smrkam */ 89013978Smrkamstatic off_t 89113978Smrkamargtooff(const char *arg, const char *msg) 89213978Smrkam{ 89313978Smrkam char *s; 89413978Smrkam off_t x; 89513978Smrkam 89613978Smrkam x = strtoll(arg, &s, 0); 89713978Smrkam /* allow at most one extra char */ 89813978Smrkam if (errno || x < 0 || (s[0] && s[1]) ) 89913978Smrkam errx(1, "%s: bad %s", arg, msg); 90013978Smrkam if (*s) { /* the extra char is the multiplier */ 90113978Smrkam switch (*s) { 90213978Smrkam default: 90313978Smrkam errx(1, "%s: bad %s", arg, msg); 90413978Smrkam /* notreached */ 90513978Smrkam 90613978Smrkam case 's': /* sector */ 90713978Smrkam case 'S': 90813978Smrkam x <<= 9; /* times 512 */ 90913978Smrkam break; 91013978Smrkam 91113978Smrkam case 'k': /* kilobyte */ 91213978Smrkam case 'K': 91313978Smrkam x <<= 10; /* times 1024 */ 91413978Smrkam break; 91513978Smrkam 91613978Smrkam case 'm': /* megabyte */ 91713978Smrkam case 'M': 91813978Smrkam x <<= 20; /* times 1024*1024 */ 91913978Smrkam break; 92013978Smrkam 92113978Smrkam case 'g': /* gigabyte */ 92213978Smrkam case 'G': 92313978Smrkam x <<= 30; /* times 1024*1024*1024 */ 92413978Smrkam break; 92513978Smrkam 92613978Smrkam case 'p': /* partition start */ 92713978Smrkam case 'P': /* partition start */ 92813978Smrkam case 'l': /* partition length */ 92913978Smrkam case 'L': /* partition length */ 93013978Smrkam errx(1, "%s: not supported yet %s", arg, msg); 93113978Smrkam /* notreached */ 93213978Smrkam } 93313978Smrkam } 93413978Smrkam return x; 93513978Smrkam} 93613978Smrkam 93713978Smrkam/* 93813978Smrkam * Check a volume label. 93913978Smrkam */ 94013978Smrkamstatic int 94113978Smrkamoklabel(const char *src) 94213978Smrkam{ 94313978Smrkam int c, i; 94413978Smrkam 94513978Smrkam for (i = 0; i <= 11; i++) { 94613978Smrkam c = (u_char)*src++; 94713978Smrkam if (c < ' ' + !i || strchr("\"*+,./:;<=>?[\\]|", c)) 94813978Smrkam break; 94913978Smrkam } 95013978Smrkam return i && !c; 95113978Smrkam} 95213978Smrkam 95313978Smrkam/* 95413978Smrkam * Make a volume label. 95513978Smrkam */ 95613978Smrkamstatic void 95713978Smrkammklabel(u_int8_t *dest, const char *src) 95813978Smrkam{ 95913978Smrkam int c, i; 96013978Smrkam 96113978Smrkam for (i = 0; i < 11; i++) { 96213978Smrkam c = *src ? toupper(*src++) : ' '; 96313978Smrkam *dest++ = !i && c == '\xe5' ? 5 : c; 96413978Smrkam } 96513978Smrkam} 96613978Smrkam 96713978Smrkam/* 96813978Smrkam * Copy string, padding with spaces. 96913978Smrkam */ 97013978Smrkamstatic void 97113978Smrkamsetstr(u_int8_t *dest, const char *src, size_t len) 97213978Smrkam{ 97313978Smrkam while (len--) 97413978Smrkam *dest++ = *src ? *src++ : ' '; 97513978Smrkam} 97613978Smrkam 97713978Smrkam/* 97813978Smrkam * Print usage message. 97913978Smrkam */ 98013978Smrkamstatic void 98113978Smrkamusage(void) 98213978Smrkam{ 98313978Smrkam fprintf(stderr, 98413978Smrkam "usage: newfs_msdos [ -options ] special [disktype]\n" 98513978Smrkam "where the options are:\n" 98613978Smrkam "\t-@ create file system at specified offset\n" 98713978Smrkam "\t-B get bootstrap from file\n" 98813978Smrkam "\t-C create image file with specified size\n" 98913978Smrkam "\t-F FAT type (12, 16, or 32)\n" 99013978Smrkam "\t-I volume ID\n" 99113978Smrkam "\t-L volume label\n" 99213978Smrkam "\t-N don't create file system: just print out parameters\n" 99313978Smrkam "\t-O OEM string\n" 99413978Smrkam "\t-S bytes/sector\n" 99513978Smrkam "\t-a sectors/FAT\n" 99613978Smrkam "\t-b block size\n" 99713978Smrkam "\t-c sectors/cluster\n" 99813978Smrkam "\t-e root directory entries\n" 99913978Smrkam "\t-f standard format\n" 100013978Smrkam "\t-h drive heads\n" 100113978Smrkam "\t-i file system info sector\n" 100213978Smrkam "\t-k backup boot sector\n" 100313978Smrkam "\t-m media descriptor\n" 100413978Smrkam "\t-n number of FATs\n" 100513978Smrkam "\t-o hidden sectors\n" 100613978Smrkam "\t-r reserved sectors\n" 100713978Smrkam "\t-s file system size (sectors)\n" 100813978Smrkam "\t-u sectors/track\n"); 100913978Smrkam exit(1); 101013978Smrkam} 101113978Smrkam