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