xref: /aosp_15_r20/external/newfs_msdos/newfs_msdos.c (revision d656534b87bd8f59341392a2dadc9aa101e4b018)
1*d656534bSElliott Hughes /*-
2*d656534bSElliott Hughes  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3*d656534bSElliott Hughes  *
4*d656534bSElliott Hughes  * Copyright (c) 1998 Robert Nordier
5*d656534bSElliott Hughes  * All rights reserved.
6*d656534bSElliott Hughes  *
7*d656534bSElliott Hughes  * Redistribution and use in source and binary forms, with or without
8*d656534bSElliott Hughes  * modification, are permitted provided that the following conditions
9*d656534bSElliott Hughes  * are met:
10*d656534bSElliott Hughes  * 1. Redistributions of source code must retain the above copyright
11*d656534bSElliott Hughes  *    notice, this list of conditions and the following disclaimer.
12*d656534bSElliott Hughes  * 2. Redistributions in binary form must reproduce the above copyright
13*d656534bSElliott Hughes  *    notice, this list of conditions and the following disclaimer in
14*d656534bSElliott Hughes  *    the documentation and/or other materials provided with the
15*d656534bSElliott Hughes  *    distribution.
16*d656534bSElliott Hughes  *
17*d656534bSElliott Hughes  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
18*d656534bSElliott Hughes  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19*d656534bSElliott Hughes  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20*d656534bSElliott Hughes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY
21*d656534bSElliott Hughes  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22*d656534bSElliott Hughes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23*d656534bSElliott Hughes  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24*d656534bSElliott Hughes  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25*d656534bSElliott Hughes  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26*d656534bSElliott Hughes  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27*d656534bSElliott Hughes  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*d656534bSElliott Hughes  */
29*d656534bSElliott Hughes 
30*d656534bSElliott Hughes #ifndef lint
31*d656534bSElliott Hughes static const char rcsid[] =
32*d656534bSElliott Hughes   "$FreeBSD$";
33*d656534bSElliott Hughes #endif /* not lint */
34*d656534bSElliott Hughes 
35*d656534bSElliott Hughes #include <sys/param.h>
36*d656534bSElliott Hughes #include <sys/stat.h>
37*d656534bSElliott Hughes #include <err.h>
38*d656534bSElliott Hughes #include <errno.h>
39*d656534bSElliott Hughes #include <paths.h>
40*d656534bSElliott Hughes #include <stdio.h>
41*d656534bSElliott Hughes #include <stdlib.h>
42*d656534bSElliott Hughes #include <string.h>
43*d656534bSElliott Hughes #include <unistd.h>
44*d656534bSElliott Hughes 
45*d656534bSElliott Hughes #include "mkfs_msdos.h"
46*d656534bSElliott Hughes 
47*d656534bSElliott Hughes #define	argto1(arg, lo, msg)  argtou(arg, lo, 0xff, msg)
48*d656534bSElliott Hughes #define	argto2(arg, lo, msg)  argtou(arg, lo, 0xffff, msg)
49*d656534bSElliott Hughes #define	argto4(arg, lo, msg)  argtou(arg, lo, 0xffffffff, msg)
50*d656534bSElliott Hughes #define	argtox(arg, lo, msg)  argtou(arg, lo, UINT_MAX, msg)
51*d656534bSElliott Hughes 
52*d656534bSElliott Hughes static u_int argtou(const char *, u_int, u_int, const char *);
53*d656534bSElliott Hughes static off_t argtooff(const char *, const char *);
54*d656534bSElliott Hughes static void usage(void);
55*d656534bSElliott Hughes 
56*d656534bSElliott Hughes static time_t
get_tstamp(const char * b)57*d656534bSElliott Hughes get_tstamp(const char *b)
58*d656534bSElliott Hughes {
59*d656534bSElliott Hughes     struct stat st;
60*d656534bSElliott Hughes     char *eb;
61*d656534bSElliott Hughes     long long l;
62*d656534bSElliott Hughes 
63*d656534bSElliott Hughes     if (stat(b, &st) != -1)
64*d656534bSElliott Hughes         return (time_t)st.st_mtime;
65*d656534bSElliott Hughes 
66*d656534bSElliott Hughes     errno = 0;
67*d656534bSElliott Hughes     l = strtoll(b, &eb, 0);
68*d656534bSElliott Hughes     if (b == eb || *eb || errno)
69*d656534bSElliott Hughes         errx(EXIT_FAILURE, "Can't parse timestamp '%s'", b);
70*d656534bSElliott Hughes     return (time_t)l;
71*d656534bSElliott Hughes }
72*d656534bSElliott Hughes 
73*d656534bSElliott Hughes /*
74*d656534bSElliott Hughes  * Construct a FAT12, FAT16, or FAT32 file system.
75*d656534bSElliott Hughes  */
76*d656534bSElliott Hughes int
main(int argc,char * argv[])77*d656534bSElliott Hughes main(int argc, char *argv[])
78*d656534bSElliott Hughes {
79*d656534bSElliott Hughes     static const char opts[] = "@:NAB:C:F:I:L:O:S:a:b:c:e:f:h:i:k:m:n:o:r:s:T:u:";
80*d656534bSElliott Hughes     struct msdos_options o;
81*d656534bSElliott Hughes     const char *fname, *dtype;
82*d656534bSElliott Hughes     char buf[MAXPATHLEN];
83*d656534bSElliott Hughes     int ch;
84*d656534bSElliott Hughes 
85*d656534bSElliott Hughes     memset(&o, 0, sizeof(o));
86*d656534bSElliott Hughes 
87*d656534bSElliott Hughes     while ((ch = getopt(argc, argv, opts)) != -1)
88*d656534bSElliott Hughes 	switch (ch) {
89*d656534bSElliott Hughes 	case '@':
90*d656534bSElliott Hughes 	    o.offset = argtooff(optarg, "offset");
91*d656534bSElliott Hughes 	    break;
92*d656534bSElliott Hughes 	case 'N':
93*d656534bSElliott Hughes 	    o.no_create = 1;
94*d656534bSElliott Hughes 	    break;
95*d656534bSElliott Hughes 	case 'A':
96*d656534bSElliott Hughes 	    o.align = true;
97*d656534bSElliott Hughes 	    break;
98*d656534bSElliott Hughes 	case 'B':
99*d656534bSElliott Hughes 	    o.bootstrap = optarg;
100*d656534bSElliott Hughes 	    break;
101*d656534bSElliott Hughes 	case 'C':
102*d656534bSElliott Hughes 	    o.create_size = argtooff(optarg, "create size");
103*d656534bSElliott Hughes 	    break;
104*d656534bSElliott Hughes 	case 'F':
105*d656534bSElliott Hughes 	    if (strcmp(optarg, "12") &&
106*d656534bSElliott Hughes 		strcmp(optarg, "16") &&
107*d656534bSElliott Hughes 		strcmp(optarg, "32"))
108*d656534bSElliott Hughes 		errx(1, "%s: bad FAT type", optarg);
109*d656534bSElliott Hughes 	    o.fat_type = atoi(optarg);
110*d656534bSElliott Hughes 	    break;
111*d656534bSElliott Hughes 	case 'I':
112*d656534bSElliott Hughes 	    o.volume_id = argto4(optarg, 0, "volume ID");
113*d656534bSElliott Hughes 	    o.volume_id_set = 1;
114*d656534bSElliott Hughes 	    break;
115*d656534bSElliott Hughes 	case 'L':
116*d656534bSElliott Hughes 	    o.volume_label = optarg;
117*d656534bSElliott Hughes 	    break;
118*d656534bSElliott Hughes 	case 'O':
119*d656534bSElliott Hughes 	    o.OEM_string = optarg;
120*d656534bSElliott Hughes 	    break;
121*d656534bSElliott Hughes 	case 'S':
122*d656534bSElliott Hughes 	    o.bytes_per_sector = argto2(optarg, 1, "bytes/sector");
123*d656534bSElliott Hughes 	    break;
124*d656534bSElliott Hughes 	case 'a':
125*d656534bSElliott Hughes 	    o.sectors_per_fat = argto4(optarg, 1, "sectors/FAT");
126*d656534bSElliott Hughes 	    break;
127*d656534bSElliott Hughes 	case 'b':
128*d656534bSElliott Hughes 	    o.block_size = argtox(optarg, 1, "block size");
129*d656534bSElliott Hughes 	    o.sectors_per_cluster = 0;
130*d656534bSElliott Hughes 	    break;
131*d656534bSElliott Hughes 	case 'c':
132*d656534bSElliott Hughes 	    o.sectors_per_cluster = argto1(optarg, 1, "sectors/cluster");
133*d656534bSElliott Hughes 	    o.block_size = 0;
134*d656534bSElliott Hughes 	    break;
135*d656534bSElliott Hughes 	case 'e':
136*d656534bSElliott Hughes 	    o.directory_entries = argto2(optarg, 1, "directory entries");
137*d656534bSElliott Hughes 	    break;
138*d656534bSElliott Hughes 	case 'f':
139*d656534bSElliott Hughes 	    o.floppy = optarg;
140*d656534bSElliott Hughes 	    break;
141*d656534bSElliott Hughes 	case 'h':
142*d656534bSElliott Hughes 	    o.drive_heads = argto2(optarg, 1, "drive heads");
143*d656534bSElliott Hughes 	    break;
144*d656534bSElliott Hughes 	case 'i':
145*d656534bSElliott Hughes 	    o.info_sector = argto2(optarg, 1, "info sector");
146*d656534bSElliott Hughes 	    break;
147*d656534bSElliott Hughes 	case 'k':
148*d656534bSElliott Hughes 	    o.backup_sector = argto2(optarg, 1, "backup sector");
149*d656534bSElliott Hughes 	    break;
150*d656534bSElliott Hughes 	case 'm':
151*d656534bSElliott Hughes 	    o.media_descriptor = argto1(optarg, 0, "media descriptor");
152*d656534bSElliott Hughes 	    o.media_descriptor_set = 1;
153*d656534bSElliott Hughes 	    break;
154*d656534bSElliott Hughes 	case 'n':
155*d656534bSElliott Hughes 	    o.num_FAT = argto1(optarg, 1, "number of FATs");
156*d656534bSElliott Hughes 	    break;
157*d656534bSElliott Hughes 	case 'o':
158*d656534bSElliott Hughes 	    o.hidden_sectors = argto4(optarg, 0, "hidden sectors");
159*d656534bSElliott Hughes 	    o.hidden_sectors_set = 1;
160*d656534bSElliott Hughes 	    break;
161*d656534bSElliott Hughes 	case 'r':
162*d656534bSElliott Hughes 	    o.reserved_sectors = argto2(optarg, 1, "reserved sectors");
163*d656534bSElliott Hughes 	    break;
164*d656534bSElliott Hughes 	case 's':
165*d656534bSElliott Hughes 	    o.size = argto4(optarg, 1, "file system size");
166*d656534bSElliott Hughes 	    break;
167*d656534bSElliott Hughes 	case 'T':
168*d656534bSElliott Hughes 	    o.timestamp_set = 1;
169*d656534bSElliott Hughes 	    o.timestamp = get_tstamp(optarg);
170*d656534bSElliott Hughes 	    break;
171*d656534bSElliott Hughes 	case 'u':
172*d656534bSElliott Hughes 	    o.sectors_per_track = argto2(optarg, 1, "sectors/track");
173*d656534bSElliott Hughes 	    break;
174*d656534bSElliott Hughes 	default:
175*d656534bSElliott Hughes 	    usage();
176*d656534bSElliott Hughes 	}
177*d656534bSElliott Hughes     argc -= optind;
178*d656534bSElliott Hughes     argv += optind;
179*d656534bSElliott Hughes     if (argc < 1 || argc > 2)
180*d656534bSElliott Hughes 	usage();
181*d656534bSElliott Hughes     if (o.align) {
182*d656534bSElliott Hughes 	if (o.reserved_sectors)
183*d656534bSElliott Hughes 	    errx(1, "align (-A) is incompatible with -r");
184*d656534bSElliott Hughes     }
185*d656534bSElliott Hughes     fname = *argv++;
186*d656534bSElliott Hughes     if (!o.create_size && !strchr(fname, '/')) {
187*d656534bSElliott Hughes 	snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname);
188*d656534bSElliott Hughes 	fname = buf;
189*d656534bSElliott Hughes     }
190*d656534bSElliott Hughes     dtype = *argv;
191*d656534bSElliott Hughes     exit(!!mkfs_msdos(fname, dtype, &o));
192*d656534bSElliott Hughes }
193*d656534bSElliott Hughes 
194*d656534bSElliott Hughes /*
195*d656534bSElliott Hughes  * Convert and check a numeric option argument.
196*d656534bSElliott Hughes  */
197*d656534bSElliott Hughes static u_int
argtou(const char * arg,u_int lo,u_int hi,const char * msg)198*d656534bSElliott Hughes argtou(const char *arg, u_int lo, u_int hi, const char *msg)
199*d656534bSElliott Hughes {
200*d656534bSElliott Hughes     char *s;
201*d656534bSElliott Hughes     u_long x;
202*d656534bSElliott Hughes 
203*d656534bSElliott Hughes     errno = 0;
204*d656534bSElliott Hughes     x = strtoul(arg, &s, 0);
205*d656534bSElliott Hughes     if (errno || !*arg || *s || x < lo || x > hi)
206*d656534bSElliott Hughes 	errx(1, "%s: bad %s", arg, msg);
207*d656534bSElliott Hughes     return x;
208*d656534bSElliott Hughes }
209*d656534bSElliott Hughes 
210*d656534bSElliott Hughes /*
211*d656534bSElliott Hughes  * Same for off_t, with optional skmgpP suffix
212*d656534bSElliott Hughes  */
213*d656534bSElliott Hughes static off_t
argtooff(const char * arg,const char * msg)214*d656534bSElliott Hughes argtooff(const char *arg, const char *msg)
215*d656534bSElliott Hughes {
216*d656534bSElliott Hughes     char *s;
217*d656534bSElliott Hughes     off_t x;
218*d656534bSElliott Hughes 
219*d656534bSElliott Hughes     errno = 0;
220*d656534bSElliott Hughes     x = strtoll(arg, &s, 0);
221*d656534bSElliott Hughes     /* allow at most one extra char */
222*d656534bSElliott Hughes     if (errno || x < 0 || (s[0] && s[1]) )
223*d656534bSElliott Hughes 	errx(1, "%s: bad %s", arg, msg);
224*d656534bSElliott Hughes     if (*s) {	/* the extra char is the multiplier */
225*d656534bSElliott Hughes 	switch (*s) {
226*d656534bSElliott Hughes 	default:
227*d656534bSElliott Hughes 	    errx(1, "%s: bad %s", arg, msg);
228*d656534bSElliott Hughes 	    /* notreached */
229*d656534bSElliott Hughes 
230*d656534bSElliott Hughes 	case 's':		/* sector */
231*d656534bSElliott Hughes 	case 'S':
232*d656534bSElliott Hughes 	    x <<= 9;		/* times 512 */
233*d656534bSElliott Hughes 	    break;
234*d656534bSElliott Hughes 
235*d656534bSElliott Hughes 	case 'k':		/* kilobyte */
236*d656534bSElliott Hughes 	case 'K':
237*d656534bSElliott Hughes 	    x <<= 10;		/* times 1024 */
238*d656534bSElliott Hughes 	    break;
239*d656534bSElliott Hughes 
240*d656534bSElliott Hughes 	case 'm':		/* megabyte */
241*d656534bSElliott Hughes 	case 'M':
242*d656534bSElliott Hughes 	    x <<= 20;		/* times 1024*1024 */
243*d656534bSElliott Hughes 	    break;
244*d656534bSElliott Hughes 
245*d656534bSElliott Hughes 	case 'g':		/* gigabyte */
246*d656534bSElliott Hughes 	case 'G':
247*d656534bSElliott Hughes 	    x <<= 30;		/* times 1024*1024*1024 */
248*d656534bSElliott Hughes 	    break;
249*d656534bSElliott Hughes 
250*d656534bSElliott Hughes 	case 'p':		/* partition start */
251*d656534bSElliott Hughes 	case 'P':
252*d656534bSElliott Hughes 	case 'l':		/* partition length */
253*d656534bSElliott Hughes 	case 'L':
254*d656534bSElliott Hughes 	    errx(1, "%s: not supported yet %s", arg, msg);
255*d656534bSElliott Hughes 	    /* notreached */
256*d656534bSElliott Hughes 	}
257*d656534bSElliott Hughes     }
258*d656534bSElliott Hughes     return x;
259*d656534bSElliott Hughes }
260*d656534bSElliott Hughes 
261*d656534bSElliott Hughes /*
262*d656534bSElliott Hughes  * Print usage message.
263*d656534bSElliott Hughes  */
264*d656534bSElliott Hughes static void
usage(void)265*d656534bSElliott Hughes usage(void)
266*d656534bSElliott Hughes {
267*d656534bSElliott Hughes     fprintf(stderr,
268*d656534bSElliott Hughes 	    "usage: %s [ -options ] special [disktype]\n", getprogname());
269*d656534bSElliott Hughes     fprintf(stderr, "where the options are:\n");
270*d656534bSElliott Hughes static struct {
271*d656534bSElliott Hughes     char o;
272*d656534bSElliott Hughes     const char *h;
273*d656534bSElliott Hughes } opts[] = {
274*d656534bSElliott Hughes #define AOPT(_opt, _type, _name, _min, _desc) { _opt, _desc },
275*d656534bSElliott Hughes ALLOPTS
276*d656534bSElliott Hughes #undef AOPT
277*d656534bSElliott Hughes     };
278*d656534bSElliott Hughes     for (size_t i = 0; i < nitems(opts); i++)
279*d656534bSElliott Hughes 	fprintf(stderr, "\t-%c %s\n", opts[i].o, opts[i].h);
280*d656534bSElliott Hughes     exit(1);
281*d656534bSElliott Hughes }
282