Home | History | Annotate | Line # | Download | only in newfs
newfs.c revision 1.1
      1 /*
      2  * Copyright (c) 1983, 1989 The Regents of the University of California.
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  * 3. All advertising materials mentioning features or use of this software
     14  *    must display the following acknowledgement:
     15  *	This product includes software developed by the University of
     16  *	California, Berkeley and its contributors.
     17  * 4. Neither the name of the University nor the names of its contributors
     18  *    may be used to endorse or promote products derived from this software
     19  *    without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     31  * SUCH DAMAGE.
     32  */
     33 
     34 #ifndef lint
     35 static char sccsid[] = "@(#)newfs.c	6.27 (Berkeley) 7/3/91";
     36 #endif /* not lint */
     37 
     38 #ifndef lint
     39 char copyright[] =
     40 "@(#) Copyright (c) 1983, 1989 Regents of the University of California.\n\
     41  All rights reserved.\n";
     42 #endif /* not lint */
     43 
     44 /*
     45  * newfs: friendly front end to mkfs
     46  */
     47 #include <sys/param.h>
     48 #include <sys/stat.h>
     49 #include <ufs/fs.h>
     50 #include <ufs/dir.h>
     51 #include <sys/ioctl.h>
     52 #include <sys/disklabel.h>
     53 #include <sys/file.h>
     54 #include <sys/mount.h>
     55 
     56 #include <errno.h>
     57 #include <stdarg.h>
     58 #include <stdio.h>
     59 #include <ctype.h>
     60 #include <string.h>
     61 #include <stdlib.h>
     62 #include <paths.h>
     63 
     64 #define	COMPAT			/* allow non-labeled disks */
     65 
     66 /*
     67  * The following two constants set the default block and fragment sizes.
     68  * Both constants must be a power of 2 and meet the following constraints:
     69  *	MINBSIZE <= DESBLKSIZE <= MAXBSIZE
     70  *	sectorsize <= DESFRAGSIZE <= DESBLKSIZE
     71  *	DESBLKSIZE / DESFRAGSIZE <= 8
     72  */
     73 #define	DFL_FRAGSIZE	1024
     74 #define	DFL_BLKSIZE	8192
     75 
     76 /*
     77  * Cylinder groups may have up to many cylinders. The actual
     78  * number used depends upon how much information can be stored
     79  * on a single cylinder. The default is to use 16 cylinders
     80  * per group.
     81  */
     82 #define	DESCPG		16	/* desired fs_cpg */
     83 
     84 /*
     85  * MINFREE gives the minimum acceptable percentage of file system
     86  * blocks which may be free. If the freelist drops below this level
     87  * only the superuser may continue to allocate blocks. This may
     88  * be set to 0 if no reserve of free blocks is deemed necessary,
     89  * however throughput drops by fifty percent if the file system
     90  * is run at between 90% and 100% full; thus the default value of
     91  * fs_minfree is 10%. With 10% free space, fragmentation is not a
     92  * problem, so we choose to optimize for time.
     93  */
     94 #define MINFREE		10
     95 #define DEFAULTOPT	FS_OPTTIME
     96 
     97 /*
     98  * ROTDELAY gives the minimum number of milliseconds to initiate
     99  * another disk transfer on the same cylinder. It is used in
    100  * determining the rotationally optimal layout for disk blocks
    101  * within a file; the default of fs_rotdelay is 4ms.
    102  */
    103 #define ROTDELAY	4
    104 
    105 /*
    106  * MAXCONTIG sets the default for the maximum number of blocks
    107  * that may be allocated sequentially. Since UNIX drivers are
    108  * not capable of scheduling multi-block transfers, this defaults
    109  * to 1 (ie no contiguous blocks are allocated).
    110  */
    111 #define MAXCONTIG	1
    112 
    113 /*
    114  * MAXBLKPG determines the maximum number of data blocks which are
    115  * placed in a single cylinder group. The default is one indirect
    116  * block worth of data blocks.
    117  */
    118 #define MAXBLKPG(bsize)	((bsize) / sizeof(daddr_t))
    119 
    120 /*
    121  * Each file system has a number of inodes statically allocated.
    122  * We allocate one inode slot per NFPI fragments, expecting this
    123  * to be far more than we will ever need.
    124  */
    125 #define	NFPI		4
    126 
    127 /*
    128  * For each cylinder we keep track of the availability of blocks at different
    129  * rotational positions, so that we can lay out the data to be picked
    130  * up with minimum rotational latency.  NRPOS is the default number of
    131  * rotational positions that we distinguish.  With NRPOS of 8 the resolution
    132  * of our summary information is 2ms for a typical 3600 rpm drive.
    133  */
    134 #define	NRPOS		8	/* number distinct rotational positions */
    135 
    136 
    137 int	mfs;			/* run as the memory based filesystem */
    138 int	Nflag;			/* run without writing file system */
    139 int	fssize;			/* file system size */
    140 int	ntracks;		/* # tracks/cylinder */
    141 int	nsectors;		/* # sectors/track */
    142 int	nphyssectors;		/* # sectors/track including spares */
    143 int	secpercyl;		/* sectors per cylinder */
    144 int	trackspares = -1;	/* spare sectors per track */
    145 int	cylspares = -1;		/* spare sectors per cylinder */
    146 int	sectorsize;		/* bytes/sector */
    147 #ifdef tahoe
    148 int	realsectorsize;		/* bytes/sector in hardware */
    149 #endif
    150 int	rpm;			/* revolutions/minute of drive */
    151 int	interleave;		/* hardware sector interleave */
    152 int	trackskew = -1;		/* sector 0 skew, per track */
    153 int	headswitch;		/* head switch time, usec */
    154 int	trackseek;		/* track-to-track seek, usec */
    155 int	fsize = 0;		/* fragment size */
    156 int	bsize = 0;		/* block size */
    157 int	cpg = DESCPG;		/* cylinders/cylinder group */
    158 int	cpgflg;			/* cylinders/cylinder group flag was given */
    159 int	minfree = MINFREE;	/* free space threshold */
    160 int	opt = DEFAULTOPT;	/* optimization preference (space or time) */
    161 int	density;		/* number of bytes per inode */
    162 int	maxcontig = MAXCONTIG;	/* max contiguous blocks to allocate */
    163 int	rotdelay = ROTDELAY;	/* rotational delay between blocks */
    164 int	maxbpg;			/* maximum blocks per file in a cyl group */
    165 int	nrpos = NRPOS;		/* # of distinguished rotational positions */
    166 int	bbsize = BBSIZE;	/* boot block size */
    167 int	sbsize = SBSIZE;	/* superblock size */
    168 int	mntflags;		/* flags to be passed to mount */
    169 u_long	memleft;		/* virtual memory available */
    170 caddr_t	membase;		/* start address of memory based filesystem */
    171 #ifdef COMPAT
    172 char	*disktype;
    173 int	unlabeled;
    174 #endif
    175 
    176 char	device[MAXPATHLEN];
    177 char	*progname;
    178 
    179 main(argc, argv)
    180 	int argc;
    181 	char *argv[];
    182 {
    183 	extern char *optarg;
    184 	extern int optind;
    185 	register int ch;
    186 	register struct partition *pp;
    187 	register struct disklabel *lp;
    188 	struct disklabel *getdisklabel();
    189 	struct partition oldpartition;
    190 	struct stat st;
    191 	int fsi, fso;
    192 	char *cp, *special, *opstring, buf[BUFSIZ];
    193 
    194 	if (progname = rindex(*argv, '/'))
    195 		++progname;
    196 	else
    197 		progname = *argv;
    198 
    199 	if (strstr(progname, "mfs")) {
    200 		mfs = 1;
    201 		Nflag++;
    202 	}
    203 
    204 	opstring = "F:NS:T:a:b:c:d:e:f:i:k:l:m:n:o:p:r:s:t:u:x:";
    205 	if (!mfs)
    206 		opstring += 2;		/* -F is mfs only */
    207 
    208 	while ((ch = getopt(argc, argv, opstring)) != EOF)
    209 		switch(ch) {
    210 		case 'F':
    211 			if ((mntflags = atoi(optarg)) == 0)
    212 				fatal("%s: bad mount flags", optarg);
    213 			break;
    214 		case 'N':
    215 			Nflag++;
    216 			break;
    217 		case 'S':
    218 			if ((sectorsize = atoi(optarg)) <= 0)
    219 				fatal("%s: bad sector size", optarg);
    220 			break;
    221 #ifdef COMPAT
    222 		case 'T':
    223 			disktype = optarg;
    224 			break;
    225 #endif
    226 		case 'a':
    227 			if ((maxcontig = atoi(optarg)) <= 0)
    228 				fatal("%s: bad max contiguous blocks\n",
    229 				    optarg);
    230 			break;
    231 		case 'b':
    232 			if ((bsize = atoi(optarg)) < MINBSIZE)
    233 				fatal("%s: bad block size", optarg);
    234 			break;
    235 		case 'c':
    236 			if ((cpg = atoi(optarg)) <= 0)
    237 				fatal("%s: bad cylinders/group", optarg);
    238 			cpgflg++;
    239 			break;
    240 		case 'd':
    241 			if ((rotdelay = atoi(optarg)) < 0)
    242 				fatal("%s: bad rotational delay\n", optarg);
    243 			break;
    244 		case 'e':
    245 			if ((maxbpg = atoi(optarg)) <= 0)
    246 				fatal("%s: bad blocks per file in a cyl group\n",
    247 				    optarg);
    248 			break;
    249 		case 'f':
    250 			if ((fsize = atoi(optarg)) <= 0)
    251 				fatal("%s: bad frag size", optarg);
    252 			break;
    253 		case 'i':
    254 			if ((density = atoi(optarg)) <= 0)
    255 				fatal("%s: bad bytes per inode\n", optarg);
    256 			break;
    257 		case 'k':
    258 			if ((trackskew = atoi(optarg)) < 0)
    259 				fatal("%s: bad track skew", optarg);
    260 			break;
    261 		case 'l':
    262 			if ((interleave = atoi(optarg)) <= 0)
    263 				fatal("%s: bad interleave", optarg);
    264 			break;
    265 		case 'm':
    266 			if ((minfree = atoi(optarg)) < 0 || minfree > 99)
    267 				fatal("%s: bad free space %%\n", optarg);
    268 			break;
    269 		case 'n':
    270 			if ((nrpos = atoi(optarg)) <= 0)
    271 				fatal("%s: bad rotational layout count\n",
    272 				    optarg);
    273 			break;
    274 		case 'o':
    275 			if (strcmp(optarg, "space") == 0)
    276 				opt = FS_OPTSPACE;
    277 			else if (strcmp(optarg, "time") == 0)
    278 				opt = FS_OPTTIME;
    279 			else
    280 				fatal("%s: bad optimization preference %s",
    281 				    optarg, "(options are `space' or `time')");
    282 			break;
    283 		case 'p':
    284 			if ((trackspares = atoi(optarg)) < 0)
    285 				fatal("%s: bad spare sectors per track",
    286 				    optarg);
    287 			break;
    288 		case 'r':
    289 			if ((rpm = atoi(optarg)) <= 0)
    290 				fatal("%s: bad revs/minute\n", optarg);
    291 			break;
    292 		case 's':
    293 			if ((fssize = atoi(optarg)) <= 0)
    294 				fatal("%s: bad file system size", optarg);
    295 			break;
    296 		case 't':
    297 			if ((ntracks = atoi(optarg)) <= 0)
    298 				fatal("%s: bad total tracks", optarg);
    299 			break;
    300 		case 'u':
    301 			if ((nsectors = atoi(optarg)) <= 0)
    302 				fatal("%s: bad sectors/track", optarg);
    303 			break;
    304 		case 'x':
    305 			if ((cylspares = atoi(optarg)) < 0)
    306 				fatal("%s: bad spare sectors per cylinder",
    307 				    optarg);
    308 			break;
    309 		case '?':
    310 		default:
    311 			usage();
    312 		}
    313 	argc -= optind;
    314 	argv += optind;
    315 
    316 	if (argc != 2 && (mfs || argc != 1))
    317 		usage();
    318 
    319 	special = argv[0];
    320 	cp = rindex(special, '/');
    321 	if (cp == 0) {
    322 		/*
    323 		 * No path prefix; try /dev/r%s then /dev/%s.
    324 		 */
    325 		(void)sprintf(device, "%sr%s", _PATH_DEV, special);
    326 		if (stat(device, &st) == -1)
    327 			(void)sprintf(device, "%s%s", _PATH_DEV, special);
    328 		special = device;
    329 	}
    330 	if (!Nflag) {
    331 		fso = open(special, O_WRONLY);
    332 		if (fso < 0)
    333 			fatal("%s: %s", special, strerror(errno));
    334 	} else
    335 		fso = -1;
    336 	fsi = open(special, O_RDONLY);
    337 	if (fsi < 0)
    338 		fatal("%s: %s", special, strerror(errno));
    339 	if (fstat(fsi, &st) < 0)
    340 		fatal("%s: %s", special, strerror(errno));
    341 	if ((st.st_mode & S_IFMT) != S_IFCHR && !mfs)
    342 		printf("%s: %s: not a character-special device\n",
    343 		    progname, special);
    344 	cp = index(argv[0], '\0') - 1;
    345 	if (cp == 0 || (*cp < 'a' || *cp > 'h') && !isdigit(*cp))
    346 		fatal("%s: can't figure out file system partition", argv[0]);
    347 #ifdef COMPAT
    348 	if (!mfs && disktype == NULL)
    349 		disktype = argv[1];
    350 #endif
    351 	lp = getdisklabel(special, fsi);
    352 	if (isdigit(*cp))
    353 		pp = &lp->d_partitions[0];
    354 	else
    355 		pp = &lp->d_partitions[*cp - 'a'];
    356 	if (pp->p_size == 0)
    357 		fatal("%s: `%c' partition is unavailable", argv[0], *cp);
    358 	if (fssize == 0)
    359 		fssize = pp->p_size;
    360 	if (fssize > pp->p_size && !mfs)
    361 	       fatal("%s: maximum file system size on the `%c' partition is %d",
    362 			argv[0], *cp, pp->p_size);
    363 	if (rpm == 0) {
    364 		rpm = lp->d_rpm;
    365 		if (rpm <= 0)
    366 			rpm = 3600;
    367 	}
    368 	if (ntracks == 0) {
    369 		ntracks = lp->d_ntracks;
    370 		if (ntracks <= 0)
    371 			fatal("%s: no default #tracks", argv[0]);
    372 	}
    373 	if (nsectors == 0) {
    374 		nsectors = lp->d_nsectors;
    375 		if (nsectors <= 0)
    376 			fatal("%s: no default #sectors/track", argv[0]);
    377 	}
    378 	if (sectorsize == 0) {
    379 		sectorsize = lp->d_secsize;
    380 		if (sectorsize <= 0)
    381 			fatal("%s: no default sector size", argv[0]);
    382 	}
    383 	if (trackskew == -1) {
    384 		trackskew = lp->d_trackskew;
    385 		if (trackskew < 0)
    386 			trackskew = 0;
    387 	}
    388 	if (interleave == 0) {
    389 		interleave = lp->d_interleave;
    390 		if (interleave <= 0)
    391 			interleave = 1;
    392 	}
    393 	if (fsize == 0) {
    394 		fsize = pp->p_fsize;
    395 		if (fsize <= 0)
    396 			fsize = MAX(DFL_FRAGSIZE, lp->d_secsize);
    397 	}
    398 	if (bsize == 0) {
    399 		bsize = pp->p_frag * pp->p_fsize;
    400 		if (bsize <= 0)
    401 			bsize = MIN(DFL_BLKSIZE, 8 * fsize);
    402 	}
    403 	if (density == 0)
    404 		density = NFPI * fsize;
    405 	if (minfree < 10 && opt != FS_OPTSPACE) {
    406 		fprintf(stderr, "Warning: changing optimization to space ");
    407 		fprintf(stderr, "because minfree is less than 10%%\n");
    408 		opt = FS_OPTSPACE;
    409 	}
    410 	if (trackspares == -1) {
    411 		trackspares = lp->d_sparespertrack;
    412 		if (trackspares < 0)
    413 			trackspares = 0;
    414 	}
    415 	nphyssectors = nsectors + trackspares;
    416 	if (cylspares == -1) {
    417 		cylspares = lp->d_sparespercyl;
    418 		if (cylspares < 0)
    419 			cylspares = 0;
    420 	}
    421 	secpercyl = nsectors * ntracks - cylspares;
    422 	if (secpercyl != lp->d_secpercyl)
    423 		fprintf(stderr, "%s (%d) %s (%lu)\n",
    424 			"Warning: calculated sectors per cylinder", secpercyl,
    425 			"disagrees with disk label", lp->d_secpercyl);
    426 	if (maxbpg == 0)
    427 		maxbpg = MAXBLKPG(bsize);
    428 	headswitch = lp->d_headswitch;
    429 	trackseek = lp->d_trkseek;
    430 #ifdef notdef /* label may be 0 if faked up by kernel */
    431 	bbsize = lp->d_bbsize;
    432 	sbsize = lp->d_sbsize;
    433 #endif
    434 	oldpartition = *pp;
    435 #ifdef tahoe
    436 	realsectorsize = sectorsize;
    437 	if (sectorsize != DEV_BSIZE) {		/* XXX */
    438 		int secperblk = DEV_BSIZE / sectorsize;
    439 
    440 		sectorsize = DEV_BSIZE;
    441 		nsectors /= secperblk;
    442 		nphyssectors /= secperblk;
    443 		secpercyl /= secperblk;
    444 		fssize /= secperblk;
    445 		pp->p_size /= secperblk;
    446 	}
    447 #endif
    448 	mkfs(pp, special, fsi, fso);
    449 #ifdef tahoe
    450 	if (realsectorsize != DEV_BSIZE)
    451 		pp->p_size *= DEV_BSIZE / realsectorsize;
    452 #endif
    453 	if (!Nflag && bcmp(pp, &oldpartition, sizeof(oldpartition)))
    454 		rewritelabel(special, fso, lp);
    455 	if (!Nflag)
    456 		close(fso);
    457 	close(fsi);
    458 #ifdef MFS
    459 	if (mfs) {
    460 		struct mfs_args args;
    461 
    462 		sprintf(buf, "mfs:%d", getpid());
    463 		args.name = buf;
    464 		args.base = membase;
    465 		args.size = fssize * sectorsize;
    466 		if (mount(MOUNT_MFS, argv[1], mntflags, &args) < 0)
    467 			fatal("%s: %s", argv[1], strerror(errno));
    468 	}
    469 #endif
    470 	exit(0);
    471 }
    472 
    473 #ifdef COMPAT
    474 char lmsg[] = "%s: can't read disk label; disk type must be specified";
    475 #else
    476 char lmsg[] = "%s: can't read disk label";
    477 #endif
    478 
    479 struct disklabel *
    480 getdisklabel(s, fd)
    481 	char *s;
    482 	int fd;
    483 {
    484 	static struct disklabel lab;
    485 
    486 	if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) {
    487 #ifdef COMPAT
    488 		if (disktype) {
    489 			struct disklabel *lp, *getdiskbyname();
    490 
    491 			unlabeled++;
    492 			lp = getdiskbyname(disktype);
    493 			if (lp == NULL)
    494 				fatal("%s: unknown disk type", disktype);
    495 			return (lp);
    496 		}
    497 #endif
    498 		(void)fprintf(stderr,
    499 		    "%s: ioctl (GDINFO): %s\n", progname, strerror(errno));
    500 		fatal(lmsg, s);
    501 	}
    502 	return (&lab);
    503 }
    504 
    505 rewritelabel(s, fd, lp)
    506 	char *s;
    507 	int fd;
    508 	register struct disklabel *lp;
    509 {
    510 #ifdef COMPAT
    511 	if (unlabeled)
    512 		return;
    513 #endif
    514 	lp->d_checksum = 0;
    515 	lp->d_checksum = dkcksum(lp);
    516 	if (ioctl(fd, DIOCWDINFO, (char *)lp) < 0) {
    517 		(void)fprintf(stderr,
    518 		    "%s: ioctl (WDINFO): %s\n", progname, strerror(errno));
    519 		fatal("%s: can't rewrite disk label", s);
    520 	}
    521 #if vax
    522 	if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) {
    523 		register i;
    524 		int cfd;
    525 		daddr_t alt;
    526 		char specname[64];
    527 		char blk[1024];
    528 		char *cp;
    529 
    530 		/*
    531 		 * Make name for 'c' partition.
    532 		 */
    533 		strcpy(specname, s);
    534 		cp = specname + strlen(specname) - 1;
    535 		if (!isdigit(*cp))
    536 			*cp = 'c';
    537 		cfd = open(specname, O_WRONLY);
    538 		if (cfd < 0)
    539 			fatal("%s: %s", specname, strerror(errno));
    540 		bzero(blk, sizeof(blk));
    541 		*(struct disklabel *)(blk + LABELOFFSET) = *lp;
    542 		alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors;
    543 		for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) {
    544 			if (lseek(cfd, (off_t)(alt + i) * lp->d_secsize,
    545 			    L_SET) == -1)
    546 				fatal("lseek to badsector area: %s",
    547 				    strerror(errno));
    548 			if (write(cfd, blk, lp->d_secsize) < lp->d_secsize)
    549 				fprintf(stderr,
    550 				    "%s: alternate label %d write: %s\n",
    551 				    progname, i/2, strerror(errno));
    552 		}
    553 		close(cfd);
    554 	}
    555 #endif
    556 }
    557 
    558 /*VARARGS*/
    559 fatal(fmt)
    560 	char *fmt;
    561 {
    562 	va_list ap;
    563 
    564 	fprintf(stderr, "%s: ", progname);
    565 	va_start(ap, fmt);
    566 	(void)vfprintf(stderr, fmt, ap);
    567 	va_end(ap);
    568 	putc('\n', stderr);
    569 	exit(1);
    570 }
    571 
    572 usage()
    573 {
    574 	if (mfs) {
    575 		fprintf(stderr,
    576 		    "usage: mfs [ -fsoptions ] special-device mount-point\n");
    577 	} else
    578 		fprintf(stderr,
    579 		    "usage: newfs [ -fsoptions ] special-device%s\n",
    580 #ifdef COMPAT
    581 		    " [device-type]");
    582 #else
    583 		    "");
    584 #endif
    585 	fprintf(stderr, "where fsoptions are:\n");
    586 	fprintf(stderr,
    587 	    "\t-N do not create file system, just print out parameters\n");
    588 	fprintf(stderr, "\t-S sector size\n");
    589 #ifdef COMPAT
    590 	fprintf(stderr, "\t-T disktype\n");
    591 #endif
    592 	fprintf(stderr, "\t-a maximum contiguous blocks\n");
    593 	fprintf(stderr, "\t-b block size\n");
    594 	fprintf(stderr, "\t-c cylinders/group\n");
    595 	fprintf(stderr, "\t-d rotational delay between contiguous blocks\n");
    596 	fprintf(stderr, "\t-e maximum blocks per file in a cylinder group\n");
    597 	fprintf(stderr, "\t-f frag size\n");
    598 	fprintf(stderr, "\t-i number of bytes per inode\n");
    599 	fprintf(stderr, "\t-k sector 0 skew, per track\n");
    600 	fprintf(stderr, "\t-l hardware sector interleave\n");
    601 	fprintf(stderr, "\t-m minimum free space %%\n");
    602 	fprintf(stderr, "\t-n number of distinguished rotational positions\n");
    603 	fprintf(stderr, "\t-o optimization preference (`space' or `time')\n");
    604 	fprintf(stderr, "\t-p spare sectors per track\n");
    605 	fprintf(stderr, "\t-s file system size (sectors)\n");
    606 	fprintf(stderr, "\t-r revolutions/minute\n");
    607 	fprintf(stderr, "\t-t tracks/cylinder\n");
    608 	fprintf(stderr, "\t-u sectors/track\n");
    609 	fprintf(stderr, "\t-x spare sectors per cylinder\n");
    610 	exit(1);
    611 }
    612