Home | History | Annotate | Line # | Download | only in newfs_msdos
newfs_msdos.c revision 1.44
      1 /*	$NetBSD: newfs_msdos.c,v 1.44 2017/02/16 18:49:31 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.44 2017/02/16 18:49:31 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 = get_tstamp(optarg);
    174 	    break;
    175 	case 'u':
    176 	    o.sectors_per_track = argto2(optarg, 1, "sectors/track");
    177 	    break;
    178 	default:
    179 	    usage();
    180 	}
    181     argc -= optind;
    182     argv += optind;
    183     if (argc < 1 || argc > 2)
    184 	usage();
    185     fname = *argv++;
    186     if (!strchr(fname, '/') && !o.create_size) {
    187 	snprintf(buf, sizeof(buf), "%sr%s", _PATH_DEV, fname);
    188 	if (!(fname = strdup(buf)))
    189 	    err(1, NULL);
    190     }
    191     dtype = *argv;
    192     return mkfs_msdos(fname, dtype, &o);
    193 }
    194 
    195 /*
    196  * Convert and check a numeric option argument.
    197  */
    198 static u_int
    199 argtou(const char *arg, u_int lo, u_int hi, const char *msg)
    200 {
    201     off_t x;
    202 
    203     errno = 0;
    204     x = argtooff(arg, msg);
    205     if (x < lo || x > hi)
    206 	errx(1, "%s: bad %s", arg, msg);
    207     return (u_int)x;
    208 }
    209 
    210 /*
    211  * Same for off_t, with optional skmgpP suffix
    212  */
    213 static off_t
    214 argtooff(const char *arg, const char *msg)
    215 {
    216     char *s;
    217     off_t x;
    218 
    219     errno = 0;
    220     x = strtoll(arg, &s, 0);
    221     /* allow at most one extra char */
    222     if (errno || x < 0 || (s[0] && s[1]) )
    223 	errx(1, "%s: bad %s", arg, msg);
    224     if (*s) {	/* the extra char is the multiplier */
    225 	switch (*s) {
    226 	default:
    227 	    errx(1, "%s: bad %s", arg, msg);
    228 	    /* notreached */
    229 
    230 	case 's':	/* sector */
    231 	case 'S':
    232 	    x <<= 9;	/* times 512 */
    233 	    break;
    234 
    235 	case 'k':	/* kilobyte */
    236 	case 'K':
    237 	    x <<= 10;	/* times 1024 */
    238 	    break;
    239 
    240 	case 'm':	/* megabyte */
    241 	case 'M':
    242 	    x <<= 20;	/* times 1024*1024 */
    243 	    break;
    244 
    245 	case 'g':	/* gigabyte */
    246 	case 'G':
    247 	    x <<= 30;	/* times 1024*1024*1024 */
    248 	    break;
    249 
    250 	case 'p':	/* partition start */
    251 	case 'P':	/* partition start */
    252 	case 'l':	/* partition length */
    253 	case 'L':	/* partition length */
    254 	    errx(1, "%s: not supported yet %s", arg, msg);
    255 	    return -1;
    256 	    /* notreached */
    257 	}
    258     }
    259     return x;
    260 }
    261 
    262 /*
    263  * Print usage message.
    264  */
    265 static void
    266 usage(void)
    267 {
    268     fprintf(stderr,
    269 	    "usage: %s [ -options ] special [disktype]\n", getprogname());
    270     fprintf(stderr, "where the options are:\n");
    271 static struct {
    272 	char o;
    273 	const char *h;
    274 } opts[] = {
    275 #define AOPT(_opt, _type, _name, _min, _desc) { _opt, _desc },
    276 ALLOPTS
    277 #undef AOPT
    278 };
    279     for (size_t i = 0; i < __arraycount(opts); i++)
    280 	fprintf(stderr, "\t-%c %s\n", opts[i].o, opts[i].h);
    281     exit(1);
    282 }
    283