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