Home | History | Annotate | Line # | Download | only in newfs_msdos
newfs_msdos.c revision 1.3.4.1
      1  1.3.4.1       cgd /*	$NetBSD: newfs_msdos.c,v 1.3.4.1 1999/08/20 04:56:49 cgd Exp $	*/
      2      1.1  christos 
      3      1.1  christos /*
      4      1.1  christos  * Copyright (c) 1997 Christos Zoulas
      5      1.1  christos  * Copyright (c) 1995, 1996 Joerg Wunsch
      6      1.1  christos  *
      7      1.1  christos  * All rights reserved.
      8      1.1  christos  *
      9      1.1  christos  * This program is free software.
     10      1.1  christos  *
     11      1.1  christos  * Redistribution and use in source and binary forms, with or without
     12      1.1  christos  * modification, are permitted provided that the following conditions
     13      1.1  christos  * are met:
     14      1.1  christos  * 1. Redistributions of source code must retain the above copyright
     15      1.1  christos  *    notice, this list of conditions and the following disclaimer.
     16      1.1  christos  * 2. Redistributions in binary form must reproduce the above copyright
     17      1.1  christos  *    notice, this list of conditions and the following disclaimer in the
     18      1.1  christos  *    documentation and/or other materials provided with the distribution.
     19      1.1  christos  *
     20      1.1  christos  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY EXPRESS OR
     21      1.1  christos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     22      1.1  christos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     23      1.1  christos  * IN NO EVENT SHALL THE DEVELOPERS BE LIABLE FOR ANY DIRECT, INDIRECT,
     24      1.1  christos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     25      1.1  christos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26      1.1  christos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27      1.1  christos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28      1.1  christos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     29      1.1  christos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30      1.1  christos  */
     31      1.1  christos 
     32      1.1  christos /*
     33      1.1  christos  * Create an MS-DOS (FAT) file system.
     34      1.1  christos  *
     35      1.1  christos  * Id: mkdosfs.c,v 1.4 1997/02/22 16:06:38 peter Exp
     36      1.1  christos  */
     37      1.2     lukem 
     38      1.2     lukem #include <sys/cdefs.h>
     39      1.1  christos #ifndef lint
     40  1.3.4.1       cgd __RCSID("$NetBSD: newfs_msdos.c,v 1.3.4.1 1999/08/20 04:56:49 cgd Exp $");
     41      1.1  christos #endif /* not lint */
     42      1.1  christos 
     43      1.1  christos #include <sys/types.h>
     44      1.1  christos #include <sys/param.h>
     45      1.1  christos #include <sys/stat.h>
     46      1.1  christos #include <stdio.h>
     47      1.1  christos #include <stdlib.h>
     48      1.1  christos #include <time.h>
     49      1.1  christos #include <unistd.h>
     50      1.1  christos #include <memory.h>
     51      1.1  christos #include <err.h>
     52      1.1  christos #include <errno.h>
     53      1.1  christos #include <fcntl.h>
     54      1.1  christos #include <assert.h>
     55      1.1  christos 
     56      1.1  christos /* From msdosfs */
     57      1.1  christos #include <direntry.h>
     58      1.1  christos #include <bpb.h>
     59      1.1  christos #include <bootsect.h>
     60      1.1  christos 
     61      1.1  christos #include "bootcode.h"
     62      1.1  christos 
     63      1.1  christos struct descrip {
     64      1.1  christos 	/* our database key */
     65      1.1  christos 	unsigned        kilobytes;
     66      1.1  christos 	/* MSDOS 3.3 BPB fields */
     67      1.1  christos 	u_short         sectsiz;
     68      1.1  christos 	u_char          clustsiz;
     69      1.1  christos 	u_short         ressecs;
     70      1.1  christos 	u_char          fatcnt;
     71      1.1  christos 	u_short         rootsiz;
     72      1.1  christos 	u_short         totsecs;
     73      1.1  christos 	u_char          media;
     74      1.1  christos 	u_short         fatsize;
     75      1.1  christos 	u_short         trksecs;
     76      1.1  christos 	u_short         headcnt;
     77      1.1  christos 	u_short         hidnsec;
     78      1.1  christos 	/* MSDOS 4 BPB extensions */
     79      1.1  christos 	u_long          ext_totsecs;
     80      1.1  christos 	u_short         ext_physdrv;
     81      1.1  christos 	u_char          ext_extboot;
     82      1.1  christos 	char            ext_label[11];
     83      1.1  christos 	char            ext_fsysid[8];
     84      1.1  christos };
     85      1.1  christos 
     86      1.1  christos static struct descrip table[] = {
     87      1.1  christos 	/* NB: must be sorted, starting with the largest format! */
     88      1.1  christos 	/*
     89      1.1  christos          *  KB  sec cls res fat  rot   tot   med fsz spt hds hid
     90      1.1  christos          * tot  phs ebt  label       fsysid
     91      1.1  christos          */
     92      1.1  christos 	{ 1440, 512,  1,  1,  2, 224, 2880, 0xf0,  9, 18,  2,  0,
     93      1.1  christos 	     0,   0,  0, "4.4BSD     ", "FAT12   " },
     94      1.1  christos 	{ 1200, 512,  1,  1,  2, 224, 2400, 0xf9,  7, 15,  2,  0,
     95      1.1  christos 	     0,   0,  0, "4.4BSD     ", "FAT12   " },
     96      1.1  christos 	{  720, 512,  2,  1,  2, 112, 1440, 0xf9,  3,  9,  2,  0,
     97      1.1  christos 	     0,   0,  0, "4.4BSD     ", "FAT12   " },
     98      1.1  christos 	{  360, 512,  2,  1,  2, 112,  720, 0xfd,  2,  9,  2,  0,
     99      1.1  christos 	     0,   0,  0, "4.4BSD     ", "FAT12   " },
    100      1.1  christos 	{    0,   0,  0,  0,  0,   0,    0, 0x00,  0,  0,  0,  0,
    101      1.1  christos 	     0,   0,  0, "           ", "        " }
    102      1.1  christos };
    103      1.1  christos 
    104      1.1  christos struct fat {
    105      1.1  christos 	u_int8_t media;		/* the media descriptor again */
    106      1.1  christos 	u_int8_t padded;	/* always 0xff */
    107      1.1  christos 	u_int8_t contents[1];	/* the `1' is a placeholder only */
    108      1.1  christos };
    109      1.1  christos 
    110      1.1  christos 
    111      1.1  christos int main __P((int, char *[]));
    112      1.1  christos 
    113      1.1  christos static void usage __P((void));
    114      1.1  christos static size_t findformat __P((int));
    115      1.1  christos static void setup_boot_sector_from_template __P((union bootsector *,
    116      1.1  christos     struct descrip *));
    117      1.1  christos 
    118      1.1  christos 
    119      1.1  christos static void
    120      1.1  christos usage()
    121      1.1  christos {
    122      1.1  christos 	extern char *__progname;
    123      1.1  christos 
    124      1.1  christos 	(void) fprintf(stderr,
    125      1.1  christos 	    "Usage: %s [-f <kbytes>] [-L <label>] <device>\n", __progname);
    126      1.1  christos 	exit(1);
    127      1.1  christos }
    128      1.1  christos 
    129      1.1  christos /*
    130      1.1  christos  *	Try to deduce a format appropriate for our disk.
    131      1.1  christos  *	This is a bit tricky.  If the argument is a regular file, we can
    132      1.1  christos  *	lseek() to its end and get the size reported.  If it's a device
    133      1.1  christos  *	however, lseeking doesn't report us any useful number.  Instead,
    134      1.1  christos  *	we try to seek just to the end of the device and try reading a
    135      1.1  christos  *	block there.  In the case where we've hit exactly the device
    136      1.1  christos  *	boundary, we get a zero read, and thus have found the size.
    137      1.1  christos  *	Since our knowledge of distinct formats is limited anyway, this
    138      1.1  christos  *	is not a big deal at all.
    139      1.1  christos  */
    140      1.1  christos static size_t
    141      1.1  christos findformat(fd)
    142      1.1  christos 	int fd;
    143      1.1  christos {
    144      1.1  christos 	struct stat     sb;
    145      1.1  christos 	off_t offs;
    146      1.1  christos 
    147      1.1  christos 
    148      1.1  christos 	if (fstat(fd, &sb) == -1)
    149      1.1  christos 		err(1, "Cannot fstat disk");	/* Cannot happen */
    150      1.1  christos 
    151      1.1  christos 	if (S_ISREG(sb.st_mode)) {
    152      1.1  christos 		if (lseek(fd, (off_t) 0, SEEK_END) == -1 ||
    153      1.1  christos 		    (offs = lseek(fd, (off_t) 0, SEEK_CUR)) == -1)
    154      1.1  christos 			/* Hmm, hmm.  Hard luck. */
    155      1.1  christos 			return 0;
    156  1.3.4.1       cgd 		(void) lseek(fd, (off_t) 0, SEEK_SET);
    157      1.1  christos 		return (size_t) (offs / 1024);
    158      1.1  christos 	} else if (S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode)) {
    159      1.1  christos 		char            b[512];
    160      1.1  christos 		int             rv;
    161      1.1  christos 		struct descrip *dp;
    162      1.1  christos 
    163      1.1  christos 		for (dp = table; dp->kilobytes != 0; dp++) {
    164      1.1  christos 			offs = dp->kilobytes * 1024;
    165      1.1  christos 
    166      1.1  christos 			if (lseek(fd, offs, SEEK_SET) == -1)
    167      1.1  christos 				/* Uh-oh, lseek() is not supposed to fail. */
    168      1.1  christos 				return 0;
    169      1.1  christos 
    170      1.1  christos 			if ((rv = read(fd, b, 512)) == 0)
    171      1.1  christos 				break;
    172      1.1  christos 			/*
    173      1.1  christos 			 * XXX The ENOSPC is for the bogus fd(4) driver
    174      1.1  christos 			 * return value.
    175      1.1  christos 			 */
    176      1.1  christos 			if (rv == -1 && errno != EINVAL && errno != ENOSPC)
    177      1.1  christos 				return 0;
    178      1.1  christos 			/* else: continue */
    179      1.1  christos 		}
    180      1.1  christos 		(void) lseek(fd, (off_t) 0, SEEK_SET);
    181      1.1  christos 		return dp->kilobytes;
    182      1.1  christos 	} else
    183      1.1  christos 		/* Outta luck. */
    184      1.1  christos 		return 0;
    185      1.1  christos }
    186      1.1  christos 
    187      1.1  christos 
    188      1.1  christos static void
    189      1.1  christos setup_boot_sector_from_template(bs, dp)
    190      1.1  christos 	union bootsector *bs;
    191      1.1  christos 	struct descrip *dp;
    192      1.1  christos {
    193      1.1  christos 	struct byte_bpb50 bpb;
    194      1.3  drochner 	struct extboot *exb = (struct extboot *)bs->bs50.bsExt;
    195      1.1  christos 
    196      1.1  christos 	assert(sizeof(bs->bs50) == 512);
    197      1.1  christos 	assert(sizeof(bootcode) == 512);
    198      1.1  christos 
    199      1.1  christos 	(void) memcpy(&bs->bs50, bootcode, 512);
    200      1.1  christos 
    201      1.1  christos 	putushort(bpb.bpbBytesPerSec, dp->sectsiz);
    202      1.1  christos 	bpb.bpbSecPerClust = dp->clustsiz;
    203      1.1  christos 	putushort(bpb.bpbResSectors, dp->ressecs);
    204      1.1  christos 	bpb.bpbFATs = dp->fatcnt;
    205      1.1  christos 	putushort(bpb.bpbRootDirEnts, dp->rootsiz);
    206      1.1  christos 	putushort(bpb.bpbSectors, dp->totsecs);
    207      1.1  christos 	bpb.bpbMedia = dp->media;
    208      1.1  christos 	putushort(bpb.bpbFATsecs, dp->fatsize);
    209      1.1  christos 	putushort(bpb.bpbSecPerTrack, dp->trksecs);
    210      1.1  christos 	putushort(bpb.bpbHeads, dp->headcnt);
    211      1.1  christos 	putulong(bpb.bpbHiddenSecs, dp->hidnsec);
    212      1.1  christos 	putulong(bpb.bpbHugeSectors, dp->ext_totsecs);
    213      1.1  christos 
    214      1.3  drochner 	exb->exDriveNumber = dp->ext_physdrv;
    215      1.3  drochner 	exb->exBootSignature = dp->ext_extboot;
    216      1.1  christos 
    217      1.1  christos 	/* assign a "serial number" :) */
    218      1.1  christos 	srandom((unsigned) time((time_t) 0));
    219      1.3  drochner 	putulong(exb->exVolumeID, random());
    220      1.1  christos 
    221      1.3  drochner 	(void) memcpy(exb->exVolumeLabel, dp->ext_label,
    222      1.3  drochner 	    MIN(sizeof(dp->ext_label), sizeof(exb->exVolumeLabel)));
    223      1.3  drochner 	(void) memcpy(exb->exFileSysType, dp->ext_fsysid,
    224      1.3  drochner 	    MIN(sizeof(dp->ext_fsysid), sizeof(exb->exFileSysType)));
    225      1.1  christos 	(void) memcpy(bs->bs50.bsBPB, &bpb,
    226      1.1  christos 	    MIN(sizeof(bpb), sizeof(bs->bs50.bsBPB)));
    227      1.1  christos }
    228      1.1  christos 
    229      1.1  christos int
    230      1.1  christos main(argc, argv)
    231      1.1  christos 	int argc;
    232      1.1  christos 	char *argv[];
    233      1.1  christos {
    234      1.1  christos 	union bootsector bs;
    235      1.1  christos 	struct descrip *dp;
    236      1.1  christos 	struct fat     *fat;
    237      1.1  christos 	struct direntry *rootdir;
    238      1.1  christos 	struct tm      *tp;
    239      1.1  christos 	time_t          now;
    240      1.1  christos 	int             c, i, fd, format = 0, rootdirsize, fatsz;
    241      1.1  christos 	const char     *label = 0;
    242      1.1  christos 
    243      1.1  christos 	while ((c = getopt(argc, argv, "f:L:")) != -1)
    244      1.1  christos 		switch (c) {
    245      1.1  christos 		case 'f':
    246      1.1  christos 			format = atoi(optarg);
    247      1.1  christos 			break;
    248      1.1  christos 
    249      1.1  christos 		case 'L':
    250      1.1  christos 			label = optarg;
    251      1.1  christos 			break;
    252      1.1  christos 
    253      1.1  christos 		case '?':
    254      1.1  christos 		default:
    255      1.1  christos 			usage();
    256      1.1  christos 		}
    257      1.1  christos 
    258      1.1  christos 	argc -= optind;
    259      1.1  christos 	argv += optind;
    260      1.1  christos 
    261      1.1  christos 	if (argc != 1)
    262      1.1  christos 		usage();
    263      1.1  christos 
    264      1.1  christos 	if ((fd = open(argv[0], O_RDWR | O_EXCL, 0)) == -1)
    265      1.1  christos 		err(1, "Cannot open `%s'", argv[0]);
    266      1.1  christos 
    267      1.1  christos 	/* If no format specified, try to figure it out. */
    268      1.1  christos 	if (format == 0  && (format = findformat(fd)) == 0)
    269      1.1  christos 		errx(1, "Cannot determine size, must use -f format");
    270      1.1  christos 
    271      1.1  christos 	for (dp = table; dp->kilobytes != 0; dp++)
    272      1.1  christos 		if (dp->kilobytes == format)
    273      1.1  christos 			break;
    274      1.1  christos 
    275      1.1  christos 	if (dp->kilobytes == 0)
    276      1.1  christos 		errx(1, "Cannot find format description for %d KB", format);
    277      1.1  christos 
    278      1.1  christos 	/* prepare and write the boot sector */
    279      1.1  christos 	setup_boot_sector_from_template(&bs, dp);
    280      1.1  christos 
    281      1.1  christos 	/* if we've got an explicit label, use it */
    282      1.1  christos 	if (label)
    283      1.3  drochner 		(void) strncpy(((struct extboot *)(bs.bs50.bsExt))
    284      1.3  drochner 			       ->exVolumeLabel, label, 11);
    285      1.1  christos 
    286      1.1  christos 	if (write(fd, &bs, sizeof bs) != sizeof bs)
    287      1.1  christos 		err(1, "Writing boot sector");
    288      1.1  christos 
    289      1.1  christos 	/* now, go on with the FATs */
    290      1.1  christos 	if ((fat = (struct fat *) malloc(dp->sectsiz * dp->fatsize)) == NULL)
    291      1.1  christos 		err(1, "Out of memory (FAT table)");
    292      1.1  christos 
    293      1.1  christos 	(void) memset(fat, 0, dp->sectsiz * dp->fatsize);
    294      1.1  christos 
    295      1.1  christos 	fat->media = dp->media;
    296      1.1  christos 	fat->padded = 0xff;
    297      1.1  christos 	fat->contents[0] = 0xff;
    298      1.1  christos 	if (dp->totsecs > 20740 ||
    299      1.1  christos 	    (dp->totsecs == 0 && dp->ext_totsecs > 20740))
    300      1.1  christos 		/* 16-bit FAT */
    301      1.1  christos 		fat->contents[1] = 0xff;
    302      1.1  christos 
    303      1.1  christos 	fatsz =  dp->sectsiz * dp->fatsize;
    304      1.1  christos 	for (i = 0; i < dp->fatcnt; i++)
    305      1.1  christos 		if (write(fd, fat, fatsz) != fatsz)
    306      1.1  christos 			err(1, "Writing FAT %d", i);
    307      1.1  christos 
    308      1.1  christos 	free(fat);
    309      1.1  christos 
    310      1.1  christos 	/* finally, build the root dir */
    311      1.1  christos 	rootdirsize = dp->rootsiz * sizeof(struct direntry);
    312      1.1  christos 	rootdirsize = roundup(rootdirsize, dp->clustsiz * dp->sectsiz);
    313      1.1  christos 
    314      1.1  christos 	if ((rootdir = (struct direntry *) malloc(rootdirsize)) == NULL)
    315      1.1  christos 		err(1, "Out of memory (root directory)");
    316      1.1  christos 
    317      1.1  christos 	(void) memset(rootdir, 0, rootdirsize);
    318      1.1  christos 
    319      1.1  christos 	/* set up a volume label inside the root dir :) */
    320      1.1  christos 	if (label)
    321      1.1  christos 		(void) strncpy(rootdir->deName, label, 11);
    322      1.1  christos 	else
    323      1.1  christos 		(void) memcpy(rootdir->deName, dp->ext_label, 11);
    324      1.1  christos 
    325      1.1  christos 	rootdir->deAttributes = ATTR_VOLUME;
    326      1.1  christos 	now = time((time_t) 0);
    327      1.1  christos 	tp = localtime(&now);
    328      1.1  christos 	rootdir->deCTime[0] = tp->tm_sec / 2;
    329      1.1  christos 	rootdir->deCTime[0] |= (tp->tm_min & 7) << 5;
    330      1.1  christos 	rootdir->deCTime[1] = ((tp->tm_min >> 3) & 7);
    331      1.1  christos 	rootdir->deCTime[1] |= tp->tm_hour << 3;
    332      1.1  christos 	rootdir->deCDate[0] = tp->tm_mday;
    333      1.1  christos 	rootdir->deCDate[0] |= ((tp->tm_mon + 1) & 7) << 5;
    334      1.1  christos 	rootdir->deCDate[1] = ((tp->tm_mon + 1) >> 3) & 1;
    335      1.1  christos 	rootdir->deCDate[1] |= (tp->tm_year - 80) << 1;
    336      1.1  christos 
    337      1.1  christos 	if (write(fd, rootdir, rootdirsize) != rootdirsize)
    338      1.1  christos 		err(1, "Writing root directory");
    339      1.1  christos 
    340      1.1  christos 	(void) close(fd);
    341      1.1  christos 
    342      1.1  christos 	return 0;
    343      1.1  christos }
    344