xref: /netbsd-src/sbin/newfs_msdos/newfs_msdos.c (revision 285cf5690532d819b210a94aedd8823cfa7d042c)
1*285cf569Schristos /*	$NetBSD: newfs_msdos.c,v 1.45 2017/02/16 22:42:25 christos Exp $	*/
2d5fff03eSchristos 
3d5fff03eSchristos /*
4de3ce7e7Schristos  * Copyright (c) 1998 Robert Nordier
5d5fff03eSchristos  * All rights reserved.
6d5fff03eSchristos  *
7d5fff03eSchristos  * Redistribution and use in source and binary forms, with or without
8d5fff03eSchristos  * modification, are permitted provided that the following conditions
9d5fff03eSchristos  * are met:
10d5fff03eSchristos  * 1. Redistributions of source code must retain the above copyright
11d5fff03eSchristos  *    notice, this list of conditions and the following disclaimer.
12d5fff03eSchristos  * 2. Redistributions in binary form must reproduce the above copyright
13de3ce7e7Schristos  *    notice, this list of conditions and the following disclaimer in
14de3ce7e7Schristos  *    the documentation and/or other materials provided with the
15de3ce7e7Schristos  *    distribution.
16d5fff03eSchristos  *
17de3ce7e7Schristos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS
18de3ce7e7Schristos  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19de3ce7e7Schristos  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20de3ce7e7Schristos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY
21de3ce7e7Schristos  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22de3ce7e7Schristos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
23de3ce7e7Schristos  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24de3ce7e7Schristos  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
25de3ce7e7Schristos  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26de3ce7e7Schristos  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
27de3ce7e7Schristos  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28d5fff03eSchristos  */
298dee301bSlukem 
308dee301bSlukem #include <sys/cdefs.h>
31d5fff03eSchristos #ifndef lint
32de3ce7e7Schristos #if 0
33de3ce7e7Schristos static const char rcsid[] =
34de3ce7e7Schristos   "$FreeBSD: src/sbin/newfs_msdos/newfs_msdos.c,v 1.15 2000/10/10 01:49:37 wollman Exp $";
35de3ce7e7Schristos #else
36*285cf569Schristos __RCSID("$NetBSD: newfs_msdos.c,v 1.45 2017/02/16 22:42:25 christos Exp $");
37de3ce7e7Schristos #endif
38d5fff03eSchristos #endif /* not lint */
39d5fff03eSchristos 
40d5fff03eSchristos #include <sys/param.h>
4129723468Schristos #include <sys/stat.h>
42de3ce7e7Schristos #include <stdio.h>
43de3ce7e7Schristos #include <string.h>
44aed35c48Schristos #include <err.h>
45aed35c48Schristos #include <stdlib.h>
46de3ce7e7Schristos #include <unistd.h>
47aed35c48Schristos #include <paths.h>
48aed35c48Schristos #include <errno.h>
4929723468Schristos #include <util.h>
50b6f6f7a7Schristos 
51aed35c48Schristos #include "mkfs_msdos.h"
52de3ce7e7Schristos 
53de3ce7e7Schristos #define argto1(arg, lo, msg)  argtou(arg, lo, 0xff, msg)
54de3ce7e7Schristos #define argto2(arg, lo, msg)  argtou(arg, lo, 0xffff, msg)
55de3ce7e7Schristos #define argto4(arg, lo, msg)  argtou(arg, lo, 0xffffffff, msg)
56de3ce7e7Schristos #define argtox(arg, lo, msg)  argtou(arg, lo, UINT_MAX, msg)
57de3ce7e7Schristos 
58aed35c48Schristos __dead static void usage(void);
59de3ce7e7Schristos static u_int argtou(const char *, u_int, u_int, const char *);
6032852eceSpooka static off_t argtooff(const char *, const char *);
61d5fff03eSchristos 
6229723468Schristos static time_t
get_tstamp(const char * b)6329723468Schristos get_tstamp(const char *b)
6429723468Schristos {
6529723468Schristos 	struct stat st;
6629723468Schristos 	char *eb;
6729723468Schristos 	long long l;
6829723468Schristos #ifndef HAVE_NBTOOL_CONFIG_H
6929723468Schristos 	time_t when;
7029723468Schristos #endif
7129723468Schristos 
7229723468Schristos 	if (stat(b, &st) != -1)
7329723468Schristos 		return (time_t)st.st_mtime;
7429723468Schristos 
7529723468Schristos #ifndef HAVE_NBTOOL_CONFIG_H
7629723468Schristos 	errno = 0;
7729723468Schristos 	if ((when = parsedate(b, NULL, NULL)) != -1 || errno == 0)
7829723468Schristos 		return when;
7929723468Schristos #endif
8029723468Schristos 	errno = 0;
8129723468Schristos 	l = strtoll(b, &eb, 0);
8229723468Schristos 	if (b == eb || *eb || errno)
8329723468Schristos 		errx(EXIT_FAILURE, "Can't parse timestamp `%s'", b);
8429723468Schristos 	return (time_t)l;
8529723468Schristos }
8629723468Schristos 
87d5fff03eSchristos /*
88de3ce7e7Schristos  * Construct a FAT12, FAT16, or FAT32 file system.
89d5fff03eSchristos  */
90d5fff03eSchristos int
main(int argc,char * argv[])91de3ce7e7Schristos main(int argc, char *argv[])
92d5fff03eSchristos {
9329723468Schristos     static const char opts[] = "@:NB:C:F:I:L:O:S:a:b:c:e:f:h:i:k:m:n:o:r:s:T:u:";
94aed35c48Schristos     struct msdos_options o;
95aed35c48Schristos     char *fname, *dtype;
96de3ce7e7Schristos     char buf[MAXPATHLEN];
97aed35c48Schristos     int ch;
98aed35c48Schristos 
99aed35c48Schristos     memset(&o, 0, sizeof(o));
100d5fff03eSchristos 
101de3ce7e7Schristos     while ((ch = getopt(argc, argv, opts)) != -1)
102de3ce7e7Schristos 	switch (ch) {
10332852eceSpooka 	case '@':
104aed35c48Schristos 	    o.offset = argtooff(optarg, "offset");
10532852eceSpooka 	    break;
106de3ce7e7Schristos 	case 'N':
107aed35c48Schristos 	    o.no_create = 1;
108d5fff03eSchristos 	    break;
109de3ce7e7Schristos 	case 'B':
110aed35c48Schristos 	    o.bootstrap = optarg;
111de3ce7e7Schristos 	    break;
11232852eceSpooka 	case 'C':
113aed35c48Schristos 	    o.create_size = argtooff(optarg, "create size");
11432852eceSpooka 	    break;
115de3ce7e7Schristos 	case 'F':
116aed35c48Schristos 	    o.fat_type = atoi(optarg);
117de3ce7e7Schristos 	    break;
118de3ce7e7Schristos 	case 'I':
119aed35c48Schristos 	    o.volume_id = argto4(optarg, 0, "volume ID");
120aed35c48Schristos 	    o.volume_id_set = 1;
121de3ce7e7Schristos 	    break;
122d5fff03eSchristos 	case 'L':
123aed35c48Schristos 	    o.volume_label = optarg;
124d5fff03eSchristos 	    break;
125de3ce7e7Schristos 	case 'O':
126aed35c48Schristos 	    o.OEM_string = optarg;
127de3ce7e7Schristos 	    break;
128de3ce7e7Schristos 	case 'S':
129aed35c48Schristos 	    o.bytes_per_sector = argto2(optarg, 1, "bytes/sector");
130de3ce7e7Schristos 	    break;
131de3ce7e7Schristos 	case 'a':
132aed35c48Schristos 	    o.sectors_per_fat = argto4(optarg, 1, "sectors/FAT");
133de3ce7e7Schristos 	    break;
134de3ce7e7Schristos 	case 'b':
135aed35c48Schristos 	    o.block_size = argtox(optarg, 1, "block size");
136de3ce7e7Schristos 	    break;
137de3ce7e7Schristos 	case 'c':
138aed35c48Schristos 	    o.sectors_per_cluster = argto1(optarg, 1, "sectors/cluster");
139de3ce7e7Schristos 	    break;
140de3ce7e7Schristos 	case 'e':
141aed35c48Schristos 	    o.directory_entries = argto2(optarg, 1, "directory entries");
142de3ce7e7Schristos 	    break;
143de3ce7e7Schristos 	case 'f':
144aed35c48Schristos 	    o.floppy = optarg;
145de3ce7e7Schristos 	    break;
146de3ce7e7Schristos 	case 'h':
147aed35c48Schristos 	    o.drive_heads = argto2(optarg, 1, "drive heads");
148de3ce7e7Schristos 	    break;
149de3ce7e7Schristos 	case 'i':
150aed35c48Schristos 	    o.info_sector = argto2(optarg, 1, "info sector");
151de3ce7e7Schristos 	    break;
152de3ce7e7Schristos 	case 'k':
153aed35c48Schristos 	    o.backup_sector = argto2(optarg, 1, "backup sector");
154de3ce7e7Schristos 	    break;
155de3ce7e7Schristos 	case 'm':
156aed35c48Schristos 	    o.media_descriptor = argto1(optarg, 0, "media descriptor");
157aed35c48Schristos 	    o.media_descriptor_set = 1;
158de3ce7e7Schristos 	    break;
159de3ce7e7Schristos 	case 'n':
160aed35c48Schristos 	    o.num_FAT = argto1(optarg, 1, "number of FATs");
161de3ce7e7Schristos 	    break;
162de3ce7e7Schristos 	case 'o':
163aed35c48Schristos 	    o.hidden_sectors = argto4(optarg, 0, "hidden sectors");
164aed35c48Schristos 	    o.hidden_sectors_set = 1;
165de3ce7e7Schristos 	    break;
166de3ce7e7Schristos 	case 'r':
167aed35c48Schristos 	    o.reserved_sectors = argto2(optarg, 1, "reserved sectors");
168de3ce7e7Schristos 	    break;
169de3ce7e7Schristos 	case 's':
170aed35c48Schristos 	    o.size = argto4(optarg, 1, "file system size");
171de3ce7e7Schristos 	    break;
17229723468Schristos 	case 'T':
173*285cf569Schristos 	    o.timestamp_set = 1;
17429723468Schristos 	    o.timestamp = get_tstamp(optarg);
17529723468Schristos 	    break;
176de3ce7e7Schristos 	case 'u':
177aed35c48Schristos 	    o.sectors_per_track = argto2(optarg, 1, "sectors/track");
178de3ce7e7Schristos 	    break;
179d5fff03eSchristos 	default:
180d5fff03eSchristos 	    usage();
181d5fff03eSchristos 	}
182d5fff03eSchristos     argc -= optind;
183d5fff03eSchristos     argv += optind;
184de3ce7e7Schristos     if (argc < 1 || argc > 2)
185d5fff03eSchristos 	usage();
186de3ce7e7Schristos     fname = *argv++;
187aed35c48Schristos     if (!strchr(fname, '/') && !o.create_size) {
188db8658a3Spooka 	snprintf(buf, sizeof(buf), "%sr%s", _PATH_DEV, fname);
189de3ce7e7Schristos 	if (!(fname = strdup(buf)))
190de3ce7e7Schristos 	    err(1, NULL);
191de3ce7e7Schristos     }
192de3ce7e7Schristos     dtype = *argv;
193aed35c48Schristos     return mkfs_msdos(fname, dtype, &o);
194de3ce7e7Schristos }
195de3ce7e7Schristos 
196de3ce7e7Schristos /*
197de3ce7e7Schristos  * Convert and check a numeric option argument.
198de3ce7e7Schristos  */
199de3ce7e7Schristos static u_int
argtou(const char * arg,u_int lo,u_int hi,const char * msg)200de3ce7e7Schristos argtou(const char *arg, u_int lo, u_int hi, const char *msg)
201de3ce7e7Schristos {
202b46e0d15Sabs     off_t x;
203de3ce7e7Schristos 
204de3ce7e7Schristos     errno = 0;
205b46e0d15Sabs     x = argtooff(arg, msg);
206b46e0d15Sabs     if (x < lo || x > hi)
207de3ce7e7Schristos 	errx(1, "%s: bad %s", arg, msg);
208b46e0d15Sabs     return (u_int)x;
209de3ce7e7Schristos }
210de3ce7e7Schristos 
211de3ce7e7Schristos /*
21232852eceSpooka  * Same for off_t, with optional skmgpP suffix
21332852eceSpooka  */
21432852eceSpooka static off_t
argtooff(const char * arg,const char * msg)21532852eceSpooka argtooff(const char *arg, const char *msg)
21632852eceSpooka {
21732852eceSpooka     char *s;
21832852eceSpooka     off_t x;
21932852eceSpooka 
220d69295fdSpooka     errno = 0;
22132852eceSpooka     x = strtoll(arg, &s, 0);
22232852eceSpooka     /* allow at most one extra char */
22332852eceSpooka     if (errno || x < 0 || (s[0] && s[1]) )
22432852eceSpooka 	errx(1, "%s: bad %s", arg, msg);
22532852eceSpooka     if (*s) {	/* the extra char is the multiplier */
22632852eceSpooka 	switch (*s) {
22732852eceSpooka 	default:
22832852eceSpooka 	    errx(1, "%s: bad %s", arg, msg);
22932852eceSpooka 	    /* notreached */
23032852eceSpooka 
23132852eceSpooka 	case 's':	/* sector */
23232852eceSpooka 	case 'S':
23332852eceSpooka 	    x <<= 9;	/* times 512 */
23432852eceSpooka 	    break;
23532852eceSpooka 
23632852eceSpooka 	case 'k':	/* kilobyte */
23732852eceSpooka 	case 'K':
23832852eceSpooka 	    x <<= 10;	/* times 1024 */
23932852eceSpooka 	    break;
24032852eceSpooka 
24132852eceSpooka 	case 'm':	/* megabyte */
24232852eceSpooka 	case 'M':
24332852eceSpooka 	    x <<= 20;	/* times 1024*1024 */
24432852eceSpooka 	    break;
24532852eceSpooka 
24632852eceSpooka 	case 'g':	/* gigabyte */
24732852eceSpooka 	case 'G':
24832852eceSpooka 	    x <<= 30;	/* times 1024*1024*1024 */
24932852eceSpooka 	    break;
25032852eceSpooka 
25132852eceSpooka 	case 'p':	/* partition start */
25232852eceSpooka 	case 'P':	/* partition start */
25332852eceSpooka 	case 'l':	/* partition length */
25432852eceSpooka 	case 'L':	/* partition length */
25532852eceSpooka 	    errx(1, "%s: not supported yet %s", arg, msg);
256aed35c48Schristos 	    return -1;
25732852eceSpooka 	    /* notreached */
25832852eceSpooka 	}
25932852eceSpooka     }
26032852eceSpooka     return x;
26132852eceSpooka }
26232852eceSpooka 
26332852eceSpooka /*
264de3ce7e7Schristos  * Print usage message.
265de3ce7e7Schristos  */
266de3ce7e7Schristos static void
usage(void)267de3ce7e7Schristos usage(void)
268de3ce7e7Schristos {
269de3ce7e7Schristos     fprintf(stderr,
270b635f565Sjmmv 	    "usage: %s [ -options ] special [disktype]\n", getprogname());
271de3ce7e7Schristos     fprintf(stderr, "where the options are:\n");
272aed35c48Schristos static struct {
273aed35c48Schristos 	char o;
274aed35c48Schristos 	const char *h;
275aed35c48Schristos } opts[] = {
27630441591Schristos #define AOPT(_opt, _type, _name, _min, _desc) { _opt, _desc },
277aed35c48Schristos ALLOPTS
278aed35c48Schristos #undef AOPT
279aed35c48Schristos };
280aed35c48Schristos     for (size_t i = 0; i < __arraycount(opts); i++)
281aed35c48Schristos 	fprintf(stderr, "\t-%c %s\n", opts[i].o, opts[i].h);
282de3ce7e7Schristos     exit(1);
283de3ce7e7Schristos }
284