newfs_msdos.c revision 189112
1229997Sken/* 2229997Sken * Copyright (c) 1998 Robert Nordier 3229997Sken * All rights reserved. 4232604Strasz * 5229997Sken * Redistribution and use in source and binary forms, with or without 6229997Sken * modification, are permitted provided that the following conditions 7232604Strasz * are met: 8232604Strasz * 1. Redistributions of source code must retain the above copyright 9232604Strasz * notice, this list of conditions and the following disclaimer. 10229997Sken * 2. Redistributions in binary form must reproduce the above copyright 11229997Sken * notice, this list of conditions and the following disclaimer in 12229997Sken * the documentation and/or other materials provided with the 13229997Sken * distribution. 14229997Sken * 15229997Sken * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS 16229997Sken * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17229997Sken * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18229997Sken * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY 19229997Sken * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20229997Sken * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 21229997Sken * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 22229997Sken * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 23229997Sken * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24229997Sken * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 25229997Sken * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26229997Sken */ 27229997Sken 28229997Sken#ifndef lint 29229997Skenstatic const char rcsid[] = 30229997Sken "$FreeBSD: head/sbin/newfs_msdos/newfs_msdos.c 189112 2009-02-27 17:29:48Z avg $"; 31229997Sken#endif /* not lint */ 32229997Sken 33229997Sken#include <sys/param.h> 34229997Sken#include <sys/fdcio.h> 35229997Sken#include <sys/disk.h> 36229997Sken#include <sys/disklabel.h> 37229997Sken#include <sys/mount.h> 38229997Sken#include <sys/stat.h> 39229997Sken#include <sys/time.h> 40229997Sken 41229997Sken#include <ctype.h> 42229997Sken#include <err.h> 43229997Sken#include <errno.h> 44229997Sken#include <fcntl.h> 45229997Sken#include <inttypes.h> 46229997Sken#include <paths.h> 47229997Sken#include <stdio.h> 48229997Sken#include <stdlib.h> 49229997Sken#include <string.h> 50229997Sken#include <time.h> 51229997Sken#include <unistd.h> 52264274Smav 53229997Sken#define MAXU16 0xffff /* maximum unsigned 16-bit quantity */ 54229997Sken#define BPN 4 /* bits per nibble */ 55229997Sken#define NPB 2 /* nibbles per byte */ 56229997Sken 57229997Sken#define DOSMAGIC 0xaa55 /* DOS magic number */ 58229997Sken#define MINBPS 512 /* minimum bytes per sector */ 59229997Sken#define MAXSPC 128 /* maximum sectors per cluster */ 60229997Sken#define MAXNFT 16 /* maximum number of FATs */ 61229997Sken#define DEFBLK 4096 /* default block size */ 62229997Sken#define DEFBLK16 2048 /* default block size FAT16 */ 63229997Sken#define DEFRDE 512 /* default root directory entries */ 64229997Sken#define RESFTE 2 /* reserved FAT entries */ 65229997Sken#define MINCLS12 1 /* minimum FAT12 clusters */ 66229997Sken#define MINCLS16 0x1000 /* minimum FAT16 clusters */ 67229997Sken#define MINCLS32 2 /* minimum FAT32 clusters */ 68229997Sken#define MAXCLS12 0xfed /* maximum FAT12 clusters */ 69229997Sken#define MAXCLS16 0xfff5 /* maximum FAT16 clusters */ 70229997Sken#define MAXCLS32 0xffffff5 /* maximum FAT32 clusters */ 71275474Smav 72229997Sken#define mincls(fat) ((fat) == 12 ? MINCLS12 : \ 73229997Sken (fat) == 16 ? MINCLS16 : \ 74229997Sken MINCLS32) 75229997Sken 76229997Sken#define maxcls(fat) ((fat) == 12 ? MAXCLS12 : \ 77229997Sken (fat) == 16 ? MAXCLS16 : \ 78229997Sken MAXCLS32) 79229997Sken 80229997Sken#define mk1(p, x) \ 81229997Sken (p) = (u_int8_t)(x) 82229997Sken 83229997Sken#define mk2(p, x) \ 84229997Sken (p)[0] = (u_int8_t)(x), \ 85229997Sken (p)[1] = (u_int8_t)((x) >> 010) 86229997Sken 87229997Sken#define mk4(p, x) \ 88287621Smav (p)[0] = (u_int8_t)(x), \ 89229997Sken (p)[1] = (u_int8_t)((x) >> 010), \ 90287621Smav (p)[2] = (u_int8_t)((x) >> 020), \ 91229997Sken (p)[3] = (u_int8_t)((x) >> 030) 92229997Sken 93229997Sken#define argto1(arg, lo, msg) argtou(arg, lo, 0xff, msg) 94264886Smav#define argto2(arg, lo, msg) argtou(arg, lo, 0xffff, msg) 95264886Smav#define argto4(arg, lo, msg) argtou(arg, lo, 0xffffffff, msg) 96229997Sken#define argtox(arg, lo, msg) argtou(arg, lo, UINT_MAX, msg) 97267537Smav 98267537Smavstruct bs { 99264886Smav u_int8_t jmp[3]; /* bootstrap entry point */ 100267537Smav u_int8_t oem[8]; /* OEM name and version */ 101267537Smav}; 102229997Sken 103229997Skenstruct bsbpb { 104229997Sken u_int8_t bps[2]; /* bytes per sector */ 105229997Sken u_int8_t spc; /* sectors per cluster */ 106229997Sken u_int8_t res[2]; /* reserved sectors */ 107229997Sken u_int8_t nft; /* number of FATs */ 108229997Sken u_int8_t rde[2]; /* root directory entries */ 109229997Sken u_int8_t sec[2]; /* total sectors */ 110267519Smav u_int8_t mid; /* media descriptor */ 111267519Smav u_int8_t spf[2]; /* sectors per FAT */ 112267537Smav u_int8_t spt[2]; /* sectors per track */ 113267537Smav u_int8_t hds[2]; /* drive heads */ 114267519Smav u_int8_t hid[4]; /* hidden sectors */ 115229997Sken u_int8_t bsec[4]; /* big total sectors */ 116229997Sken}; 117229997Sken 118229997Skenstruct bsxbpb { 119229997Sken u_int8_t bspf[4]; /* big sectors per FAT */ 120229997Sken u_int8_t xflg[2]; /* FAT control flags */ 121229997Sken u_int8_t vers[2]; /* file system version */ 122229997Sken u_int8_t rdcl[4]; /* root directory start cluster */ 123229997Sken u_int8_t infs[2]; /* file system info sector */ 124229997Sken u_int8_t bkbs[2]; /* backup boot sector */ 125229997Sken u_int8_t rsvd[12]; /* reserved */ 126229997Sken}; 127229997Sken 128229997Skenstruct bsx { 129229997Sken u_int8_t drv; /* drive number */ 130229997Sken u_int8_t rsvd; /* reserved */ 131229997Sken u_int8_t sig; /* extended boot signature */ 132229997Sken u_int8_t volid[4]; /* volume ID number */ 133229997Sken u_int8_t label[11]; /* volume label */ 134229997Sken u_int8_t type[8]; /* file system type */ 135229997Sken}; 136229997Sken 137229997Skenstruct de { 138229997Sken u_int8_t namext[11]; /* name and extension */ 139229997Sken u_int8_t attr; /* attributes */ 140229997Sken u_int8_t rsvd[10]; /* reserved */ 141229997Sken u_int8_t time[2]; /* creation time */ 142274154Smav u_int8_t date[2]; /* creation date */ 143274154Smav u_int8_t clus[2]; /* starting cluster */ 144229997Sken u_int8_t size[4]; /* size */ 145229997Sken}; 146229997Sken 147229997Skenstruct bpb { 148229997Sken u_int bps; /* bytes per sector */ 149229997Sken u_int spc; /* sectors per cluster */ 150272911Smav u_int res; /* reserved sectors */ 151229997Sken u_int nft; /* number of FATs */ 152229997Sken u_int rde; /* root directory entries */ 153229997Sken u_int sec; /* total sectors */ 154229997Sken u_int mid; /* media descriptor */ 155229997Sken u_int spf; /* sectors per FAT */ 156229997Sken u_int spt; /* sectors per track */ 157229997Sken u_int hds; /* drive heads */ 158264274Smav u_int hid; /* hidden sectors */ 159275474Smav u_int bsec; /* big total sectors */ 160274154Smav u_int bspf; /* big sectors per FAT */ 161229997Sken u_int rdcl; /* root directory start cluster */ 162229997Sken u_int infs; /* file system info sector */ 163229997Sken u_int bkbs; /* backup boot sector */ 164229997Sken}; 165229997Sken 166229997Sken#define BPBGAP 0, 0, 0, 0, 0, 0 167229997Sken 168287499Smavstatic struct { 169229997Sken const char *name; 170229997Sken struct bpb bpb; 171229997Sken} stdfmt[] = { 172229997Sken {"160", {512, 1, 1, 2, 64, 320, 0xfe, 1, 8, 1, BPBGAP}}, 173275474Smav {"180", {512, 1, 1, 2, 64, 360, 0xfc, 2, 9, 1, BPBGAP}}, 174229997Sken {"320", {512, 2, 1, 2, 112, 640, 0xff, 1, 8, 2, BPBGAP}}, 175229997Sken {"360", {512, 2, 1, 2, 112, 720, 0xfd, 2, 9, 2, BPBGAP}}, 176267877Smav {"640", {512, 2, 1, 2, 112, 1280, 0xfb, 2, 8, 2, BPBGAP}}, 177267877Smav {"720", {512, 2, 1, 2, 112, 1440, 0xf9, 3, 9, 2, BPBGAP}}, 178229997Sken {"1200", {512, 1, 1, 2, 224, 2400, 0xf9, 7, 15, 2, BPBGAP}}, 179229997Sken {"1232", {1024,1, 1, 2, 192, 1232, 0xfe, 2, 8, 2, BPBGAP}}, 180229997Sken {"1440", {512, 1, 1, 2, 224, 2880, 0xf0, 9, 18, 2, BPBGAP}}, 181229997Sken {"2880", {512, 2, 1, 2, 240, 5760, 0xf0, 9, 36, 2, BPBGAP}} 182229997Sken}; 183229997Sken 184229997Skenstatic u_int8_t bootcode[] = { 185229997Sken 0xfa, /* cli */ 186229997Sken 0x31, 0xc0, /* xor ax,ax */ 187229997Sken 0x8e, 0xd0, /* mov ss,ax */ 188229997Sken 0xbc, 0x00, 0x7c, /* mov sp,7c00h */ 189229997Sken 0xfb, /* sti */ 190229997Sken 0x8e, 0xd8, /* mov ds,ax */ 191229997Sken 0xe8, 0x00, 0x00, /* call $ + 3 */ 192229997Sken 0x5e, /* pop si */ 193229997Sken 0x83, 0xc6, 0x19, /* add si,+19h */ 194229997Sken 0xbb, 0x07, 0x00, /* mov bx,0007h */ 195229997Sken 0xfc, /* cld */ 196229997Sken 0xac, /* lodsb */ 197229997Sken 0x84, 0xc0, /* test al,al */ 198229997Sken 0x74, 0x06, /* jz $ + 8 */ 199229997Sken 0xb4, 0x0e, /* mov ah,0eh */ 200229997Sken 0xcd, 0x10, /* int 10h */ 201229997Sken 0xeb, 0xf5, /* jmp $ - 9 */ 202229997Sken 0x30, 0xe4, /* xor ah,ah */ 203229997Sken 0xcd, 0x16, /* int 16h */ 204229997Sken 0xcd, 0x19, /* int 19h */ 205229997Sken 0x0d, 0x0a, 206229997Sken 'N', 'o', 'n', '-', 's', 'y', 's', 't', 207229997Sken 'e', 'm', ' ', 'd', 'i', 's', 'k', 208229997Sken 0x0d, 0x0a, 209286353Smav 'P', 'r', 'e', 's', 's', ' ', 'a', 'n', 210229997Sken 'y', ' ', 'k', 'e', 'y', ' ', 't', 'o', 211229997Sken ' ', 'r', 'e', 'b', 'o', 'o', 't', 212264274Smav 0x0d, 0x0a, 213229997Sken 0 214229997Sken}; 215287621Smav 216287621Smavstatic void check_mounted(const char *, mode_t); 217229997Skenstatic void getstdfmt(const char *, struct bpb *); 218229997Skenstatic void getdiskinfo(int, const char *, const char *, int, 219229997Sken struct bpb *); 220267992Shselaskystatic void print_bpb(struct bpb *); 221229997Skenstatic u_int ckgeom(const char *, u_int, const char *); 222229997Skenstatic u_int argtou(const char *, u_int, u_int, const char *); 223229997Skenstatic off_t argtooff(const char *, const char *); 224229997Skenstatic int oklabel(const char *); 225229997Skenstatic void mklabel(u_int8_t *, const char *); 226229997Skenstatic void setstr(u_int8_t *, const char *, size_t); 227229997Skenstatic void usage(void); 228229997Sken 229229997Sken/* 230229997Sken * Construct a FAT12, FAT16, or FAT32 file system. 231229997Sken */ 232275474Smavint 233275474Smavmain(int argc, char *argv[]) 234275481Smav{ 235275481Smav static char opts[] = "@:NB:C:F:I:L:O:S:a:b:c:e:f:h:i:k:m:n:o:r:s:u:"; 236229997Sken static const char *opt_B, *opt_L, *opt_O, *opt_f; 237229997Sken static u_int opt_F, opt_I, opt_S, opt_a, opt_b, opt_c, opt_e; 238264274Smav static u_int opt_h, opt_i, opt_k, opt_m, opt_n, opt_o, opt_r; 239264274Smav static u_int opt_s, opt_u; 240229997Sken static int opt_N; 241229997Sken static int Iflag, mflag, oflag; 242274154Smav char buf[MAXPATHLEN]; 243274154Smav struct stat sb; 244275474Smav struct timeval tv; 245275474Smav struct bpb bpb; 246229997Sken struct tm *tm; 247229997Sken struct bs *bs; 248229997Sken struct bsbpb *bsbpb; 249229997Sken struct bsxbpb *bsxbpb; 250229997Sken struct bsx *bsx; 251229997Sken struct de *de; 252229997Sken u_int8_t *img; 253229997Sken const char *fname, *dtype, *bname; 254229997Sken ssize_t n; 255229997Sken time_t now; 256229997Sken u_int fat, bss, rds, cls, dir, lsn, x, x1, x2; 257229997Sken int ch, fd, fd1; 258229997Sken static off_t opt_create=0, opt_ofs=0; 259229997Sken 260229997Sken while ((ch = getopt(argc, argv, opts)) != -1) 261229997Sken switch (ch) { 262229997Sken case '@': 263229997Sken opt_ofs = argtooff(optarg, "offset"); 264229997Sken break; 265229997Sken case 'N': 266232604Strasz opt_N = 1; 267232604Strasz break; 268232604Strasz case 'B': 269232604Strasz opt_B = optarg; 270232604Strasz break; 271232604Strasz case 'C': 272229997Sken opt_create = argtooff(optarg, "create size"); 273229997Sken break; 274229997Sken case 'F': 275229997Sken if (strcmp(optarg, "12") && 276229997Sken strcmp(optarg, "16") && 277229997Sken strcmp(optarg, "32")) 278274154Smav errx(1, "%s: bad FAT type", optarg); 279229997Sken opt_F = atoi(optarg); 280229997Sken break; 281229997Sken case 'I': 282229997Sken opt_I = argto4(optarg, 0, "volume ID"); 283230334Sken Iflag = 1; 284230334Sken break; 285230334Sken case 'L': 286230334Sken if (!oklabel(optarg)) 287230334Sken errx(1, "%s: bad volume label", optarg); 288230334Sken opt_L = optarg; 289230334Sken break; 290230334Sken case 'O': 291274154Smav if (strlen(optarg) > 8) 292274154Smav errx(1, "%s: bad OEM string", optarg); 293229997Sken opt_O = optarg; 294229997Sken break; 295229997Sken case 'S': 296229997Sken opt_S = argto2(optarg, 1, "bytes/sector"); 297229997Sken break; 298264020Strasz case 'a': 299264020Strasz opt_a = argto4(optarg, 1, "sectors/FAT"); 300229997Sken break; 301229997Sken case 'b': 302229997Sken opt_b = argtox(optarg, 1, "block size"); 303229997Sken opt_c = 0; 304229997Sken break; 305264020Strasz case 'c': 306264020Strasz opt_c = argto1(optarg, 1, "sectors/cluster"); 307229997Sken opt_b = 0; 308229997Sken break; 309229997Sken case 'e': 310229997Sken opt_e = argto2(optarg, 1, "directory entries"); 311229997Sken break; 312229997Sken case 'f': 313229997Sken opt_f = optarg; 314229997Sken break; 315229997Sken case 'h': 316229997Sken opt_h = argto2(optarg, 1, "drive heads"); 317229997Sken break; 318229997Sken case 'i': 319229997Sken opt_i = argto2(optarg, 1, "info sector"); 320229997Sken break; 321229997Sken case 'k': 322229997Sken opt_k = argto2(optarg, 1, "backup sector"); 323229997Sken break; 324267537Smav case 'm': 325267537Smav opt_m = argto1(optarg, 0, "media descriptor"); 326267537Smav mflag = 1; 327267537Smav break; 328267537Smav case 'n': 329267537Smav opt_n = argto1(optarg, 1, "number of FATs"); 330267537Smav break; 331229997Sken case 'o': 332229997Sken opt_o = argto4(optarg, 0, "hidden sectors"); 333229997Sken oflag = 1; 334229997Sken break; 335229997Sken case 'r': 336229997Sken opt_r = argto2(optarg, 1, "reserved sectors"); 337229997Sken break; 338264020Strasz case 's': 339229997Sken opt_s = argto4(optarg, 1, "file system size"); 340229997Sken break; 341229997Sken case 'u': 342229997Sken opt_u = argto2(optarg, 1, "sectors/track"); 343229997Sken break; 344267877Smav default: 345229997Sken usage(); 346264274Smav } 347264274Smav argc -= optind; 348264274Smav argv += optind; 349264274Smav if (argc < 1 || argc > 2) 350267537Smav usage(); 351264274Smav fname = *argv++; 352229997Sken if (!strchr(fname, '/')) { 353229997Sken snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname); 354229997Sken if (!(fname = strdup(buf))) 355229997Sken err(1, NULL); 356229997Sken } 357229997Sken dtype = *argv; 358229997Sken if (opt_create) { 359267537Smav off_t pos; 360229997Sken 361229997Sken if (opt_N) 362267537Smav errx(1, "create (-C) is incompatible with -N"); 363267537Smav fd = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0644); 364229997Sken if (fd == -1) 365267519Smav errx(1, "failed to create %s", fname); 366229997Sken pos = lseek(fd, opt_create - 1, SEEK_SET); 367229997Sken if (write(fd, "\0", 1) != 1) 368229997Sken errx(1, "failed to initialize %jd bytes", (intmax_t)opt_create); 369229997Sken pos = lseek(fd, 0, SEEK_SET); 370229997Sken } else if ((fd = open(fname, opt_N ? O_RDONLY : O_RDWR)) == -1 || 371229997Sken fstat(fd, &sb)) 372229997Sken err(1, "%s", fname); 373229997Sken if (!opt_N) 374229997Sken check_mounted(fname, sb.st_mode); 375229997Sken if (!S_ISCHR(sb.st_mode)) 376267537Smav warnx("warning, %s is not a character device", fname); 377229997Sken if (opt_ofs && opt_ofs != lseek(fd, opt_ofs, SEEK_SET)) 378229997Sken errx(1, "cannot seek to %jd", (intmax_t)opt_ofs); 379229997Sken memset(&bpb, 0, sizeof(bpb)); 380229997Sken if (opt_f) { 381229997Sken getstdfmt(opt_f, &bpb); 382275058Smav bpb.bsec = bpb.sec; 383275058Smav bpb.sec = 0; 384275058Smav bpb.bspf = bpb.spf; 385267537Smav bpb.spf = 0; 386267537Smav } 387267537Smav if (opt_h) 388267537Smav bpb.hds = opt_h; 389267537Smav if (opt_u) 390267537Smav bpb.spt = opt_u; 391267537Smav if (opt_S) 392267537Smav bpb.bps = opt_S; 393267537Smav if (opt_s) 394267537Smav bpb.bsec = opt_s; 395267537Smav if (oflag) 396267537Smav bpb.hid = opt_o; 397267537Smav if (!(opt_f || (opt_h && opt_u && opt_S && opt_s && oflag))) { 398267537Smav off_t delta; 399267537Smav getdiskinfo(fd, fname, dtype, oflag, &bpb); 400267537Smav bpb.bsec -= (opt_ofs / bpb.bps); 401267537Smav delta = bpb.bsec % bpb.spt; 402267537Smav if (delta != 0) { 403267537Smav warnx("trim %d sectors to adjust to a multiple of %d", 404267537Smav (int)delta, bpb.spt); 405267537Smav bpb.bsec -= delta; 406267537Smav } 407275058Smav if (bpb.spc == 0) { /* set defaults */ 408275058Smav if (bpb.bsec <= 6000) /* about 3MB -> 512 bytes */ 409275058Smav bpb.spc = 1; 410229997Sken else if (bpb.bsec <= (1<<17)) /* 64M -> 4k */ 411229997Sken bpb.spc = 8; 412229997Sken else if (bpb.bsec <= (1<<19)) /* 256M -> 8k */ 413229997Sken bpb.spc = 16; 414229997Sken else if (bpb.bsec <= (1<<21)) /* 1G -> 16k */ 415229997Sken bpb.spc = 32; 416229997Sken else 417229997Sken bpb.spc = 64; /* otherwise 32k */ 418229997Sken } 419229997Sken } 420229997Sken if (!powerof2(bpb.bps)) 421229997Sken errx(1, "bytes/sector (%u) is not a power of 2", bpb.bps); 422229997Sken if (bpb.bps < MINBPS) 423229997Sken errx(1, "bytes/sector (%u) is too small; minimum is %u", 424229997Sken bpb.bps, MINBPS); 425229997Sken if (!(fat = opt_F)) { 426229997Sken if (opt_f) 427229997Sken fat = 12; 428229997Sken else if (!opt_e && (opt_i || opt_k)) 429229997Sken fat = 32; 430229997Sken } 431229997Sken if ((fat == 32 && opt_e) || (fat != 32 && (opt_i || opt_k))) 432229997Sken errx(1, "-%c is not a legal FAT%s option", 433229997Sken fat == 32 ? 'e' : opt_i ? 'i' : 'k', 434229997Sken fat == 32 ? "32" : "12/16"); 435229997Sken if (opt_f && fat == 32) 436229997Sken bpb.rde = 0; 437229997Sken if (opt_b) { 438229997Sken if (!powerof2(opt_b)) 439229997Sken errx(1, "block size (%u) is not a power of 2", opt_b); 440229997Sken if (opt_b < bpb.bps) 441229997Sken errx(1, "block size (%u) is too small; minimum is %u", 442267877Smav opt_b, bpb.bps); 443229997Sken if (opt_b > bpb.bps * MAXSPC) 444229997Sken errx(1, "block size (%u) is too large; maximum is %u", 445229997Sken opt_b, bpb.bps * MAXSPC); 446229997Sken bpb.spc = opt_b / bpb.bps; 447229997Sken } 448229997Sken if (opt_c) { 449267877Smav if (!powerof2(opt_c)) 450229997Sken errx(1, "sectors/cluster (%u) is not a power of 2", opt_c); 451229997Sken bpb.spc = opt_c; 452229997Sken } 453229997Sken if (opt_r) 454229997Sken bpb.res = opt_r; 455229997Sken if (opt_n) { 456229997Sken if (opt_n > MAXNFT) 457229997Sken errx(1, "number of FATs (%u) is too large; maximum is %u", 458229997Sken opt_n, MAXNFT); 459229997Sken bpb.nft = opt_n; 460229997Sken } 461229997Sken if (opt_e) 462261538Smav bpb.rde = opt_e; 463229997Sken if (mflag) { 464229997Sken if (opt_m < 0xf0) 465229997Sken errx(1, "illegal media descriptor (%#x)", opt_m); 466229997Sken bpb.mid = opt_m; 467229997Sken } 468229997Sken if (opt_a) 469229997Sken bpb.bspf = opt_a; 470261538Smav if (opt_i) 471267877Smav bpb.infs = opt_i; 472261538Smav if (opt_k) 473229997Sken bpb.bkbs = opt_k; 474229997Sken bss = 1; 475229997Sken bname = NULL; 476229997Sken fd1 = -1; 477229997Sken if (opt_B) { 478229997Sken bname = opt_B; 479229997Sken if (!strchr(bname, '/')) { 480229997Sken snprintf(buf, sizeof(buf), "/boot/%s", bname); 481229997Sken if (!(bname = strdup(buf))) 482229997Sken err(1, NULL); 483229997Sken } 484229997Sken if ((fd1 = open(bname, O_RDONLY)) == -1 || fstat(fd1, &sb)) 485229997Sken err(1, "%s", bname); 486229997Sken if (!S_ISREG(sb.st_mode) || sb.st_size % bpb.bps || 487229997Sken sb.st_size < bpb.bps || sb.st_size > bpb.bps * MAXU16) 488229997Sken errx(1, "%s: inappropriate file type or format", bname); 489267877Smav bss = sb.st_size / bpb.bps; 490229997Sken } 491229997Sken if (!bpb.nft) 492229997Sken bpb.nft = 2; 493229997Sken if (!fat) { 494229997Sken if (bpb.bsec < (bpb.res ? bpb.res : bss) + 495229997Sken howmany((RESFTE + (bpb.spc ? MINCLS16 : MAXCLS12 + 1)) * 496229997Sken ((bpb.spc ? 16 : 12) / BPN), bpb.bps * NPB) * 497267877Smav bpb.nft + 498267877Smav howmany(bpb.rde ? bpb.rde : DEFRDE, 499267877Smav bpb.bps / sizeof(struct de)) + 500267877Smav (bpb.spc ? MINCLS16 : MAXCLS12 + 1) * 501229997Sken (bpb.spc ? bpb.spc : howmany(DEFBLK, bpb.bps))) 502229997Sken fat = 12; 503229997Sken else if (bpb.rde || bpb.bsec < 504229997Sken (bpb.res ? bpb.res : bss) + 505229997Sken howmany((RESFTE + MAXCLS16) * 2, bpb.bps) * bpb.nft + 506229997Sken howmany(DEFRDE, bpb.bps / sizeof(struct de)) + 507261538Smav (MAXCLS16 + 1) * 508261538Smav (bpb.spc ? bpb.spc : howmany(8192, bpb.bps))) 509282565Smav fat = 16; 510273809Smav else 511261538Smav fat = 32; 512229997Sken } 513229997Sken x = bss; 514229997Sken if (fat == 32) { 515229997Sken if (!bpb.infs) { 516229997Sken if (x == MAXU16 || x == bpb.bkbs) 517229997Sken errx(1, "no room for info sector"); 518229997Sken bpb.infs = x; 519229997Sken } 520229997Sken if (bpb.infs != MAXU16 && x <= bpb.infs) 521229997Sken x = bpb.infs + 1; 522229997Sken if (!bpb.bkbs) { 523267537Smav if (x == MAXU16) 524229997Sken errx(1, "no room for backup sector"); 525229997Sken bpb.bkbs = x; 526229997Sken } else if (bpb.bkbs != MAXU16 && bpb.bkbs == bpb.infs) 527264274Smav errx(1, "backup sector would overwrite info sector"); 528267537Smav if (bpb.bkbs != MAXU16 && x <= bpb.bkbs) 529267537Smav x = bpb.bkbs + 1; 530229997Sken } 531229997Sken if (!bpb.res) 532229997Sken bpb.res = fat == 32 ? MAX(x, MAX(16384 / bpb.bps, 4)) : x; 533275058Smav else if (bpb.res < x) 534275058Smav errx(1, "too few reserved sectors"); 535275058Smav if (fat != 32 && !bpb.rde) 536229997Sken bpb.rde = DEFRDE; 537229997Sken rds = howmany(bpb.rde, bpb.bps / sizeof(struct de)); 538229997Sken if (!bpb.spc) 539229997Sken for (bpb.spc = howmany(fat == 16 ? DEFBLK16 : DEFBLK, bpb.bps); 540229997Sken bpb.spc < MAXSPC && 541229997Sken bpb.res + 542229997Sken howmany((RESFTE + maxcls(fat)) * (fat / BPN), 543229997Sken bpb.bps * NPB) * bpb.nft + 544229997Sken rds + 545229997Sken (u_int64_t)(maxcls(fat) + 1) * bpb.spc <= bpb.bsec; 546229997Sken bpb.spc <<= 1); 547267877Smav if (fat != 32 && bpb.bspf > MAXU16) 548229997Sken errx(1, "too many sectors/FAT for FAT12/16"); 549241896Skib x1 = bpb.res + rds; 550229997Sken x = bpb.bspf ? bpb.bspf : 1; 551229997Sken if (x1 + (u_int64_t)x * bpb.nft > bpb.bsec) 552229997Sken errx(1, "meta data exceeds file system size"); 553267877Smav x1 += x * bpb.nft; 554267877Smav x = (u_int64_t)(bpb.bsec - x1) * bpb.bps * NPB / 555267877Smav (bpb.spc * bpb.bps * NPB + fat / BPN * bpb.nft); 556267877Smav x2 = howmany((RESFTE + MIN(x, maxcls(fat))) * (fat / BPN), 557229997Sken bpb.bps * NPB); 558267877Smav if (!bpb.bspf) { 559229997Sken bpb.bspf = x2; 560229997Sken x1 += (bpb.bspf - 1) * bpb.nft; 561229997Sken } 562229997Sken cls = (bpb.bsec - x1) / bpb.spc; 563229997Sken x = (u_int64_t)bpb.bspf * bpb.bps * NPB / (fat / BPN) - RESFTE; 564229997Sken if (cls > x) 565229997Sken cls = x; 566229997Sken if (bpb.bspf < x2) 567229997Sken warnx("warning: sectors/FAT limits file system to %u clusters", 568229997Sken cls); 569286353Smav if (cls < mincls(fat)) 570286353Smav errx(1, "%u clusters too few clusters for FAT%u, need %u", cls, fat, 571229997Sken mincls(fat)); 572229997Sken if (cls > maxcls(fat)) { 573229997Sken cls = maxcls(fat); 574229997Sken bpb.bsec = x1 + (cls + 1) * bpb.spc - 1; 575267877Smav warnx("warning: FAT type limits file system to %u sectors", 576267877Smav bpb.bsec); 577267877Smav } 578267877Smav printf("%s: %u sector%s in %u FAT%u cluster%s " 579267877Smav "(%u bytes/cluster)\n", fname, cls * bpb.spc, 580267877Smav cls * bpb.spc == 1 ? "" : "s", cls, fat, 581229997Sken cls == 1 ? "" : "s", bpb.bps * bpb.spc); 582229997Sken if (!bpb.mid) 583229997Sken bpb.mid = !bpb.hid ? 0xf0 : 0xf8; 584229997Sken if (fat == 32) 585229997Sken bpb.rdcl = RESFTE; 586229997Sken if (bpb.hid + bpb.bsec <= MAXU16) { 587229997Sken bpb.sec = bpb.bsec; 588229997Sken bpb.bsec = 0; 589229997Sken } 590229997Sken if (fat != 32) { 591229997Sken bpb.spf = bpb.bspf; 592229997Sken bpb.bspf = 0; 593258622Savg } 594258622Savg print_bpb(&bpb); 595258622Savg if (!opt_N) { 596258622Savg gettimeofday(&tv, NULL); 597229997Sken now = tv.tv_sec; 598229997Sken tm = localtime(&now); 599229997Sken if (!(img = malloc(bpb.bps))) 600229997Sken err(1, NULL); 601229997Sken dir = bpb.res + (bpb.spf ? bpb.spf : bpb.bspf) * bpb.nft; 602229997Sken for (lsn = 0; lsn < dir + (fat == 32 ? bpb.spc : rds); lsn++) { 603229997Sken x = lsn; 604229997Sken if (opt_B && 605229997Sken fat == 32 && bpb.bkbs != MAXU16 && 606241896Skib bss <= bpb.bkbs && x >= bpb.bkbs) { 607229997Sken x -= bpb.bkbs; 608229997Sken if (!x && lseek(fd1, opt_ofs, SEEK_SET)) 609229997Sken err(1, "%s", bname); 610229997Sken } 611229997Sken if (opt_B && x < bss) { 612229997Sken if ((n = read(fd1, img, bpb.bps)) == -1) 613271309Smav err(1, "%s", bname); 614271309Smav if ((unsigned)n != bpb.bps) 615271309Smav errx(1, "%s: can't read sector %u", bname, x); 616271309Smav } else 617271309Smav memset(img, 0, bpb.bps); 618229997Sken if (!lsn || 619267537Smav (fat == 32 && bpb.bkbs != MAXU16 && lsn == bpb.bkbs)) { 620229997Sken x1 = sizeof(struct bs); 621229997Sken bsbpb = (struct bsbpb *)(img + x1); 622267537Smav mk2(bsbpb->bps, bpb.bps); 623229997Sken mk1(bsbpb->spc, bpb.spc); 624229997Sken mk2(bsbpb->res, bpb.res); 625267537Smav mk1(bsbpb->nft, bpb.nft); 626229997Sken mk2(bsbpb->rde, bpb.rde); 627229997Sken mk2(bsbpb->sec, bpb.sec); 628229997Sken mk1(bsbpb->mid, bpb.mid); 629229997Sken mk2(bsbpb->spf, bpb.spf); 630229997Sken mk2(bsbpb->spt, bpb.spt); 631229997Sken mk2(bsbpb->hds, bpb.hds); 632229997Sken mk4(bsbpb->hid, bpb.hid); 633229997Sken mk4(bsbpb->bsec, bpb.bsec); 634229997Sken x1 += sizeof(struct bsbpb); 635229997Sken if (fat == 32) { 636229997Sken bsxbpb = (struct bsxbpb *)(img + x1); 637229997Sken mk4(bsxbpb->bspf, bpb.bspf); 638229997Sken mk2(bsxbpb->xflg, 0); 639267877Smav mk2(bsxbpb->vers, 0); 640267877Smav mk4(bsxbpb->rdcl, bpb.rdcl); 641267877Smav mk2(bsxbpb->infs, bpb.infs); 642267877Smav mk2(bsxbpb->bkbs, bpb.bkbs); 643267877Smav x1 += sizeof(struct bsxbpb); 644229997Sken } 645229997Sken bsx = (struct bsx *)(img + x1); 646229997Sken mk1(bsx->sig, 0x29); 647229997Sken if (Iflag) 648229997Sken x = opt_I; 649229997Sken else 650229997Sken x = (((u_int)(1 + tm->tm_mon) << 8 | 651229997Sken (u_int)tm->tm_mday) + 652229997Sken ((u_int)tm->tm_sec << 8 | 653229997Sken (u_int)(tv.tv_usec / 10))) << 16 | 654229997Sken ((u_int)(1900 + tm->tm_year) + 655229997Sken ((u_int)tm->tm_hour << 8 | 656229997Sken (u_int)tm->tm_min)); 657229997Sken mk4(bsx->volid, x); 658229997Sken mklabel(bsx->label, opt_L ? opt_L : "NO NAME"); 659229997Sken sprintf(buf, "FAT%u", fat); 660229997Sken setstr(bsx->type, buf, sizeof(bsx->type)); 661229997Sken if (!opt_B) { 662229997Sken x1 += sizeof(struct bsx); 663229997Sken bs = (struct bs *)img; 664271309Smav mk1(bs->jmp[0], 0xeb); 665229997Sken mk1(bs->jmp[1], x1 - 2); 666229997Sken mk1(bs->jmp[2], 0x90); 667267537Smav setstr(bs->oem, opt_O ? opt_O : "BSD 4.4", 668229997Sken sizeof(bs->oem)); 669229997Sken memcpy(img + x1, bootcode, sizeof(bootcode)); 670229997Sken mk2(img + MINBPS - 2, DOSMAGIC); 671229997Sken } 672229997Sken } else if (fat == 32 && bpb.infs != MAXU16 && 673229997Sken (lsn == bpb.infs || 674229997Sken (bpb.bkbs != MAXU16 && 675229997Sken lsn == bpb.bkbs + bpb.infs))) { 676229997Sken mk4(img, 0x41615252); 677229997Sken mk4(img + MINBPS - 28, 0x61417272); 678229997Sken mk4(img + MINBPS - 24, 0xffffffff); 679229997Sken mk4(img + MINBPS - 20, bpb.rdcl); 680229997Sken mk2(img + MINBPS - 2, DOSMAGIC); 681229997Sken } else if (lsn >= bpb.res && lsn < dir && 682229997Sken !((lsn - bpb.res) % 683229997Sken (bpb.spf ? bpb.spf : bpb.bspf))) { 684229997Sken mk1(img[0], bpb.mid); 685229997Sken for (x = 1; x < fat * (fat == 32 ? 3 : 2) / 8; x++) 686229997Sken mk1(img[x], fat == 32 && x % 4 == 3 ? 0x0f : 0xff); 687229997Sken } else if (lsn == dir && opt_L) { 688229997Sken de = (struct de *)img; 689229997Sken mklabel(de->namext, opt_L); 690229997Sken mk1(de->attr, 050); 691229997Sken x = (u_int)tm->tm_hour << 11 | 692229997Sken (u_int)tm->tm_min << 5 | 693229997Sken (u_int)tm->tm_sec >> 1; 694229997Sken mk2(de->time, x); 695229997Sken x = (u_int)(tm->tm_year - 80) << 9 | 696229997Sken (u_int)(tm->tm_mon + 1) << 5 | 697229997Sken (u_int)tm->tm_mday; 698271309Smav mk2(de->date, x); 699229997Sken } 700229997Sken if ((n = write(fd, img, bpb.bps)) == -1) 701229997Sken err(1, "%s", fname); 702267537Smav if ((unsigned)n != bpb.bps) 703229997Sken errx(1, "%s: can't write sector %u", fname, lsn); 704229997Sken } 705267877Smav } 706267877Smav return 0; 707267877Smav} 708267877Smav 709267877Smav/* 710267877Smav * Exit with error if file system is mounted. 711229997Sken */ 712229997Skenstatic void 713229997Skencheck_mounted(const char *fname, mode_t mode) 714229997Sken{ 715229997Sken struct statfs *mp; 716229997Sken const char *s1, *s2; 717229997Sken size_t len; 718229997Sken int n, r; 719229997Sken 720229997Sken if (!(n = getmntinfo(&mp, MNT_NOWAIT))) 721282565Smav err(1, "getmntinfo"); 722273809Smav len = strlen(_PATH_DEV); 723273809Smav s1 = fname; 724273809Smav if (!strncmp(s1, _PATH_DEV, len)) 725229997Sken s1 += len; 726229997Sken r = S_ISCHR(mode) && s1 != fname && *s1 == 'r'; 727229997Sken for (; n--; mp++) { 728229997Sken s2 = mp->f_mntfromname; 729229997Sken if (!strncmp(s2, _PATH_DEV, len)) 730269122Smav s2 += len; 731229997Sken if ((r && s2 != mp->f_mntfromname && !strcmp(s1 + 1, s2)) || 732229997Sken !strcmp(s1, s2)) 733269122Smav errx(1, "%s is mounted on %s", fname, mp->f_mntonname); 734269122Smav } 735229997Sken} 736229997Sken 737229997Sken/* 738275058Smav * Get a standard format. 739275058Smav */ 740275058Smavstatic void 741229997Skengetstdfmt(const char *fmt, struct bpb *bpb) 742229997Sken{ 743229997Sken u_int x, i; 744229997Sken 745229997Sken x = sizeof(stdfmt) / sizeof(stdfmt[0]); 746229997Sken for (i = 0; i < x && strcmp(fmt, stdfmt[i].name); i++); 747229997Sken if (i == x) 748229997Sken errx(1, "%s: unknown standard format", fmt); 749275474Smav *bpb = stdfmt[i].bpb; 750275474Smav} 751275474Smav 752275474Smav/* 753275474Smav * Get disk slice, partition, and geometry information. 754275474Smav */ 755275474Smavstatic void 756275474Smavgetdiskinfo(int fd, const char *fname, const char *dtype, __unused int oflag, 757275474Smav struct bpb *bpb) 758275474Smav{ 759275474Smav struct disklabel *lp, dlp; 760287499Smav struct fd_type type; 761275474Smav off_t ms, hs = 0; 762275474Smav 763275474Smav lp = NULL; 764275474Smav 765275474Smav /* If the user specified a disk type, try to use that */ 766275474Smav if (dtype != NULL) { 767275474Smav lp = getdiskbyname(dtype); 768275474Smav } 769275474Smav 770275474Smav /* Maybe it's a floppy drive */ 771275474Smav if (lp == NULL) { 772275474Smav if (ioctl(fd, DIOCGMEDIASIZE, &ms) == -1) { 773275474Smav struct stat st; 774275474Smav 775275474Smav if (fstat(fd, &st)) 776275474Smav err(1, "Cannot get disk size"); 777275474Smav /* create a fake geometry for a file image */ 778275474Smav ms = st.st_size; 779275474Smav dlp.d_secsize = 512; 780287499Smav dlp.d_nsectors = 63; 781287499Smav dlp.d_ntracks = 255; 782275474Smav dlp.d_secperunit = ms / dlp.d_secsize; 783275474Smav lp = &dlp; 784275474Smav } else if (ioctl(fd, FD_GTYPE, &type) != -1) { 785275474Smav dlp.d_secsize = 128 << type.secsize; 786275474Smav dlp.d_nsectors = type.sectrac; 787275481Smav dlp.d_ntracks = type.heads; 788275481Smav dlp.d_secperunit = ms / dlp.d_secsize; 789275481Smav lp = &dlp; 790275481Smav } 791275481Smav } 792285030Smav 793275481Smav /* Maybe it's a fixed drive */ 794275481Smav if (lp == NULL) { 795285030Smav if (ioctl(fd, DIOCGDINFO, &dlp) == -1) { 796275481Smav if (bpb->bps == 0 && ioctl(fd, DIOCGSECTORSIZE, &dlp.d_secsize) == -1) 797285030Smav errx(1, "Cannot get sector size, %s", strerror(errno)); 798285030Smav 799275481Smav /* XXX Should we use bpb->bps if it's set? */ 800275481Smav dlp.d_secperunit = ms / dlp.d_secsize; 801285030Smav 802287499Smav if (bpb->spt == 0 && ioctl(fd, DIOCGFWSECTORS, &dlp.d_nsectors) == -1) { 803275481Smav warnx("Cannot get number of sectors per track, %s", strerror(errno)); 804285030Smav dlp.d_nsectors = 63; 805285030Smav } 806275481Smav if (bpb->hds == 0 && ioctl(fd, DIOCGFWHEADS, &dlp.d_ntracks) == -1) { 807285030Smav warnx("Cannot get number of heads, %s", strerror(errno)); 808286811Smav if (dlp.d_secperunit <= 63*1*1024) 809287499Smav dlp.d_ntracks = 1; 810275481Smav else if (dlp.d_secperunit <= 63*16*1024) 811285030Smav dlp.d_ntracks = 16; 812285030Smav else 813275481Smav dlp.d_ntracks = 255; 814275481Smav } 815275474Smav } 816269123Smav 817269123Smav hs = (ms / dlp.d_secsize) - dlp.d_secperunit; 818269123Smav lp = &dlp; 819269123Smav } 820287664Smav 821287664Smav if (bpb->bps == 0) 822269123Smav bpb->bps = ckgeom(fname, lp->d_secsize, "bytes/sector"); 823269123Smav if (bpb->spt == 0) 824287664Smav bpb->spt = ckgeom(fname, lp->d_nsectors, "sectors/track"); 825269123Smav if (bpb->hds == 0) 826269123Smav bpb->hds = ckgeom(fname, lp->d_ntracks, "drive heads"); 827269123Smav if (bpb->bsec == 0) 828269123Smav bpb->bsec = lp->d_secperunit; 829271309Smav if (bpb->hid == 0) 830271309Smav bpb->hid = hs; 831271309Smav} 832271309Smav 833271309Smav/* 834269123Smav * Print out BPB values. 835269123Smav */ 836269123Smavstatic void 837269123Smavprint_bpb(struct bpb *bpb) 838269123Smav{ 839269123Smav printf("bps=%u spc=%u res=%u nft=%u", bpb->bps, bpb->spc, bpb->res, 840269123Smav bpb->nft); 841269123Smav if (bpb->rde) 842269123Smav printf(" rde=%u", bpb->rde); 843269123Smav if (bpb->sec) 844269123Smav printf(" sec=%u", bpb->sec); 845269123Smav printf(" mid=%#x", bpb->mid); 846269123Smav if (bpb->spf) 847269123Smav printf(" spf=%u", bpb->spf); 848269123Smav printf(" spt=%u hds=%u hid=%u", bpb->spt, bpb->hds, bpb->hid); 849269123Smav if (bpb->bsec) 850269123Smav printf(" bsec=%u", bpb->bsec); 851269123Smav if (!bpb->spf) { 852269123Smav printf(" bspf=%u rdcl=%u", bpb->bspf, bpb->rdcl); 853269123Smav printf(" infs="); 854269123Smav printf(bpb->infs == MAXU16 ? "%#x" : "%u", bpb->infs); 855269123Smav printf(" bkbs="); 856269123Smav printf(bpb->bkbs == MAXU16 ? "%#x" : "%u", bpb->bkbs); 857269123Smav } 858269123Smav printf("\n"); 859269123Smav} 860287664Smav 861287664Smav/* 862287664Smav * Check a disk geometry value. 863287664Smav */ 864287664Smavstatic u_int 865287664Smavckgeom(const char *fname, u_int val, const char *msg) 866287664Smav{ 867287664Smav if (!val) 868287664Smav errx(1, "%s: no default %s", fname, msg); 869287664Smav if (val > MAXU16) 870287664Smav errx(1, "%s: illegal %s %d", fname, msg, val); 871269123Smav return val; 872287664Smav} 873269123Smav 874269123Smav/* 875269123Smav * Convert and check a numeric option argument. 876269123Smav */ 877269123Smavstatic u_int 878269123Smavargtou(const char *arg, u_int lo, u_int hi, const char *msg) 879269123Smav{ 880269123Smav char *s; 881269123Smav u_long x; 882269123Smav 883269123Smav errno = 0; 884269123Smav x = strtoul(arg, &s, 0); 885269123Smav if (errno || !*arg || *s || x < lo || x > hi) 886282565Smav errx(1, "%s: bad %s", arg, msg); 887273809Smav return x; 888273809Smav} 889273809Smav 890269123Smav/* 891269123Smav * Same for off_t, with optional skmgpP suffix 892269123Smav */ 893269123Smavstatic off_t 894269123Smavargtooff(const char *arg, const char *msg) 895269123Smav{ 896269123Smav char *s; 897269123Smav off_t x; 898269123Smav 899269123Smav x = strtoll(arg, &s, 0); 900269123Smav /* allow at most one extra char */ 901269123Smav if (errno || x < 0 || (s[0] && s[1]) ) 902269123Smav errx(1, "%s: bad %s", arg, msg); 903275058Smav if (*s) { /* the extra char is the multiplier */ 904275058Smav switch (*s) { 905275058Smav default: 906269123Smav errx(1, "%s: bad %s", arg, msg); 907269123Smav /* notreached */ 908269123Smav 909269123Smav case 's': /* sector */ 910269123Smav case 'S': 911269123Smav x <<= 9; /* times 512 */ 912269123Smav break; 913269123Smav 914275474Smav case 'k': /* kilobyte */ 915275474Smav case 'K': 916275474Smav x <<= 10; /* times 1024 */ 917275474Smav break; 918287664Smav 919287664Smav case 'm': /* megabyte */ 920275474Smav case 'M': 921275474Smav x <<= 20; /* times 1024*1024 */ 922275474Smav break; 923287664Smav 924275474Smav case 'g': /* gigabyte */ 925275474Smav case 'G': 926275474Smav x <<= 30; /* times 1024*1024*1024 */ 927287664Smav break; 928287664Smav 929287664Smav case 'p': /* partition start */ 930287664Smav case 'P': /* partition start */ 931287664Smav case 'l': /* partition length */ 932287664Smav case 'L': /* partition length */ 933287499Smav errx(1, "%s: not supported yet %s", arg, msg); 934287664Smav /* notreached */ 935287664Smav } 936275474Smav } 937275474Smav return x; 938275474Smav} 939287664Smav 940287664Smav/* 941275474Smav * Check a volume label. 942275474Smav */ 943275474Smavstatic int 944275474Smavoklabel(const char *src) 945275474Smav{ 946275474Smav int c, i; 947275474Smav 948287664Smav for (i = 0; i <= 11; i++) { 949275474Smav c = (u_char)*src++; 950287664Smav if (c < ' ' + !i || strchr("\"*+,./:;<=>?[\\]|", c)) 951275474Smav break; 952275474Smav } 953287499Smav return i && !c; 954287499Smav} 955275474Smav 956275474Smav/* 957275474Smav * Make a volume label. 958275474Smav */ 959275474Smavstatic void 960275474Smavmklabel(u_int8_t *dest, const char *src) 961229997Sken{ 962229997Sken int c, i; 963229997Sken 964229997Sken for (i = 0; i < 11; i++) { 965229997Sken c = *src ? toupper(*src++) : ' '; 966287664Smav *dest++ = !i && c == '\xe5' ? 5 : c; 967287664Smav } 968287664Smav} 969229997Sken 970229997Sken/* 971229997Sken * Copy string, padding with spaces. 972229997Sken */ 973229997Skenstatic void 974229997Skensetstr(u_int8_t *dest, const char *src, size_t len) 975229997Sken{ 976229997Sken while (len--) 977229997Sken *dest++ = *src ? *src++ : ' '; 978229997Sken} 979229997Sken 980229997Sken/* 981229997Sken * Print usage message. 982229997Sken */ 983229997Skenstatic void 984229997Skenusage(void) 985229997Sken{ 986229997Sken fprintf(stderr, 987229997Sken "usage: newfs_msdos [ -options ] special [disktype]\n"); 988229997Sken fprintf(stderr, "where the options are:\n"); 989229997Sken fprintf(stderr, "\t-N don't create file system: " 990229997Sken "just print out parameters\n"); 991229997Sken fprintf(stderr, "\t-B get bootstrap from file\n"); 992229997Sken fprintf(stderr, "\t-F FAT type (12, 16, or 32)\n"); 993267877Smav fprintf(stderr, "\t-I volume ID\n"); 994229997Sken fprintf(stderr, "\t-L volume label\n"); 995267877Smav fprintf(stderr, "\t-O OEM string\n"); 996229997Sken fprintf(stderr, "\t-S bytes/sector\n"); 997287664Smav fprintf(stderr, "\t-a sectors/FAT\n"); 998287664Smav fprintf(stderr, "\t-b block size\n"); 999287664Smav fprintf(stderr, "\t-c sectors/cluster\n"); 1000287664Smav fprintf(stderr, "\t-e root directory entries\n"); 1001287664Smav fprintf(stderr, "\t-f standard format\n"); 1002287664Smav fprintf(stderr, "\t-h drive heads\n"); 1003287664Smav fprintf(stderr, "\t-i file system info sector\n"); 1004287664Smav fprintf(stderr, "\t-k backup boot sector\n"); 1005287664Smav fprintf(stderr, "\t-m media descriptor\n"); 1006229997Sken fprintf(stderr, "\t-n number of FATs\n"); 1007229997Sken fprintf(stderr, "\t-o hidden sectors\n"); 1008229997Sken fprintf(stderr, "\t-r reserved sectors\n"); 1009264274Smav fprintf(stderr, "\t-s file system size (sectors)\n"); 1010264274Smav fprintf(stderr, "\t-u sectors/track\n"); 1011264274Smav exit(1); 1012264274Smav} 1013264274Smav