Home | History | Annotate | Line # | Download | only in newfs_msdos
      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