1f252c9b0SSascha Wildner /*
2f252c9b0SSascha Wildner * Copyright (c) 1998 Robert Nordier
3f252c9b0SSascha Wildner * All rights reserved.
4f252c9b0SSascha Wildner *
5f252c9b0SSascha Wildner * Redistribution and use in source and binary forms, with or without
6f252c9b0SSascha Wildner * modification, are permitted provided that the following conditions
7f252c9b0SSascha Wildner * are met:
8f252c9b0SSascha Wildner * 1. Redistributions of source code must retain the above copyright
9f252c9b0SSascha Wildner * notice, this list of conditions and the following disclaimer.
10f252c9b0SSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright
11f252c9b0SSascha Wildner * notice, this list of conditions and the following disclaimer in
12f252c9b0SSascha Wildner * the documentation and/or other materials provided with the
13f252c9b0SSascha Wildner * distribution.
14f252c9b0SSascha Wildner *
15f252c9b0SSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
16f252c9b0SSascha Wildner * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17f252c9b0SSascha Wildner * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18f252c9b0SSascha Wildner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY
19f252c9b0SSascha Wildner * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20f252c9b0SSascha Wildner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21f252c9b0SSascha Wildner * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22f252c9b0SSascha Wildner * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23f252c9b0SSascha Wildner * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24f252c9b0SSascha Wildner * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25f252c9b0SSascha Wildner * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26f252c9b0SSascha Wildner */
27f252c9b0SSascha Wildner
28f252c9b0SSascha Wildner #include <sys/param.h>
29f252c9b0SSascha Wildner #include <sys/disklabel32.h>
30f252c9b0SSascha Wildner #include <sys/diskmbr.h>
31f252c9b0SSascha Wildner #include <sys/diskslice.h>
32f252c9b0SSascha Wildner #include <sys/mount.h>
33f252c9b0SSascha Wildner #include <sys/stat.h>
34d14d5141STomohiro Kusumi //#include <sys/sysctl.h>
35f252c9b0SSascha Wildner #include <sys/time.h>
36f252c9b0SSascha Wildner
37f252c9b0SSascha Wildner #include <machine/ioctl_fd.h>
38f252c9b0SSascha Wildner
39d14d5141STomohiro Kusumi #include <assert.h>
40f252c9b0SSascha Wildner #include <ctype.h>
41f252c9b0SSascha Wildner #include <disktab.h>
42f252c9b0SSascha Wildner #include <err.h>
43f252c9b0SSascha Wildner #include <errno.h>
44f252c9b0SSascha Wildner #include <fcntl.h>
45f252c9b0SSascha Wildner #include <inttypes.h>
46f252c9b0SSascha Wildner #include <paths.h>
47f252c9b0SSascha Wildner #include <signal.h>
48f252c9b0SSascha Wildner #include <stdio.h>
49f252c9b0SSascha Wildner #include <stdlib.h>
50f252c9b0SSascha Wildner #include <string.h>
51f252c9b0SSascha Wildner #include <time.h>
52f252c9b0SSascha Wildner #include <unistd.h>
53f252c9b0SSascha Wildner
54f252c9b0SSascha Wildner #include "mkfs_msdos.h"
55f252c9b0SSascha Wildner
56f252c9b0SSascha Wildner #define MAXU16 0xffff /* maximum unsigned 16-bit quantity */
57f252c9b0SSascha Wildner #define BPN 4 /* bits per nibble */
58f252c9b0SSascha Wildner #define NPB 2 /* nibbles per byte */
59f252c9b0SSascha Wildner
60f252c9b0SSascha Wildner #define MINBPS 512 /* minimum bytes per sector */
61db72ecfeSTomohiro Kusumi #define MAXBPS 4096 /* maximum bytes per sector */
62f252c9b0SSascha Wildner #define MAXSPC 128 /* maximum sectors per cluster */
63f252c9b0SSascha Wildner #define MAXNFT 16 /* maximum number of FATs */
64f252c9b0SSascha Wildner #define DEFBLK 4096 /* default block size */
65f252c9b0SSascha Wildner #define DEFBLK16 2048 /* default block size FAT16 */
66f252c9b0SSascha Wildner #define DEFRDE 512 /* default root directory entries */
67f252c9b0SSascha Wildner #define RESFTE 2 /* reserved FAT entries */
68f252c9b0SSascha Wildner #define MINCLS12 1U /* minimum FAT12 clusters */
69f252c9b0SSascha Wildner #define MINCLS16 0xff5U /* minimum FAT16 clusters */
70f252c9b0SSascha Wildner #define MINCLS32 0xfff5U /* minimum FAT32 clusters */
71f252c9b0SSascha Wildner #define MAXCLS12 0xff4U /* maximum FAT12 clusters */
72f252c9b0SSascha Wildner #define MAXCLS16 0xfff4U /* maximum FAT16 clusters */
73f252c9b0SSascha Wildner #define MAXCLS32 0xffffff4U /* maximum FAT32 clusters */
74f252c9b0SSascha Wildner
75f252c9b0SSascha Wildner #define mincls(fat) ((fat) == 12 ? MINCLS12 : \
76f252c9b0SSascha Wildner (fat) == 16 ? MINCLS16 : \
77f252c9b0SSascha Wildner MINCLS32)
78f252c9b0SSascha Wildner
79f252c9b0SSascha Wildner #define maxcls(fat) ((fat) == 12 ? MAXCLS12 : \
80f252c9b0SSascha Wildner (fat) == 16 ? MAXCLS16 : \
81f252c9b0SSascha Wildner MAXCLS32)
82f252c9b0SSascha Wildner
83f252c9b0SSascha Wildner #define mk1(p, x) \
84149331c9STomohiro Kusumi (p) = (uint8_t)(x)
85f252c9b0SSascha Wildner
86f252c9b0SSascha Wildner #define mk2(p, x) \
87149331c9STomohiro Kusumi (p)[0] = (uint8_t)(x), \
88149331c9STomohiro Kusumi (p)[1] = (uint8_t)((x) >> 010)
89f252c9b0SSascha Wildner
90f252c9b0SSascha Wildner #define mk4(p, x) \
91149331c9STomohiro Kusumi (p)[0] = (uint8_t)(x), \
92149331c9STomohiro Kusumi (p)[1] = (uint8_t)((x) >> 010), \
93149331c9STomohiro Kusumi (p)[2] = (uint8_t)((x) >> 020), \
94149331c9STomohiro Kusumi (p)[3] = (uint8_t)((x) >> 030)
95f252c9b0SSascha Wildner
96f252c9b0SSascha Wildner struct bs {
97149331c9STomohiro Kusumi uint8_t bsJump[3]; /* bootstrap entry point */
98149331c9STomohiro Kusumi uint8_t bsOemName[8]; /* OEM name and version */
99f252c9b0SSascha Wildner } __packed;
100f252c9b0SSascha Wildner
101f252c9b0SSascha Wildner struct bsbpb {
102149331c9STomohiro Kusumi uint8_t bpbBytesPerSec[2]; /* bytes per sector */
103149331c9STomohiro Kusumi uint8_t bpbSecPerClust; /* sectors per cluster */
104149331c9STomohiro Kusumi uint8_t bpbResSectors[2]; /* reserved sectors */
105149331c9STomohiro Kusumi uint8_t bpbFATs; /* number of FATs */
106149331c9STomohiro Kusumi uint8_t bpbRootDirEnts[2]; /* root directory entries */
107149331c9STomohiro Kusumi uint8_t bpbSectors[2]; /* total sectors */
108149331c9STomohiro Kusumi uint8_t bpbMedia; /* media descriptor */
109149331c9STomohiro Kusumi uint8_t bpbFATsecs[2]; /* sectors per FAT */
110149331c9STomohiro Kusumi uint8_t bpbSecPerTrack[2]; /* sectors per track */
111149331c9STomohiro Kusumi uint8_t bpbHeads[2]; /* drive heads */
112149331c9STomohiro Kusumi uint8_t bpbHiddenSecs[4]; /* hidden sectors */
113149331c9STomohiro Kusumi uint8_t bpbHugeSectors[4]; /* big total sectors */
114f252c9b0SSascha Wildner } __packed;
115f252c9b0SSascha Wildner
116f252c9b0SSascha Wildner struct bsxbpb {
117149331c9STomohiro Kusumi uint8_t bpbBigFATsecs[4]; /* big sectors per FAT */
118149331c9STomohiro Kusumi uint8_t bpbExtFlags[2]; /* FAT control flags */
119149331c9STomohiro Kusumi uint8_t bpbFSVers[2]; /* file system version */
120149331c9STomohiro Kusumi uint8_t bpbRootClust[4]; /* root directory start cluster */
121149331c9STomohiro Kusumi uint8_t bpbFSInfo[2]; /* file system info sector */
122149331c9STomohiro Kusumi uint8_t bpbBackup[2]; /* backup boot sector */
123149331c9STomohiro Kusumi uint8_t bpbReserved[12]; /* reserved */
124f252c9b0SSascha Wildner } __packed;
125f252c9b0SSascha Wildner
126f252c9b0SSascha Wildner struct bsx {
127149331c9STomohiro Kusumi uint8_t exDriveNumber; /* drive number */
128149331c9STomohiro Kusumi uint8_t exReserved1; /* reserved */
129149331c9STomohiro Kusumi uint8_t exBootSignature; /* extended boot signature */
130149331c9STomohiro Kusumi uint8_t exVolumeID[4]; /* volume ID number */
131149331c9STomohiro Kusumi uint8_t exVolumeLabel[11]; /* volume label */
132149331c9STomohiro Kusumi uint8_t exFileSysType[8]; /* file system type */
133f252c9b0SSascha Wildner } __packed;
134f252c9b0SSascha Wildner
135f252c9b0SSascha Wildner struct de {
136149331c9STomohiro Kusumi uint8_t deName[11]; /* name and extension */
137149331c9STomohiro Kusumi uint8_t deAttributes; /* attributes */
138149331c9STomohiro Kusumi uint8_t rsvd[10]; /* reserved */
139149331c9STomohiro Kusumi uint8_t deMTime[2]; /* last-modified time */
140149331c9STomohiro Kusumi uint8_t deMDate[2]; /* last-modified date */
141149331c9STomohiro Kusumi uint8_t deStartCluster[2]; /* starting cluster */
142149331c9STomohiro Kusumi uint8_t deFileSize[4]; /* size */
143f252c9b0SSascha Wildner } __packed;
144f252c9b0SSascha Wildner
145f252c9b0SSascha Wildner struct bpb {
146f252c9b0SSascha Wildner u_int bpbBytesPerSec; /* bytes per sector */
147f252c9b0SSascha Wildner u_int bpbSecPerClust; /* sectors per cluster */
148f252c9b0SSascha Wildner u_int bpbResSectors; /* reserved sectors */
149f252c9b0SSascha Wildner u_int bpbFATs; /* number of FATs */
150f252c9b0SSascha Wildner u_int bpbRootDirEnts; /* root directory entries */
151f252c9b0SSascha Wildner u_int bpbSectors; /* total sectors */
152f252c9b0SSascha Wildner u_int bpbMedia; /* media descriptor */
153f252c9b0SSascha Wildner u_int bpbFATsecs; /* sectors per FAT */
154f252c9b0SSascha Wildner u_int bpbSecPerTrack; /* sectors per track */
155f252c9b0SSascha Wildner u_int bpbHeads; /* drive heads */
156f252c9b0SSascha Wildner u_int bpbHiddenSecs; /* hidden sectors */
157f252c9b0SSascha Wildner u_int bpbHugeSectors; /* big total sectors */
158f252c9b0SSascha Wildner u_int bpbBigFATsecs; /* big sectors per FAT */
159f252c9b0SSascha Wildner u_int bpbRootClust; /* root directory start cluster */
160f252c9b0SSascha Wildner u_int bpbFSInfo; /* file system info sector */
161f252c9b0SSascha Wildner u_int bpbBackup; /* backup boot sector */
162f252c9b0SSascha Wildner };
163f252c9b0SSascha Wildner
164f252c9b0SSascha Wildner #define BPBGAP 0, 0, 0, 0, 0, 0
165f252c9b0SSascha Wildner
166f252c9b0SSascha Wildner static struct {
167f252c9b0SSascha Wildner const char *name;
168f252c9b0SSascha Wildner struct bpb bpb;
169f252c9b0SSascha Wildner } const stdfmt[] = {
170f252c9b0SSascha Wildner {"160", {512, 1, 1, 2, 64, 320, 0xfe, 1, 8, 1, BPBGAP}},
171f252c9b0SSascha Wildner {"180", {512, 1, 1, 2, 64, 360, 0xfc, 2, 9, 1, BPBGAP}},
172f252c9b0SSascha Wildner {"320", {512, 2, 1, 2, 112, 640, 0xff, 1, 8, 2, BPBGAP}},
173f252c9b0SSascha Wildner {"360", {512, 2, 1, 2, 112, 720, 0xfd, 2, 9, 2, BPBGAP}},
174f252c9b0SSascha Wildner {"640", {512, 2, 1, 2, 112, 1280, 0xfb, 2, 8, 2, BPBGAP}},
175f252c9b0SSascha Wildner {"720", {512, 2, 1, 2, 112, 1440, 0xf9, 3, 9, 2, BPBGAP}},
176f252c9b0SSascha Wildner {"1200", {512, 1, 1, 2, 224, 2400, 0xf9, 7, 15, 2, BPBGAP}},
177f252c9b0SSascha Wildner {"1232", {1024,1, 1, 2, 192, 1232, 0xfe, 2, 8, 2, BPBGAP}},
178f252c9b0SSascha Wildner {"1440", {512, 1, 1, 2, 224, 2880, 0xf0, 9, 18, 2, BPBGAP}},
179f252c9b0SSascha Wildner {"2880", {512, 2, 1, 2, 240, 5760, 0xf0, 9, 36, 2, BPBGAP}}
180f252c9b0SSascha Wildner };
181f252c9b0SSascha Wildner
182149331c9STomohiro Kusumi static const uint8_t bootcode[] = {
183f252c9b0SSascha Wildner 0xfa, /* cli */
184f252c9b0SSascha Wildner 0x31, 0xc0, /* xor ax,ax */
185f252c9b0SSascha Wildner 0x8e, 0xd0, /* mov ss,ax */
186f252c9b0SSascha Wildner 0xbc, 0x00, 0x7c, /* mov sp,7c00h */
187f252c9b0SSascha Wildner 0xfb, /* sti */
188f252c9b0SSascha Wildner 0x8e, 0xd8, /* mov ds,ax */
189f252c9b0SSascha Wildner 0xe8, 0x00, 0x00, /* call $ + 3 */
190f252c9b0SSascha Wildner 0x5e, /* pop si */
191f252c9b0SSascha Wildner 0x83, 0xc6, 0x19, /* add si,+19h */
192f252c9b0SSascha Wildner 0xbb, 0x07, 0x00, /* mov bx,0007h */
193f252c9b0SSascha Wildner 0xfc, /* cld */
194f252c9b0SSascha Wildner 0xac, /* lodsb */
195f252c9b0SSascha Wildner 0x84, 0xc0, /* test al,al */
196f252c9b0SSascha Wildner 0x74, 0x06, /* jz $ + 8 */
197f252c9b0SSascha Wildner 0xb4, 0x0e, /* mov ah,0eh */
198f252c9b0SSascha Wildner 0xcd, 0x10, /* int 10h */
199f252c9b0SSascha Wildner 0xeb, 0xf5, /* jmp $ - 9 */
200f252c9b0SSascha Wildner 0x30, 0xe4, /* xor ah,ah */
201f252c9b0SSascha Wildner 0xcd, 0x16, /* int 16h */
202f252c9b0SSascha Wildner 0xcd, 0x19, /* int 19h */
203f252c9b0SSascha Wildner 0x0d, 0x0a,
204f252c9b0SSascha Wildner 'N', 'o', 'n', '-', 's', 'y', 's', 't',
205f252c9b0SSascha Wildner 'e', 'm', ' ', 'd', 'i', 's', 'k',
206f252c9b0SSascha Wildner 0x0d, 0x0a,
207f252c9b0SSascha Wildner 'P', 'r', 'e', 's', 's', ' ', 'a', 'n',
208f252c9b0SSascha Wildner 'y', ' ', 'k', 'e', 'y', ' ', 't', 'o',
209f252c9b0SSascha Wildner ' ', 'r', 'e', 'b', 'o', 'o', 't',
210f252c9b0SSascha Wildner 0x0d, 0x0a,
211f252c9b0SSascha Wildner 0
212f252c9b0SSascha Wildner };
213f252c9b0SSascha Wildner
214f252c9b0SSascha Wildner static volatile sig_atomic_t got_siginfo;
215f252c9b0SSascha Wildner static void infohandler(int);
216f252c9b0SSascha Wildner
217*c589a8b8STomohiro Kusumi #ifndef MAKEFS
218f252c9b0SSascha Wildner static int check_mounted(const char *, mode_t);
219*c589a8b8STomohiro Kusumi #endif
220d14d5141STomohiro Kusumi static ssize_t getchunksize(void);
221f252c9b0SSascha Wildner static int getstdfmt(const char *, struct bpb *);
222f252c9b0SSascha Wildner static int getdiskinfo(int, const char *, const char *, int, struct bpb *);
223f252c9b0SSascha Wildner static void print_bpb(struct bpb *);
224f252c9b0SSascha Wildner static int ckgeom(const char *, u_int, const char *);
225149331c9STomohiro Kusumi static void mklabel(uint8_t *, const char *);
226f252c9b0SSascha Wildner static int oklabel(const char *);
227149331c9STomohiro Kusumi static void setstr(uint8_t *, const char *, size_t);
228f252c9b0SSascha Wildner
229f252c9b0SSascha Wildner int
mkfs_msdos(const char * fname,const char * dtype,const struct msdos_options * op)230f252c9b0SSascha Wildner mkfs_msdos(const char *fname, const char *dtype, const struct msdos_options *op)
231f252c9b0SSascha Wildner {
232f252c9b0SSascha Wildner char buf[MAXPATHLEN];
233f252c9b0SSascha Wildner struct sigaction si_sa;
234f252c9b0SSascha Wildner struct stat sb;
235f252c9b0SSascha Wildner struct timeval tv;
236f252c9b0SSascha Wildner struct bpb bpb;
237f252c9b0SSascha Wildner struct tm *tm;
238f252c9b0SSascha Wildner struct bs *bs;
239f252c9b0SSascha Wildner struct bsbpb *bsbpb;
240f252c9b0SSascha Wildner struct bsxbpb *bsxbpb;
241f252c9b0SSascha Wildner struct bsx *bsx;
242f252c9b0SSascha Wildner struct de *de;
243149331c9STomohiro Kusumi uint8_t *img;
244db72ecfeSTomohiro Kusumi uint8_t *physbuf, *physbuf_end;
245f252c9b0SSascha Wildner const char *bname;
246f252c9b0SSascha Wildner ssize_t n;
247f252c9b0SSascha Wildner time_t now;
248f252c9b0SSascha Wildner u_int fat, bss, rds, cls, dir, lsn, x, x1, x2;
24983751b8fSTomohiro Kusumi u_int extra_res, alignment, saved_x, attempts=0;
25083751b8fSTomohiro Kusumi bool set_res, set_spf, set_spc;
251f252c9b0SSascha Wildner int fd, fd1, rv;
252f252c9b0SSascha Wildner struct msdos_options o = *op;
253d14d5141STomohiro Kusumi ssize_t chunksize;
254f252c9b0SSascha Wildner
255db72ecfeSTomohiro Kusumi physbuf = NULL;
256f252c9b0SSascha Wildner rv = -1;
2575ad6c53aSTomohiro Kusumi fd = fd1 = -1;
258f252c9b0SSascha Wildner
259f252c9b0SSascha Wildner if (o.block_size && o.sectors_per_cluster) {
260f252c9b0SSascha Wildner warnx("Cannot specify both block size and sectors per cluster");
261f252c9b0SSascha Wildner goto done;
262f252c9b0SSascha Wildner }
263f252c9b0SSascha Wildner if (o.OEM_string && strlen(o.OEM_string) > 8) {
264f252c9b0SSascha Wildner warnx("%s: bad OEM string", o.OEM_string);
265f252c9b0SSascha Wildner goto done;
266f252c9b0SSascha Wildner }
267f252c9b0SSascha Wildner if (o.create_size) {
268f252c9b0SSascha Wildner if (o.no_create) {
269f252c9b0SSascha Wildner warnx("create (-C) is incompatible with -N");
270f252c9b0SSascha Wildner goto done;
271f252c9b0SSascha Wildner }
272f252c9b0SSascha Wildner fd = open(fname, O_RDWR | O_CREAT | O_TRUNC, 0644);
273f252c9b0SSascha Wildner if (fd == -1) {
274f252c9b0SSascha Wildner warnx("failed to create %s", fname);
275f252c9b0SSascha Wildner goto done;
276f252c9b0SSascha Wildner }
277f252c9b0SSascha Wildner if (ftruncate(fd, o.create_size)) {
278f252c9b0SSascha Wildner warnx("failed to initialize %jd bytes", (intmax_t)o.create_size);
279f252c9b0SSascha Wildner goto done;
280f252c9b0SSascha Wildner }
281f252c9b0SSascha Wildner } else if ((fd = open(fname, o.no_create ? O_RDONLY : O_RDWR)) == -1) {
282f252c9b0SSascha Wildner warn("%s", fname);
283f252c9b0SSascha Wildner goto done;
284f252c9b0SSascha Wildner }
285f252c9b0SSascha Wildner if (fstat(fd, &sb)) {
286f252c9b0SSascha Wildner warn("%s", fname);
287f252c9b0SSascha Wildner goto done;
288f252c9b0SSascha Wildner }
289f252c9b0SSascha Wildner if (o.create_size) {
290f252c9b0SSascha Wildner if (!S_ISREG(sb.st_mode))
291f252c9b0SSascha Wildner warnx("warning, %s is not a regular file", fname);
292f252c9b0SSascha Wildner } else {
293*c589a8b8STomohiro Kusumi #ifdef MAKEFS
294*c589a8b8STomohiro Kusumi errx(1, "o.create_size must be set!");
295*c589a8b8STomohiro Kusumi #else
296f252c9b0SSascha Wildner if (!S_ISCHR(sb.st_mode))
297f252c9b0SSascha Wildner warnx("warning, %s is not a character device", fname);
298*c589a8b8STomohiro Kusumi #endif
299f252c9b0SSascha Wildner }
300*c589a8b8STomohiro Kusumi #ifndef MAKEFS
301f252c9b0SSascha Wildner if (!o.no_create)
302f252c9b0SSascha Wildner if (check_mounted(fname, sb.st_mode) == -1)
303f252c9b0SSascha Wildner goto done;
304*c589a8b8STomohiro Kusumi #endif
305f252c9b0SSascha Wildner if (o.offset && o.offset != lseek(fd, o.offset, SEEK_SET)) {
306f252c9b0SSascha Wildner warnx("cannot seek to %jd", (intmax_t)o.offset);
307f252c9b0SSascha Wildner goto done;
308f252c9b0SSascha Wildner }
309f252c9b0SSascha Wildner memset(&bpb, 0, sizeof(bpb));
310f252c9b0SSascha Wildner if (o.floppy) {
311f252c9b0SSascha Wildner if (getstdfmt(o.floppy, &bpb) == -1)
312f252c9b0SSascha Wildner goto done;
313f252c9b0SSascha Wildner bpb.bpbHugeSectors = bpb.bpbSectors;
314f252c9b0SSascha Wildner bpb.bpbSectors = 0;
315f252c9b0SSascha Wildner bpb.bpbBigFATsecs = bpb.bpbFATsecs;
316f252c9b0SSascha Wildner bpb.bpbFATsecs = 0;
317f252c9b0SSascha Wildner }
318f252c9b0SSascha Wildner if (o.drive_heads)
319f252c9b0SSascha Wildner bpb.bpbHeads = o.drive_heads;
320f252c9b0SSascha Wildner if (o.sectors_per_track)
321f252c9b0SSascha Wildner bpb.bpbSecPerTrack = o.sectors_per_track;
322f252c9b0SSascha Wildner if (o.bytes_per_sector)
323f252c9b0SSascha Wildner bpb.bpbBytesPerSec = o.bytes_per_sector;
324f252c9b0SSascha Wildner if (o.size)
325f252c9b0SSascha Wildner bpb.bpbHugeSectors = o.size;
326f252c9b0SSascha Wildner if (o.hidden_sectors_set)
327f252c9b0SSascha Wildner bpb.bpbHiddenSecs = o.hidden_sectors;
328f252c9b0SSascha Wildner if (!(o.floppy || (o.drive_heads && o.sectors_per_track &&
329f252c9b0SSascha Wildner o.bytes_per_sector && o.size && o.hidden_sectors_set))) {
3308c741249STomohiro Kusumi if (getdiskinfo(fd, fname, dtype, o.hidden_sectors_set, &bpb) == -1)
3318c741249STomohiro Kusumi goto done;
332f252c9b0SSascha Wildner bpb.bpbHugeSectors -= (o.offset / bpb.bpbBytesPerSec);
333f252c9b0SSascha Wildner if (bpb.bpbSecPerClust == 0) { /* set defaults */
334f252c9b0SSascha Wildner if (bpb.bpbHugeSectors <= 6000) /* about 3MB -> 512 bytes */
335f252c9b0SSascha Wildner bpb.bpbSecPerClust = 1;
336f252c9b0SSascha Wildner else if (bpb.bpbHugeSectors <= (1<<17)) /* 64M -> 4k */
337f252c9b0SSascha Wildner bpb.bpbSecPerClust = 8;
338f252c9b0SSascha Wildner else if (bpb.bpbHugeSectors <= (1<<19)) /* 256M -> 8k */
339f252c9b0SSascha Wildner bpb.bpbSecPerClust = 16;
340f252c9b0SSascha Wildner else if (bpb.bpbHugeSectors <= (1<<21)) /* 1G -> 16k */
341f252c9b0SSascha Wildner bpb.bpbSecPerClust = 32;
342f252c9b0SSascha Wildner else
343f252c9b0SSascha Wildner bpb.bpbSecPerClust = 64; /* otherwise 32k */
344f252c9b0SSascha Wildner }
345f252c9b0SSascha Wildner }
346db72ecfeSTomohiro Kusumi if (bpb.bpbBytesPerSec < MINBPS ||
347db72ecfeSTomohiro Kusumi bpb.bpbBytesPerSec > MAXBPS ||
348db72ecfeSTomohiro Kusumi !powerof2(bpb.bpbBytesPerSec)) {
349db72ecfeSTomohiro Kusumi warnx("Invalid bytes/sector (%u): must be 512, 1024, 2048 or 4096",
350db72ecfeSTomohiro Kusumi bpb.bpbBytesPerSec);
351f252c9b0SSascha Wildner goto done;
352f252c9b0SSascha Wildner }
353f252c9b0SSascha Wildner
354f252c9b0SSascha Wildner if (o.volume_label && !oklabel(o.volume_label)) {
355f252c9b0SSascha Wildner warnx("%s: bad volume label", o.volume_label);
356f252c9b0SSascha Wildner goto done;
357f252c9b0SSascha Wildner }
358f252c9b0SSascha Wildner if (!(fat = o.fat_type)) {
359f252c9b0SSascha Wildner if (o.floppy)
360f252c9b0SSascha Wildner fat = 12;
361f252c9b0SSascha Wildner else if (!o.directory_entries && (o.info_sector || o.backup_sector))
362f252c9b0SSascha Wildner fat = 32;
363f252c9b0SSascha Wildner }
36459127828STomohiro Kusumi if ((fat == 32 && o.directory_entries) ||
36559127828STomohiro Kusumi (fat != 32 && (o.info_sector || o.backup_sector))) {
366f252c9b0SSascha Wildner warnx("-%c is not a legal FAT%s option",
367f252c9b0SSascha Wildner fat == 32 ? 'e' : o.info_sector ? 'i' : 'k',
368f252c9b0SSascha Wildner fat == 32 ? "32" : "12/16");
369f252c9b0SSascha Wildner goto done;
370f252c9b0SSascha Wildner }
371f252c9b0SSascha Wildner if (o.floppy && fat == 32)
372f252c9b0SSascha Wildner bpb.bpbRootDirEnts = 0;
373f252c9b0SSascha Wildner if (fat != 0 && fat != 12 && fat != 16 && fat != 32) {
374f252c9b0SSascha Wildner warnx("%d: bad FAT type", fat);
375f252c9b0SSascha Wildner goto done;
376f252c9b0SSascha Wildner }
377f252c9b0SSascha Wildner
378f252c9b0SSascha Wildner if (o.block_size) {
379f252c9b0SSascha Wildner if (!powerof2(o.block_size)) {
380f252c9b0SSascha Wildner warnx("block size (%u) is not a power of 2", o.block_size);
381f252c9b0SSascha Wildner goto done;
382f252c9b0SSascha Wildner }
383f252c9b0SSascha Wildner if (o.block_size < bpb.bpbBytesPerSec) {
384f252c9b0SSascha Wildner warnx("block size (%u) is too small; minimum is %u",
385f252c9b0SSascha Wildner o.block_size, bpb.bpbBytesPerSec);
386f252c9b0SSascha Wildner goto done;
387f252c9b0SSascha Wildner }
388f252c9b0SSascha Wildner if (o.block_size > bpb.bpbBytesPerSec * MAXSPC) {
389f252c9b0SSascha Wildner warnx("block size (%u) is too large; maximum is %u",
390f252c9b0SSascha Wildner o.block_size, bpb.bpbBytesPerSec * MAXSPC);
391f252c9b0SSascha Wildner goto done;
392f252c9b0SSascha Wildner }
393f252c9b0SSascha Wildner bpb.bpbSecPerClust = o.block_size / bpb.bpbBytesPerSec;
394f252c9b0SSascha Wildner }
395f252c9b0SSascha Wildner if (o.sectors_per_cluster) {
396f252c9b0SSascha Wildner if (!powerof2(o.sectors_per_cluster)) {
397f252c9b0SSascha Wildner warnx("sectors/cluster (%u) is not a power of 2",
398f252c9b0SSascha Wildner o.sectors_per_cluster);
399f252c9b0SSascha Wildner goto done;
400f252c9b0SSascha Wildner }
401f252c9b0SSascha Wildner bpb.bpbSecPerClust = o.sectors_per_cluster;
402f252c9b0SSascha Wildner }
403f252c9b0SSascha Wildner if (o.reserved_sectors)
404f252c9b0SSascha Wildner bpb.bpbResSectors = o.reserved_sectors;
405f252c9b0SSascha Wildner if (o.num_FAT) {
406f252c9b0SSascha Wildner if (o.num_FAT > MAXNFT) {
407f252c9b0SSascha Wildner warnx("number of FATs (%u) is too large; maximum is %u",
408f252c9b0SSascha Wildner o.num_FAT, MAXNFT);
409f252c9b0SSascha Wildner goto done;
410f252c9b0SSascha Wildner }
411f252c9b0SSascha Wildner bpb.bpbFATs = o.num_FAT;
412f252c9b0SSascha Wildner }
413f252c9b0SSascha Wildner if (o.directory_entries)
414f252c9b0SSascha Wildner bpb.bpbRootDirEnts = o.directory_entries;
415f252c9b0SSascha Wildner if (o.media_descriptor_set) {
416f252c9b0SSascha Wildner if (o.media_descriptor < 0xf0) {
417f252c9b0SSascha Wildner warnx("illegal media descriptor (%#x)", o.media_descriptor);
418f252c9b0SSascha Wildner goto done;
419f252c9b0SSascha Wildner }
420f252c9b0SSascha Wildner bpb.bpbMedia = o.media_descriptor;
421f252c9b0SSascha Wildner }
422f252c9b0SSascha Wildner if (o.sectors_per_fat)
423f252c9b0SSascha Wildner bpb.bpbBigFATsecs = o.sectors_per_fat;
424f252c9b0SSascha Wildner if (o.info_sector)
425f252c9b0SSascha Wildner bpb.bpbFSInfo = o.info_sector;
426f252c9b0SSascha Wildner if (o.backup_sector)
427f252c9b0SSascha Wildner bpb.bpbBackup = o.backup_sector;
428f252c9b0SSascha Wildner bss = 1;
429f252c9b0SSascha Wildner bname = NULL;
430f252c9b0SSascha Wildner fd1 = -1;
431f252c9b0SSascha Wildner if (o.bootstrap) {
432f252c9b0SSascha Wildner bname = o.bootstrap;
433f252c9b0SSascha Wildner if (!strchr(bname, '/')) {
434f252c9b0SSascha Wildner snprintf(buf, sizeof(buf), "/boot/%s", bname);
4358c741249STomohiro Kusumi bname = buf;
436f252c9b0SSascha Wildner }
437f252c9b0SSascha Wildner if ((fd1 = open(bname, O_RDONLY)) == -1 || fstat(fd1, &sb)) {
438f252c9b0SSascha Wildner warn("%s", bname);
439f252c9b0SSascha Wildner goto done;
440f252c9b0SSascha Wildner }
441f252c9b0SSascha Wildner if (!S_ISREG(sb.st_mode) || sb.st_size % bpb.bpbBytesPerSec ||
442f252c9b0SSascha Wildner sb.st_size < bpb.bpbBytesPerSec ||
443f252c9b0SSascha Wildner sb.st_size > bpb.bpbBytesPerSec * MAXU16) {
444f252c9b0SSascha Wildner warnx("%s: inappropriate file type or format", bname);
445f252c9b0SSascha Wildner goto done;
446f252c9b0SSascha Wildner }
447f252c9b0SSascha Wildner bss = sb.st_size / bpb.bpbBytesPerSec;
448f252c9b0SSascha Wildner }
449f252c9b0SSascha Wildner if (!bpb.bpbFATs)
450f252c9b0SSascha Wildner bpb.bpbFATs = 2;
451f252c9b0SSascha Wildner if (!fat) {
452f252c9b0SSascha Wildner if (bpb.bpbHugeSectors < (bpb.bpbResSectors ? bpb.bpbResSectors : bss) +
453f252c9b0SSascha Wildner howmany((RESFTE + (bpb.bpbSecPerClust ? MINCLS16 : MAXCLS12 + 1)) *
454f252c9b0SSascha Wildner (bpb.bpbSecPerClust ? 16 : 12) / BPN,
455f252c9b0SSascha Wildner bpb.bpbBytesPerSec * NPB) *
456f252c9b0SSascha Wildner bpb.bpbFATs +
457f252c9b0SSascha Wildner howmany(bpb.bpbRootDirEnts ? bpb.bpbRootDirEnts : DEFRDE,
458f252c9b0SSascha Wildner bpb.bpbBytesPerSec / sizeof(struct de)) +
459f252c9b0SSascha Wildner (bpb.bpbSecPerClust ? MINCLS16 : MAXCLS12 + 1) *
460f252c9b0SSascha Wildner (bpb.bpbSecPerClust ? bpb.bpbSecPerClust :
461f252c9b0SSascha Wildner howmany(DEFBLK, bpb.bpbBytesPerSec)))
462f252c9b0SSascha Wildner fat = 12;
463f252c9b0SSascha Wildner else if (bpb.bpbRootDirEnts || bpb.bpbHugeSectors <
464f252c9b0SSascha Wildner (bpb.bpbResSectors ? bpb.bpbResSectors : bss) +
465f252c9b0SSascha Wildner howmany((RESFTE + MAXCLS16) * 2, bpb.bpbBytesPerSec) *
466f252c9b0SSascha Wildner bpb.bpbFATs +
467f252c9b0SSascha Wildner howmany(DEFRDE, bpb.bpbBytesPerSec / sizeof(struct de)) +
468f252c9b0SSascha Wildner (MAXCLS16 + 1) *
469f252c9b0SSascha Wildner (bpb.bpbSecPerClust ? bpb.bpbSecPerClust :
470f252c9b0SSascha Wildner howmany(8192, bpb.bpbBytesPerSec)))
471f252c9b0SSascha Wildner fat = 16;
472f252c9b0SSascha Wildner else
473f252c9b0SSascha Wildner fat = 32;
474f252c9b0SSascha Wildner }
475f252c9b0SSascha Wildner x = bss;
476f252c9b0SSascha Wildner if (fat == 32) {
477f252c9b0SSascha Wildner if (!bpb.bpbFSInfo) {
478f252c9b0SSascha Wildner if (x == MAXU16 || x == bpb.bpbBackup) {
479f252c9b0SSascha Wildner warnx("no room for info sector");
480f252c9b0SSascha Wildner goto done;
481f252c9b0SSascha Wildner }
482f252c9b0SSascha Wildner bpb.bpbFSInfo = x;
483f252c9b0SSascha Wildner }
484f252c9b0SSascha Wildner if (bpb.bpbFSInfo != MAXU16 && x <= bpb.bpbFSInfo)
485f252c9b0SSascha Wildner x = bpb.bpbFSInfo + 1;
486f252c9b0SSascha Wildner if (!bpb.bpbBackup) {
487f252c9b0SSascha Wildner if (x == MAXU16) {
488f252c9b0SSascha Wildner warnx("no room for backup sector");
489f252c9b0SSascha Wildner goto done;
490f252c9b0SSascha Wildner }
491f252c9b0SSascha Wildner bpb.bpbBackup = x;
492f252c9b0SSascha Wildner } else if (bpb.bpbBackup != MAXU16 && bpb.bpbBackup == bpb.bpbFSInfo) {
493f252c9b0SSascha Wildner warnx("backup sector would overwrite info sector");
494f252c9b0SSascha Wildner goto done;
495f252c9b0SSascha Wildner }
496f252c9b0SSascha Wildner if (bpb.bpbBackup != MAXU16 && x <= bpb.bpbBackup)
497f252c9b0SSascha Wildner x = bpb.bpbBackup + 1;
498f252c9b0SSascha Wildner }
49983751b8fSTomohiro Kusumi
50083751b8fSTomohiro Kusumi extra_res = 0;
50183751b8fSTomohiro Kusumi alignment = 0;
50283751b8fSTomohiro Kusumi set_res = (bpb.bpbResSectors == 0);
50383751b8fSTomohiro Kusumi set_spf = (bpb.bpbBigFATsecs == 0);
50483751b8fSTomohiro Kusumi set_spc = (bpb.bpbSecPerClust == 0);
50583751b8fSTomohiro Kusumi saved_x = x;
50683751b8fSTomohiro Kusumi
50783751b8fSTomohiro Kusumi /*
50883751b8fSTomohiro Kusumi * Attempt to align the root directory to cluster if o.align is set.
50983751b8fSTomohiro Kusumi * This is done by padding with reserved blocks. Note that this can
51083751b8fSTomohiro Kusumi * cause other factors to change, which can in turn change the alignment.
51183751b8fSTomohiro Kusumi * This should take at most 2 iterations, as increasing the reserved
51283751b8fSTomohiro Kusumi * amount may cause the FAT size to decrease by 1, requiring another
51383751b8fSTomohiro Kusumi * bpbFATs reserved blocks. If bpbSecPerClust changes, it will
51483751b8fSTomohiro Kusumi * be half of its previous size, and thus will not throw off alignment.
51583751b8fSTomohiro Kusumi */
51683751b8fSTomohiro Kusumi do {
51783751b8fSTomohiro Kusumi x = saved_x;
51883751b8fSTomohiro Kusumi if (set_res)
51983751b8fSTomohiro Kusumi bpb.bpbResSectors = ((fat == 32) ?
52083751b8fSTomohiro Kusumi MAX(x, MAX(16384 / bpb.bpbBytesPerSec, 4)) : x) + extra_res;
521f252c9b0SSascha Wildner else if (bpb.bpbResSectors < x) {
522f252c9b0SSascha Wildner warnx("too few reserved sectors (need %d have %d)", x,
523f252c9b0SSascha Wildner bpb.bpbResSectors);
524f252c9b0SSascha Wildner goto done;
525f252c9b0SSascha Wildner }
526f252c9b0SSascha Wildner if (fat != 32 && !bpb.bpbRootDirEnts)
527f252c9b0SSascha Wildner bpb.bpbRootDirEnts = DEFRDE;
52883751b8fSTomohiro Kusumi rds = howmany(bpb.bpbRootDirEnts,
52983751b8fSTomohiro Kusumi bpb.bpbBytesPerSec / sizeof(struct de));
53083751b8fSTomohiro Kusumi if (set_spc) {
531f252c9b0SSascha Wildner for (bpb.bpbSecPerClust = howmany(fat == 16 ? DEFBLK16 :
532f252c9b0SSascha Wildner DEFBLK, bpb.bpbBytesPerSec);
53383751b8fSTomohiro Kusumi bpb.bpbSecPerClust < MAXSPC && (bpb.bpbResSectors +
534f252c9b0SSascha Wildner howmany((RESFTE + maxcls(fat)) * (fat / BPN),
53583751b8fSTomohiro Kusumi bpb.bpbBytesPerSec * NPB) * bpb.bpbFATs +
536f252c9b0SSascha Wildner rds +
53783751b8fSTomohiro Kusumi (u_int64_t) (maxcls(fat) + 1) * bpb.bpbSecPerClust) <=
53883751b8fSTomohiro Kusumi bpb.bpbHugeSectors;
539f252c9b0SSascha Wildner bpb.bpbSecPerClust <<= 1)
540f252c9b0SSascha Wildner continue;
54183751b8fSTomohiro Kusumi
54283751b8fSTomohiro Kusumi }
543f252c9b0SSascha Wildner if (fat != 32 && bpb.bpbBigFATsecs > MAXU16) {
544f252c9b0SSascha Wildner warnx("too many sectors/FAT for FAT12/16");
545f252c9b0SSascha Wildner goto done;
546f252c9b0SSascha Wildner }
547f252c9b0SSascha Wildner x1 = bpb.bpbResSectors + rds;
548f252c9b0SSascha Wildner x = bpb.bpbBigFATsecs ? bpb.bpbBigFATsecs : 1;
54983751b8fSTomohiro Kusumi if (x1 + (u_int64_t)x * bpb.bpbFATs > bpb.bpbHugeSectors) {
550f252c9b0SSascha Wildner warnx("meta data exceeds file system size");
551f252c9b0SSascha Wildner goto done;
552f252c9b0SSascha Wildner }
553f252c9b0SSascha Wildner x1 += x * bpb.bpbFATs;
55483751b8fSTomohiro Kusumi x = (u_int64_t)(bpb.bpbHugeSectors - x1) * bpb.bpbBytesPerSec * NPB /
55583751b8fSTomohiro Kusumi (bpb.bpbSecPerClust * bpb.bpbBytesPerSec * NPB +
55683751b8fSTomohiro Kusumi fat / BPN * bpb.bpbFATs);
557f252c9b0SSascha Wildner x2 = howmany((RESFTE + MIN(x, maxcls(fat))) * (fat / BPN),
558f252c9b0SSascha Wildner bpb.bpbBytesPerSec * NPB);
55983751b8fSTomohiro Kusumi if (set_spf) {
56083751b8fSTomohiro Kusumi if (bpb.bpbBigFATsecs == 0)
561f252c9b0SSascha Wildner bpb.bpbBigFATsecs = x2;
562f252c9b0SSascha Wildner x1 += (bpb.bpbBigFATsecs - 1) * bpb.bpbFATs;
563f252c9b0SSascha Wildner }
56483751b8fSTomohiro Kusumi if (set_res) {
56583751b8fSTomohiro Kusumi /* attempt to align root directory */
56683751b8fSTomohiro Kusumi alignment = (bpb.bpbResSectors + bpb.bpbBigFATsecs * bpb.bpbFATs) %
56783751b8fSTomohiro Kusumi bpb.bpbSecPerClust;
56883751b8fSTomohiro Kusumi if (o.align)
56983751b8fSTomohiro Kusumi extra_res += bpb.bpbSecPerClust - alignment;
57083751b8fSTomohiro Kusumi }
57183751b8fSTomohiro Kusumi attempts++;
57283751b8fSTomohiro Kusumi } while (o.align && alignment != 0 && attempts < 2);
57383751b8fSTomohiro Kusumi if (o.align && alignment != 0)
57483751b8fSTomohiro Kusumi warnx("warning: Alignment failed.");
57583751b8fSTomohiro Kusumi
576f252c9b0SSascha Wildner cls = (bpb.bpbHugeSectors - x1) / bpb.bpbSecPerClust;
577149331c9STomohiro Kusumi x = (uint64_t)bpb.bpbBigFATsecs * bpb.bpbBytesPerSec * NPB / (fat / BPN) -
578f252c9b0SSascha Wildner RESFTE;
579f252c9b0SSascha Wildner if (cls > x)
580f252c9b0SSascha Wildner cls = x;
581f252c9b0SSascha Wildner if (bpb.bpbBigFATsecs < x2)
582f252c9b0SSascha Wildner warnx("warning: sectors/FAT limits file system to %u clusters",
583f252c9b0SSascha Wildner cls);
584f252c9b0SSascha Wildner if (cls < mincls(fat)) {
585f252c9b0SSascha Wildner warnx("%u clusters too few clusters for FAT%u, need %u", cls, fat,
586f252c9b0SSascha Wildner mincls(fat));
587f252c9b0SSascha Wildner goto done;
588f252c9b0SSascha Wildner }
589f252c9b0SSascha Wildner if (cls > maxcls(fat)) {
590f252c9b0SSascha Wildner cls = maxcls(fat);
591f252c9b0SSascha Wildner bpb.bpbHugeSectors = x1 + (cls + 1) * bpb.bpbSecPerClust - 1;
592f252c9b0SSascha Wildner warnx("warning: FAT type limits file system to %u sectors",
593f252c9b0SSascha Wildner bpb.bpbHugeSectors);
594f252c9b0SSascha Wildner }
595f252c9b0SSascha Wildner printf("%s: %u sector%s in %u FAT%u cluster%s "
596f252c9b0SSascha Wildner "(%u bytes/cluster)\n", fname, cls * bpb.bpbSecPerClust,
597f252c9b0SSascha Wildner cls * bpb.bpbSecPerClust == 1 ? "" : "s", cls, fat,
598f252c9b0SSascha Wildner cls == 1 ? "" : "s", bpb.bpbBytesPerSec * bpb.bpbSecPerClust);
599f252c9b0SSascha Wildner if (!bpb.bpbMedia)
600f252c9b0SSascha Wildner bpb.bpbMedia = !bpb.bpbHiddenSecs ? 0xf0 : 0xf8;
601f252c9b0SSascha Wildner if (fat == 32)
602f252c9b0SSascha Wildner bpb.bpbRootClust = RESFTE;
603f252c9b0SSascha Wildner if (bpb.bpbHugeSectors <= MAXU16) {
604f252c9b0SSascha Wildner bpb.bpbSectors = bpb.bpbHugeSectors;
605f252c9b0SSascha Wildner bpb.bpbHugeSectors = 0;
606f252c9b0SSascha Wildner }
607f252c9b0SSascha Wildner if (fat != 32) {
608f252c9b0SSascha Wildner bpb.bpbFATsecs = bpb.bpbBigFATsecs;
609f252c9b0SSascha Wildner bpb.bpbBigFATsecs = 0;
610f252c9b0SSascha Wildner }
611f252c9b0SSascha Wildner print_bpb(&bpb);
612f252c9b0SSascha Wildner if (!o.no_create) {
61383751b8fSTomohiro Kusumi if (o.timestamp_set) {
61483751b8fSTomohiro Kusumi tv.tv_sec = now = o.timestamp;
61583751b8fSTomohiro Kusumi tv.tv_usec = 0;
61683751b8fSTomohiro Kusumi tm = gmtime(&now);
61783751b8fSTomohiro Kusumi } else {
618f252c9b0SSascha Wildner gettimeofday(&tv, NULL);
619f252c9b0SSascha Wildner now = tv.tv_sec;
620f252c9b0SSascha Wildner tm = localtime(&now);
62183751b8fSTomohiro Kusumi }
62283751b8fSTomohiro Kusumi
623d14d5141STomohiro Kusumi chunksize = getchunksize();
624db72ecfeSTomohiro Kusumi physbuf = malloc(chunksize);
625db72ecfeSTomohiro Kusumi if (physbuf == NULL) {
626f252c9b0SSascha Wildner warn(NULL);
627f252c9b0SSascha Wildner goto done;
628f252c9b0SSascha Wildner }
629db72ecfeSTomohiro Kusumi physbuf_end = physbuf + chunksize;
630db72ecfeSTomohiro Kusumi img = physbuf;
631db72ecfeSTomohiro Kusumi
632f252c9b0SSascha Wildner dir = bpb.bpbResSectors + (bpb.bpbFATsecs ? bpb.bpbFATsecs :
633f252c9b0SSascha Wildner bpb.bpbBigFATsecs) * bpb.bpbFATs;
634f252c9b0SSascha Wildner memset(&si_sa, 0, sizeof(si_sa));
635f252c9b0SSascha Wildner si_sa.sa_handler = infohandler;
636f252c9b0SSascha Wildner if (sigaction(SIGINFO, &si_sa, NULL) == -1) {
637f252c9b0SSascha Wildner warn("sigaction SIGINFO");
638f252c9b0SSascha Wildner goto done;
639f252c9b0SSascha Wildner }
640f252c9b0SSascha Wildner for (lsn = 0; lsn < dir + (fat == 32 ? bpb.bpbSecPerClust : rds); lsn++) {
641f252c9b0SSascha Wildner if (got_siginfo) {
642f252c9b0SSascha Wildner fprintf(stderr,"%s: writing sector %u of %u (%u%%)\n",
643f252c9b0SSascha Wildner fname, lsn,
644f252c9b0SSascha Wildner (dir + (fat == 32 ? bpb.bpbSecPerClust: rds)),
645f252c9b0SSascha Wildner (lsn * 100) / (dir +
646f252c9b0SSascha Wildner (fat == 32 ? bpb.bpbSecPerClust: rds)));
647f252c9b0SSascha Wildner got_siginfo = 0;
648f252c9b0SSascha Wildner }
649f252c9b0SSascha Wildner x = lsn;
650f252c9b0SSascha Wildner if (o.bootstrap &&
651f252c9b0SSascha Wildner fat == 32 && bpb.bpbBackup != MAXU16 &&
652f252c9b0SSascha Wildner bss <= bpb.bpbBackup && x >= bpb.bpbBackup) {
653f252c9b0SSascha Wildner x -= bpb.bpbBackup;
654f252c9b0SSascha Wildner if (!x && lseek(fd1, o.offset, SEEK_SET)) {
655f252c9b0SSascha Wildner warn("%s", bname);
656f252c9b0SSascha Wildner goto done;
657f252c9b0SSascha Wildner }
658f252c9b0SSascha Wildner }
659f252c9b0SSascha Wildner if (o.bootstrap && x < bss) {
660f252c9b0SSascha Wildner if ((n = read(fd1, img, bpb.bpbBytesPerSec)) == -1) {
661f252c9b0SSascha Wildner warn("%s", bname);
662f252c9b0SSascha Wildner goto done;
663f252c9b0SSascha Wildner }
664f252c9b0SSascha Wildner if ((unsigned)n != bpb.bpbBytesPerSec) {
665f252c9b0SSascha Wildner warnx("%s: can't read sector %u", bname, x);
666f252c9b0SSascha Wildner goto done;
667f252c9b0SSascha Wildner }
668f252c9b0SSascha Wildner } else
669f252c9b0SSascha Wildner memset(img, 0, bpb.bpbBytesPerSec);
670f252c9b0SSascha Wildner if (!lsn ||
671f252c9b0SSascha Wildner (fat == 32 && bpb.bpbBackup != MAXU16 &&
672f252c9b0SSascha Wildner lsn == bpb.bpbBackup)) {
673f252c9b0SSascha Wildner x1 = sizeof(struct bs);
674f252c9b0SSascha Wildner bsbpb = (struct bsbpb *)(img + x1);
675f252c9b0SSascha Wildner mk2(bsbpb->bpbBytesPerSec, bpb.bpbBytesPerSec);
676f252c9b0SSascha Wildner mk1(bsbpb->bpbSecPerClust, bpb.bpbSecPerClust);
677f252c9b0SSascha Wildner mk2(bsbpb->bpbResSectors, bpb.bpbResSectors);
678f252c9b0SSascha Wildner mk1(bsbpb->bpbFATs, bpb.bpbFATs);
679f252c9b0SSascha Wildner mk2(bsbpb->bpbRootDirEnts, bpb.bpbRootDirEnts);
680f252c9b0SSascha Wildner mk2(bsbpb->bpbSectors, bpb.bpbSectors);
681f252c9b0SSascha Wildner mk1(bsbpb->bpbMedia, bpb.bpbMedia);
682f252c9b0SSascha Wildner mk2(bsbpb->bpbFATsecs, bpb.bpbFATsecs);
683f252c9b0SSascha Wildner mk2(bsbpb->bpbSecPerTrack, bpb.bpbSecPerTrack);
684f252c9b0SSascha Wildner mk2(bsbpb->bpbHeads, bpb.bpbHeads);
685f252c9b0SSascha Wildner mk4(bsbpb->bpbHiddenSecs, bpb.bpbHiddenSecs);
686f252c9b0SSascha Wildner mk4(bsbpb->bpbHugeSectors, bpb.bpbHugeSectors);
687f252c9b0SSascha Wildner x1 += sizeof(struct bsbpb);
688f252c9b0SSascha Wildner if (fat == 32) {
689f252c9b0SSascha Wildner bsxbpb = (struct bsxbpb *)(img + x1);
690f252c9b0SSascha Wildner mk4(bsxbpb->bpbBigFATsecs, bpb.bpbBigFATsecs);
691f252c9b0SSascha Wildner mk2(bsxbpb->bpbExtFlags, 0);
692f252c9b0SSascha Wildner mk2(bsxbpb->bpbFSVers, 0);
693f252c9b0SSascha Wildner mk4(bsxbpb->bpbRootClust, bpb.bpbRootClust);
694f252c9b0SSascha Wildner mk2(bsxbpb->bpbFSInfo, bpb.bpbFSInfo);
695f252c9b0SSascha Wildner mk2(bsxbpb->bpbBackup, bpb.bpbBackup);
696f252c9b0SSascha Wildner x1 += sizeof(struct bsxbpb);
697f252c9b0SSascha Wildner }
698f252c9b0SSascha Wildner bsx = (struct bsx *)(img + x1);
699f252c9b0SSascha Wildner mk1(bsx->exBootSignature, 0x29);
700f252c9b0SSascha Wildner if (o.volume_id_set)
701f252c9b0SSascha Wildner x = o.volume_id;
702f252c9b0SSascha Wildner else
703f252c9b0SSascha Wildner x = (((u_int)(1 + tm->tm_mon) << 8 |
704f252c9b0SSascha Wildner (u_int)tm->tm_mday) +
705f252c9b0SSascha Wildner ((u_int)tm->tm_sec << 8 |
706f252c9b0SSascha Wildner (u_int)(tv.tv_usec / 10))) << 16 |
707f252c9b0SSascha Wildner ((u_int)(1900 + tm->tm_year) +
708f252c9b0SSascha Wildner ((u_int)tm->tm_hour << 8 |
709f252c9b0SSascha Wildner (u_int)tm->tm_min));
710f252c9b0SSascha Wildner mk4(bsx->exVolumeID, x);
711f252c9b0SSascha Wildner mklabel(bsx->exVolumeLabel, o.volume_label ? o.volume_label : "NO NAME");
712f252c9b0SSascha Wildner snprintf(buf, sizeof(buf), "FAT%u", fat);
713f252c9b0SSascha Wildner setstr(bsx->exFileSysType, buf, sizeof(bsx->exFileSysType));
714f252c9b0SSascha Wildner if (!o.bootstrap) {
715f252c9b0SSascha Wildner x1 += sizeof(struct bsx);
716f252c9b0SSascha Wildner bs = (struct bs *)img;
717f252c9b0SSascha Wildner mk1(bs->bsJump[0], 0xeb);
718f252c9b0SSascha Wildner mk1(bs->bsJump[1], x1 - 2);
719f252c9b0SSascha Wildner mk1(bs->bsJump[2], 0x90);
720f252c9b0SSascha Wildner setstr(bs->bsOemName, o.OEM_string ? o.OEM_string : "BSD4.4 ",
721f252c9b0SSascha Wildner sizeof(bs->bsOemName));
722f252c9b0SSascha Wildner memcpy(img + x1, bootcode, sizeof(bootcode));
723f252c9b0SSascha Wildner mk2(img + MINBPS - 2, DOSMAGIC);
724f252c9b0SSascha Wildner }
725f252c9b0SSascha Wildner } else if (fat == 32 && bpb.bpbFSInfo != MAXU16 &&
726f252c9b0SSascha Wildner (lsn == bpb.bpbFSInfo ||
727f252c9b0SSascha Wildner (bpb.bpbBackup != MAXU16 &&
728f252c9b0SSascha Wildner lsn == bpb.bpbBackup + bpb.bpbFSInfo))) {
729f252c9b0SSascha Wildner mk4(img, 0x41615252);
730f252c9b0SSascha Wildner mk4(img + MINBPS - 28, 0x61417272);
731f252c9b0SSascha Wildner mk4(img + MINBPS - 24, 0xffffffff);
732bb3df752STomohiro Kusumi mk4(img + MINBPS - 20, 0xffffffff);
733f252c9b0SSascha Wildner mk2(img + MINBPS - 2, DOSMAGIC);
734f252c9b0SSascha Wildner } else if (lsn >= bpb.bpbResSectors && lsn < dir &&
735f252c9b0SSascha Wildner !((lsn - bpb.bpbResSectors) %
736f252c9b0SSascha Wildner (bpb.bpbFATsecs ? bpb.bpbFATsecs :
737f252c9b0SSascha Wildner bpb.bpbBigFATsecs))) {
738f252c9b0SSascha Wildner mk1(img[0], bpb.bpbMedia);
739f252c9b0SSascha Wildner for (x = 1; x < fat * (fat == 32 ? 3 : 2) / 8; x++)
740f252c9b0SSascha Wildner mk1(img[x], fat == 32 && x % 4 == 3 ? 0x0f : 0xff);
741f252c9b0SSascha Wildner } else if (lsn == dir && o.volume_label) {
742f252c9b0SSascha Wildner de = (struct de *)img;
743f252c9b0SSascha Wildner mklabel(de->deName, o.volume_label);
744f252c9b0SSascha Wildner mk1(de->deAttributes, 050);
745f252c9b0SSascha Wildner x = (u_int)tm->tm_hour << 11 |
746f252c9b0SSascha Wildner (u_int)tm->tm_min << 5 |
747f252c9b0SSascha Wildner (u_int)tm->tm_sec >> 1;
748f252c9b0SSascha Wildner mk2(de->deMTime, x);
749f252c9b0SSascha Wildner x = (u_int)(tm->tm_year - 80) << 9 |
750f252c9b0SSascha Wildner (u_int)(tm->tm_mon + 1) << 5 |
751f252c9b0SSascha Wildner (u_int)tm->tm_mday;
752f252c9b0SSascha Wildner mk2(de->deMDate, x);
753f252c9b0SSascha Wildner }
754db72ecfeSTomohiro Kusumi /*
755db72ecfeSTomohiro Kusumi * Issue a write of chunksize once we have collected
756db72ecfeSTomohiro Kusumi * enough sectors.
757db72ecfeSTomohiro Kusumi */
758db72ecfeSTomohiro Kusumi img += bpb.bpbBytesPerSec;
759db72ecfeSTomohiro Kusumi if (img >= physbuf_end) {
760db72ecfeSTomohiro Kusumi n = write(fd, physbuf, chunksize);
761db72ecfeSTomohiro Kusumi if (n != chunksize) {
762db72ecfeSTomohiro Kusumi warnx("%s: can't write sector %u", fname, lsn);
763f252c9b0SSascha Wildner goto done;
764f252c9b0SSascha Wildner }
765db72ecfeSTomohiro Kusumi img = physbuf;
766db72ecfeSTomohiro Kusumi }
767db72ecfeSTomohiro Kusumi }
768db72ecfeSTomohiro Kusumi /*
769db72ecfeSTomohiro Kusumi * Write remaining sectors, if the last write didn't end
770db72ecfeSTomohiro Kusumi * up filling a whole chunk.
771db72ecfeSTomohiro Kusumi */
772db72ecfeSTomohiro Kusumi if (img != physbuf) {
773db72ecfeSTomohiro Kusumi ssize_t tailsize = img - physbuf;
774db72ecfeSTomohiro Kusumi
775db72ecfeSTomohiro Kusumi n = write(fd, physbuf, tailsize);
776db72ecfeSTomohiro Kusumi if (n != tailsize) {
777f252c9b0SSascha Wildner warnx("%s: can't write sector %u", fname, lsn);
778f252c9b0SSascha Wildner goto done;
779f252c9b0SSascha Wildner }
780f252c9b0SSascha Wildner }
781f252c9b0SSascha Wildner }
782f252c9b0SSascha Wildner rv = 0;
783f252c9b0SSascha Wildner done:
784db72ecfeSTomohiro Kusumi free(physbuf);
7855ad6c53aSTomohiro Kusumi if (fd != -1)
7865ad6c53aSTomohiro Kusumi close(fd);
7875ad6c53aSTomohiro Kusumi if (fd1 != -1)
7885ad6c53aSTomohiro Kusumi close(fd1);
789f252c9b0SSascha Wildner
790f252c9b0SSascha Wildner return rv;
791f252c9b0SSascha Wildner }
792f252c9b0SSascha Wildner
793f252c9b0SSascha Wildner /*
794f252c9b0SSascha Wildner * return -1 with error if file system is mounted.
795f252c9b0SSascha Wildner */
796*c589a8b8STomohiro Kusumi #ifndef MAKEFS
797f252c9b0SSascha Wildner static int
check_mounted(const char * fname,mode_t mode)798f252c9b0SSascha Wildner check_mounted(const char *fname, mode_t mode)
799f252c9b0SSascha Wildner {
800*c589a8b8STomohiro Kusumi /*
801*c589a8b8STomohiro Kusumi * If getmntinfo() is not available (e.g. Linux) don't check. This should
802*c589a8b8STomohiro Kusumi * not be a problem since we will only be using makefs to create images.
803*c589a8b8STomohiro Kusumi */
804f252c9b0SSascha Wildner struct statfs *mp;
805f252c9b0SSascha Wildner const char *s1, *s2;
806f252c9b0SSascha Wildner size_t len;
807f252c9b0SSascha Wildner int n, r;
808f252c9b0SSascha Wildner
809f252c9b0SSascha Wildner if (!(n = getmntinfo(&mp, MNT_NOWAIT))) {
810f252c9b0SSascha Wildner warn("getmntinfo");
811f252c9b0SSascha Wildner return -1;
812f252c9b0SSascha Wildner }
813f252c9b0SSascha Wildner len = strlen(_PATH_DEV);
814f252c9b0SSascha Wildner s1 = fname;
815f252c9b0SSascha Wildner if (!strncmp(s1, _PATH_DEV, len))
816f252c9b0SSascha Wildner s1 += len;
817f252c9b0SSascha Wildner r = S_ISCHR(mode) && s1 != fname && *s1 == 'r';
818f252c9b0SSascha Wildner for (; n--; mp++) {
819f252c9b0SSascha Wildner s2 = mp->f_mntfromname;
820f252c9b0SSascha Wildner if (!strncmp(s2, _PATH_DEV, len))
821f252c9b0SSascha Wildner s2 += len;
822f252c9b0SSascha Wildner if ((r && s2 != mp->f_mntfromname && !strcmp(s1 + 1, s2)) ||
823f252c9b0SSascha Wildner !strcmp(s1, s2)) {
824f252c9b0SSascha Wildner warnx("%s is mounted on %s", fname, mp->f_mntonname);
825f252c9b0SSascha Wildner return -1;
826f252c9b0SSascha Wildner }
827f252c9b0SSascha Wildner }
828f252c9b0SSascha Wildner return 0;
829f252c9b0SSascha Wildner }
830*c589a8b8STomohiro Kusumi #endif
831f252c9b0SSascha Wildner
832f252c9b0SSascha Wildner /*
833d14d5141STomohiro Kusumi * Get optimal I/O size
834d14d5141STomohiro Kusumi */
835d14d5141STomohiro Kusumi static ssize_t
getchunksize(void)836d14d5141STomohiro Kusumi getchunksize(void)
837d14d5141STomohiro Kusumi {
838*c589a8b8STomohiro Kusumi static ssize_t chunksize;
839d14d5141STomohiro Kusumi
840d14d5141STomohiro Kusumi if (chunksize != 0)
841*c589a8b8STomohiro Kusumi return (chunksize);
842d14d5141STomohiro Kusumi
843d14d5141STomohiro Kusumi #if 0
844d14d5141STomohiro Kusumi int mib[2];
845d14d5141STomohiro Kusumi size_t len;
846d14d5141STomohiro Kusumi
847d14d5141STomohiro Kusumi mib[0] = CTL_KERN;
848d14d5141STomohiro Kusumi mib[1] = KERN_MAXPHYS;
849d14d5141STomohiro Kusumi len = sizeof(chunksize);
850d14d5141STomohiro Kusumi
851d14d5141STomohiro Kusumi if (sysctl(mib, 2, &chunksize, &len, NULL, 0) == -1) {
852d14d5141STomohiro Kusumi warn("sysctl: KERN_MAXPHYS, using %zu", (size_t)MAXPHYS);
853d14d5141STomohiro Kusumi chunksize = 0;
854d14d5141STomohiro Kusumi }
855d14d5141STomohiro Kusumi #endif
856d14d5141STomohiro Kusumi if (chunksize == 0)
857d14d5141STomohiro Kusumi chunksize = MAXPHYS;
858d14d5141STomohiro Kusumi
859d14d5141STomohiro Kusumi /*
860d14d5141STomohiro Kusumi * For better performance, we want to write larger chunks instead of
861d14d5141STomohiro Kusumi * individual sectors (the size can only be 512, 1024, 2048 or 4096
862d14d5141STomohiro Kusumi * bytes). Assert that chunksize can always hold an integer number of
863d14d5141STomohiro Kusumi * sectors by asserting that both are power of two numbers and the
864d14d5141STomohiro Kusumi * chunksize is greater than MAXBPS.
865d14d5141STomohiro Kusumi */
866d14d5141STomohiro Kusumi static_assert(powerof2(MAXBPS), "MAXBPS is not power of 2");
867d14d5141STomohiro Kusumi assert(powerof2(chunksize));
868d14d5141STomohiro Kusumi assert(chunksize > MAXBPS);
869d14d5141STomohiro Kusumi
870*c589a8b8STomohiro Kusumi return (chunksize);
871d14d5141STomohiro Kusumi }
872d14d5141STomohiro Kusumi
873d14d5141STomohiro Kusumi /*
874f252c9b0SSascha Wildner * Get a standard format.
875f252c9b0SSascha Wildner */
876f252c9b0SSascha Wildner static int
getstdfmt(const char * fmt,struct bpb * bpb)877f252c9b0SSascha Wildner getstdfmt(const char *fmt, struct bpb *bpb)
878f252c9b0SSascha Wildner {
879f252c9b0SSascha Wildner u_int x, i;
880f252c9b0SSascha Wildner
881f252c9b0SSascha Wildner x = NELEM(stdfmt);
882f252c9b0SSascha Wildner for (i = 0; i < x && strcmp(fmt, stdfmt[i].name); i++);
883f252c9b0SSascha Wildner if (i == x) {
884f252c9b0SSascha Wildner warnx("%s: unknown standard format", fmt);
885f252c9b0SSascha Wildner return -1;
886f252c9b0SSascha Wildner }
887f252c9b0SSascha Wildner *bpb = stdfmt[i].bpb;
888f252c9b0SSascha Wildner return 0;
889f252c9b0SSascha Wildner }
890f252c9b0SSascha Wildner
891*c589a8b8STomohiro Kusumi static void
compute_geometry_from_file(int fd,const char * fname,struct disklabel32 * lp)892*c589a8b8STomohiro Kusumi compute_geometry_from_file(int fd, const char *fname, struct disklabel32 *lp)
893*c589a8b8STomohiro Kusumi {
894*c589a8b8STomohiro Kusumi struct stat st;
895*c589a8b8STomohiro Kusumi off_t ms;
896*c589a8b8STomohiro Kusumi
897*c589a8b8STomohiro Kusumi if (fstat(fd, &st))
898*c589a8b8STomohiro Kusumi err(1, "cannot get disk size");
899*c589a8b8STomohiro Kusumi if (!S_ISREG(st.st_mode))
900*c589a8b8STomohiro Kusumi errx(1, "%s is not a regular file", fname);
901*c589a8b8STomohiro Kusumi ms = st.st_size;
902*c589a8b8STomohiro Kusumi lp->d_secsize = 512;
903*c589a8b8STomohiro Kusumi lp->d_nsectors = 63;
904*c589a8b8STomohiro Kusumi lp->d_ntracks = 255;
905*c589a8b8STomohiro Kusumi lp->d_secperunit = ms / lp->d_secsize;
906*c589a8b8STomohiro Kusumi }
907*c589a8b8STomohiro Kusumi
908f252c9b0SSascha Wildner /*
909f252c9b0SSascha Wildner * Get disk slice, partition, and geometry information.
910f252c9b0SSascha Wildner */
911f252c9b0SSascha Wildner static int
getdiskinfo(int fd,const char * fname,const char * dtype,__unused int oflag,struct bpb * bpb)912f252c9b0SSascha Wildner getdiskinfo(int fd, const char *fname, const char *dtype, __unused int oflag,
913f252c9b0SSascha Wildner struct bpb *bpb)
914f252c9b0SSascha Wildner {
915f252c9b0SSascha Wildner struct disklabel32 *lp, dlp;
916*c589a8b8STomohiro Kusumi off_t hs = 0;
917*c589a8b8STomohiro Kusumi #ifndef MAKEFS
918*c589a8b8STomohiro Kusumi off_t ms;
919f252c9b0SSascha Wildner struct fd_type type;
920f252c9b0SSascha Wildner struct partinfo pi;
921f252c9b0SSascha Wildner
922f252c9b0SSascha Wildner lp = NULL;
923f252c9b0SSascha Wildner
924f252c9b0SSascha Wildner /* If the user specified a disk type, try to use that */
925f252c9b0SSascha Wildner if (dtype != NULL) {
926f252c9b0SSascha Wildner lp = getdiskbyname(dtype);
927f252c9b0SSascha Wildner }
928f252c9b0SSascha Wildner
929f252c9b0SSascha Wildner /* Maybe it's a floppy drive */
930f252c9b0SSascha Wildner if (lp == NULL) {
931f252c9b0SSascha Wildner if (ioctl(fd, DIOCGPART, &pi) == -1) {
932f252c9b0SSascha Wildner /* create a fake geometry for a file image */
933*c589a8b8STomohiro Kusumi compute_geometry_from_file(fd, fname, &dlp);
934f252c9b0SSascha Wildner lp = &dlp;
935f252c9b0SSascha Wildner } else if (ioctl(fd, FD_GTYPE, &type) != -1) {
936f252c9b0SSascha Wildner ms = pi.media_size;
937f252c9b0SSascha Wildner dlp.d_secsize = 128 << type.secsize;
938f252c9b0SSascha Wildner dlp.d_nsectors = type.sectrac;
939f252c9b0SSascha Wildner dlp.d_ntracks = type.heads;
940f252c9b0SSascha Wildner dlp.d_secperunit = ms / dlp.d_secsize;
941f252c9b0SSascha Wildner lp = &dlp;
942f252c9b0SSascha Wildner } else {
943f252c9b0SSascha Wildner ms = pi.media_size;
944f252c9b0SSascha Wildner }
945f252c9b0SSascha Wildner }
946f252c9b0SSascha Wildner
947f252c9b0SSascha Wildner /* Maybe it's a fixed drive */
948f252c9b0SSascha Wildner if (lp == NULL) {
949f252c9b0SSascha Wildner if (ioctl(fd, DIOCGPART, &pi) == - 1)
950f252c9b0SSascha Wildner err(1, "cannot get disk information");
951f252c9b0SSascha Wildner dlp.d_secsize = pi.media_blksize;
952f252c9b0SSascha Wildner dlp.d_nsectors = pi.d_secpertrack;
953f252c9b0SSascha Wildner dlp.d_ntracks = pi.d_nheads;
954f252c9b0SSascha Wildner if (bpb->bpbBytesPerSec)
955f252c9b0SSascha Wildner dlp.d_secsize = bpb->bpbBytesPerSec;
956f252c9b0SSascha Wildner
957f252c9b0SSascha Wildner dlp.d_secperunit = ms / dlp.d_secsize;
958f252c9b0SSascha Wildner
959f252c9b0SSascha Wildner hs = (ms / dlp.d_secsize) - dlp.d_secperunit;
960f252c9b0SSascha Wildner lp = &dlp;
961f252c9b0SSascha Wildner }
962*c589a8b8STomohiro Kusumi #else
963*c589a8b8STomohiro Kusumi (void)dtype;
964*c589a8b8STomohiro Kusumi /* In the makefs case we only support image files: */
965*c589a8b8STomohiro Kusumi compute_geometry_from_file(fd, fname, &dlp);
966*c589a8b8STomohiro Kusumi lp = &dlp;
967*c589a8b8STomohiro Kusumi #endif
968f252c9b0SSascha Wildner
969f252c9b0SSascha Wildner if (bpb->bpbBytesPerSec == 0) {
970f252c9b0SSascha Wildner if (ckgeom(fname, lp->d_secsize, "bytes/sector") == -1)
971f252c9b0SSascha Wildner return -1;
972f252c9b0SSascha Wildner bpb->bpbBytesPerSec = lp->d_secsize;
973f252c9b0SSascha Wildner }
974f252c9b0SSascha Wildner if (bpb->bpbSecPerTrack == 0) {
975f252c9b0SSascha Wildner if (ckgeom(fname, lp->d_nsectors, "sectors/track") == -1)
976f252c9b0SSascha Wildner return -1;
977f252c9b0SSascha Wildner bpb->bpbSecPerTrack = lp->d_nsectors;
978f252c9b0SSascha Wildner }
979f252c9b0SSascha Wildner if (bpb->bpbHeads == 0) {
980f252c9b0SSascha Wildner if (ckgeom(fname, lp->d_ntracks, "drive heads") == -1)
981f252c9b0SSascha Wildner return -1;
982f252c9b0SSascha Wildner bpb->bpbHeads = lp->d_ntracks;
983f252c9b0SSascha Wildner }
984f252c9b0SSascha Wildner if (bpb->bpbHugeSectors == 0)
985f252c9b0SSascha Wildner bpb->bpbHugeSectors = lp->d_secperunit;
986f252c9b0SSascha Wildner if (bpb->bpbHiddenSecs == 0)
987f252c9b0SSascha Wildner bpb->bpbHiddenSecs = hs;
988f252c9b0SSascha Wildner return 0;
989f252c9b0SSascha Wildner }
990f252c9b0SSascha Wildner
991f252c9b0SSascha Wildner /*
992f252c9b0SSascha Wildner * Print out BPB values.
993f252c9b0SSascha Wildner */
994f252c9b0SSascha Wildner static void
print_bpb(struct bpb * bpb)995f252c9b0SSascha Wildner print_bpb(struct bpb *bpb)
996f252c9b0SSascha Wildner {
997f252c9b0SSascha Wildner printf("BytesPerSec=%u SecPerClust=%u ResSectors=%u FATs=%u",
998f252c9b0SSascha Wildner bpb->bpbBytesPerSec, bpb->bpbSecPerClust, bpb->bpbResSectors,
999f252c9b0SSascha Wildner bpb->bpbFATs);
1000f252c9b0SSascha Wildner if (bpb->bpbRootDirEnts)
1001f252c9b0SSascha Wildner printf(" RootDirEnts=%u", bpb->bpbRootDirEnts);
1002f252c9b0SSascha Wildner if (bpb->bpbSectors)
1003f252c9b0SSascha Wildner printf(" Sectors=%u", bpb->bpbSectors);
1004f252c9b0SSascha Wildner printf(" Media=%#x", bpb->bpbMedia);
1005f252c9b0SSascha Wildner if (bpb->bpbFATsecs)
1006f252c9b0SSascha Wildner printf(" FATsecs=%u", bpb->bpbFATsecs);
1007f252c9b0SSascha Wildner printf(" SecPerTrack=%u Heads=%u HiddenSecs=%u", bpb->bpbSecPerTrack,
1008f252c9b0SSascha Wildner bpb->bpbHeads, bpb->bpbHiddenSecs);
1009f252c9b0SSascha Wildner if (bpb->bpbHugeSectors)
1010f252c9b0SSascha Wildner printf(" HugeSectors=%u", bpb->bpbHugeSectors);
1011f252c9b0SSascha Wildner if (!bpb->bpbFATsecs) {
1012f252c9b0SSascha Wildner printf(" FATsecs=%u RootCluster=%u", bpb->bpbBigFATsecs,
1013f252c9b0SSascha Wildner bpb->bpbRootClust);
1014f252c9b0SSascha Wildner printf(" FSInfo=");
1015f252c9b0SSascha Wildner printf(bpb->bpbFSInfo == MAXU16 ? "%#x" : "%u", bpb->bpbFSInfo);
1016f252c9b0SSascha Wildner printf(" Backup=");
1017f252c9b0SSascha Wildner printf(bpb->bpbBackup == MAXU16 ? "%#x" : "%u", bpb->bpbBackup);
1018f252c9b0SSascha Wildner }
1019f252c9b0SSascha Wildner printf("\n");
1020f252c9b0SSascha Wildner }
1021f252c9b0SSascha Wildner
1022f252c9b0SSascha Wildner /*
1023f252c9b0SSascha Wildner * Check a disk geometry value.
1024f252c9b0SSascha Wildner */
1025f252c9b0SSascha Wildner static int
ckgeom(const char * fname,u_int val,const char * msg)1026f252c9b0SSascha Wildner ckgeom(const char *fname, u_int val, const char *msg)
1027f252c9b0SSascha Wildner {
1028f252c9b0SSascha Wildner if (!val) {
1029f252c9b0SSascha Wildner warnx("%s: no default %s", fname, msg);
1030f252c9b0SSascha Wildner return -1;
1031f252c9b0SSascha Wildner }
1032f252c9b0SSascha Wildner if (val > MAXU16) {
1033f252c9b0SSascha Wildner warnx("%s: illegal %s %d", fname, msg, val);
1034f252c9b0SSascha Wildner return -1;
1035f252c9b0SSascha Wildner }
1036f252c9b0SSascha Wildner return 0;
1037f252c9b0SSascha Wildner }
1038f252c9b0SSascha Wildner
1039f252c9b0SSascha Wildner /*
1040f252c9b0SSascha Wildner * Check a volume label.
1041f252c9b0SSascha Wildner */
1042f252c9b0SSascha Wildner static int
oklabel(const char * src)1043f252c9b0SSascha Wildner oklabel(const char *src)
1044f252c9b0SSascha Wildner {
1045f252c9b0SSascha Wildner int c, i;
1046f252c9b0SSascha Wildner
1047f252c9b0SSascha Wildner for (i = 0; i <= 11; i++) {
1048f252c9b0SSascha Wildner c = (u_char)*src++;
1049f252c9b0SSascha Wildner if (c < ' ' + !i || strchr("\"*+,./:;<=>?[\\]|", c))
1050f252c9b0SSascha Wildner break;
1051f252c9b0SSascha Wildner }
1052f252c9b0SSascha Wildner return i && !c;
1053f252c9b0SSascha Wildner }
1054f252c9b0SSascha Wildner
1055f252c9b0SSascha Wildner /*
1056f252c9b0SSascha Wildner * Make a volume label.
1057f252c9b0SSascha Wildner */
1058f252c9b0SSascha Wildner static void
mklabel(uint8_t * dest,const char * src)1059149331c9STomohiro Kusumi mklabel(uint8_t *dest, const char *src)
1060f252c9b0SSascha Wildner {
1061f252c9b0SSascha Wildner int c, i;
1062f252c9b0SSascha Wildner
1063f252c9b0SSascha Wildner for (i = 0; i < 11; i++) {
1064f252c9b0SSascha Wildner c = *src ? toupper(*src++) : ' ';
1065f252c9b0SSascha Wildner *dest++ = !i && c == '\xe5' ? 5 : c;
1066f252c9b0SSascha Wildner }
1067f252c9b0SSascha Wildner }
1068f252c9b0SSascha Wildner
1069f252c9b0SSascha Wildner /*
1070f252c9b0SSascha Wildner * Copy string, padding with spaces.
1071f252c9b0SSascha Wildner */
1072f252c9b0SSascha Wildner static void
setstr(uint8_t * dest,const char * src,size_t len)1073149331c9STomohiro Kusumi setstr(uint8_t *dest, const char *src, size_t len)
1074f252c9b0SSascha Wildner {
1075f252c9b0SSascha Wildner while (len--)
1076f252c9b0SSascha Wildner *dest++ = *src ? *src++ : ' ';
1077f252c9b0SSascha Wildner }
1078f252c9b0SSascha Wildner
1079f252c9b0SSascha Wildner static void
infohandler(int sig __unused)1080f252c9b0SSascha Wildner infohandler(int sig __unused)
1081f252c9b0SSascha Wildner {
1082f252c9b0SSascha Wildner
1083f252c9b0SSascha Wildner got_siginfo = 1;
1084f252c9b0SSascha Wildner }
1085