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