Home | History | Annotate | Line # | Download | only in newfs
newfs.c revision 1.1.1.3
      1 /*
      2  * Copyright (c) 1983, 1989, 1993, 1994
      3  *	The Regents of the University of California.  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	8.13 (Berkeley) 5/1/95";
     36 #endif /* not lint */
     37 
     38 #ifndef lint
     39 static char copyright[] =
     40 "@(#) Copyright (c) 1983, 1989, 1993, 1994\n\
     41 	The Regents of the University of California.  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 <sys/ioctl.h>
     50 #include <sys/disklabel.h>
     51 #include <sys/file.h>
     52 #include <sys/mount.h>
     53 
     54 #include <ufs/ufs/dir.h>
     55 #include <ufs/ufs/dinode.h>
     56 #include <ufs/ffs/fs.h>
     57 #include <ufs/ufs/ufsmount.h>
     58 
     59 #include <ctype.h>
     60 #include <errno.h>
     61 #include <paths.h>
     62 #include <stdio.h>
     63 #include <stdlib.h>
     64 #include <string.h>
     65 #include <syslog.h>
     66 #include <unistd.h>
     67 
     68 #if __STDC__
     69 #include <stdarg.h>
     70 #else
     71 #include <varargs.h>
     72 #endif
     73 
     74 #include "mntopts.h"
     75 
     76 struct mntopt mopts[] = {
     77 	MOPT_STDOPTS,
     78 	MOPT_ASYNC,
     79 	{ NULL },
     80 };
     81 
     82 #if __STDC__
     83 void	fatal(const char *fmt, ...);
     84 #else
     85 void	fatal();
     86 #endif
     87 
     88 #define	COMPAT			/* allow non-labeled disks */
     89 
     90 /*
     91  * The following two constants set the default block and fragment sizes.
     92  * Both constants must be a power of 2 and meet the following constraints:
     93  *	MINBSIZE <= DESBLKSIZE <= MAXBSIZE
     94  *	sectorsize <= DESFRAGSIZE <= DESBLKSIZE
     95  *	DESBLKSIZE / DESFRAGSIZE <= 8
     96  */
     97 #define	DFL_FRAGSIZE	1024
     98 #define	DFL_BLKSIZE	8192
     99 
    100 /*
    101  * Cylinder groups may have up to many cylinders. The actual
    102  * number used depends upon how much information can be stored
    103  * on a single cylinder. The default is to use 16 cylinders
    104  * per group.
    105  */
    106 #define	DESCPG		16	/* desired fs_cpg */
    107 
    108 /*
    109  * ROTDELAY gives the minimum number of milliseconds to initiate
    110  * another disk transfer on the same cylinder. It is used in
    111  * determining the rotationally optimal layout for disk blocks
    112  * within a file; the default of fs_rotdelay is 4ms.
    113  */
    114 #define ROTDELAY	4
    115 
    116 /*
    117  * MAXBLKPG determines the maximum number of data blocks which are
    118  * placed in a single cylinder group. The default is one indirect
    119  * block worth of data blocks.
    120  */
    121 #define MAXBLKPG(bsize)	((bsize) / sizeof(daddr_t))
    122 
    123 /*
    124  * Each file system has a number of inodes statically allocated.
    125  * We allocate one inode slot per NFPI fragments, expecting this
    126  * to be far more than we will ever need.
    127  */
    128 #define	NFPI		4
    129 
    130 /*
    131  * For each cylinder we keep track of the availability of blocks at different
    132  * rotational positions, so that we can lay out the data to be picked
    133  * up with minimum rotational latency.  NRPOS is the default number of
    134  * rotational positions that we distinguish.  With NRPOS of 8 the resolution
    135  * of our summary information is 2ms for a typical 3600 rpm drive.
    136  */
    137 #define	NRPOS		8	/* number distinct rotational positions */
    138 
    139 
    140 int	mfs;			/* run as the memory based filesystem */
    141 int	Nflag;			/* run without writing file system */
    142 int	Oflag;			/* format as an 4.3BSD file system */
    143 int	fssize;			/* file system size */
    144 int	ntracks;		/* # tracks/cylinder */
    145 int	nsectors;		/* # sectors/track */
    146 int	nphyssectors;		/* # sectors/track including spares */
    147 int	secpercyl;		/* sectors per cylinder */
    148 int	trackspares = -1;	/* spare sectors per track */
    149 int	cylspares = -1;		/* spare sectors per cylinder */
    150 int	sectorsize;		/* bytes/sector */
    151 #ifdef tahoe
    152 int	realsectorsize;		/* bytes/sector in hardware */
    153 #endif
    154 int	rpm;			/* revolutions/minute of drive */
    155 int	interleave;		/* hardware sector interleave */
    156 int	trackskew = -1;		/* sector 0 skew, per track */
    157 int	headswitch;		/* head switch time, usec */
    158 int	trackseek;		/* track-to-track seek, usec */
    159 int	fsize = 0;		/* fragment size */
    160 int	bsize = 0;		/* block size */
    161 int	cpg = DESCPG;		/* cylinders/cylinder group */
    162 int	cpgflg;			/* cylinders/cylinder group flag was given */
    163 int	minfree = MINFREE;	/* free space threshold */
    164 int	opt = DEFAULTOPT;	/* optimization preference (space or time) */
    165 int	density;		/* number of bytes per inode */
    166 int	maxcontig = 0;		/* max contiguous blocks to allocate */
    167 int	rotdelay = ROTDELAY;	/* rotational delay between blocks */
    168 int	maxbpg;			/* maximum blocks per file in a cyl group */
    169 int	nrpos = NRPOS;		/* # of distinguished rotational positions */
    170 int	bbsize = BBSIZE;	/* boot block size */
    171 int	sbsize = SBSIZE;	/* superblock size */
    172 int	mntflags = MNT_ASYNC;	/* flags to be passed to mount */
    173 u_long	memleft;		/* virtual memory available */
    174 caddr_t	membase;		/* start address of memory based filesystem */
    175 #ifdef COMPAT
    176 char	*disktype;
    177 int	unlabeled;
    178 #endif
    179 
    180 char	device[MAXPATHLEN];
    181 char	*progname;
    182 
    183 int
    184 main(argc, argv)
    185 	int argc;
    186 	char *argv[];
    187 {
    188 	extern char *optarg;
    189 	extern int optind;
    190 	register int ch;
    191 	register struct partition *pp;
    192 	register struct disklabel *lp;
    193 	struct disklabel *getdisklabel();
    194 	struct partition oldpartition;
    195 	struct stat st;
    196 	struct statfs *mp;
    197 	int fsi, fso, len, n;
    198 	char *cp, *s1, *s2, *special, *opstring, buf[BUFSIZ];
    199 
    200 	if (progname = strrchr(*argv, '/'))
    201 		++progname;
    202 	else
    203 		progname = *argv;
    204 
    205 	if (strstr(progname, "mfs")) {
    206 		mfs = 1;
    207 		Nflag++;
    208 	}
    209 
    210 	opstring = mfs ?
    211 	    "NT:a:b:c:d:e:f:i:m:o:s:" :
    212 	    "NOS:T:a:b:c:d:e:f:i:k:l:m:n:o:p:r:s:t:u:x:";
    213 	while ((ch = getopt(argc, argv, opstring)) != EOF)
    214 		switch (ch) {
    215 		case 'N':
    216 			Nflag = 1;
    217 			break;
    218 		case 'O':
    219 			Oflag = 1;
    220 			break;
    221 		case 'S':
    222 			if ((sectorsize = atoi(optarg)) <= 0)
    223 				fatal("%s: bad sector size", optarg);
    224 			break;
    225 #ifdef COMPAT
    226 		case 'T':
    227 			disktype = optarg;
    228 			break;
    229 #endif
    230 		case 'a':
    231 			if ((maxcontig = atoi(optarg)) <= 0)
    232 				fatal("%s: bad maximum contiguous blocks\n",
    233 				    optarg);
    234 			break;
    235 		case 'b':
    236 			if ((bsize = atoi(optarg)) < MINBSIZE)
    237 				fatal("%s: bad block size", optarg);
    238 			break;
    239 		case 'c':
    240 			if ((cpg = atoi(optarg)) <= 0)
    241 				fatal("%s: bad cylinders/group", optarg);
    242 			cpgflg++;
    243 			break;
    244 		case 'd':
    245 			if ((rotdelay = atoi(optarg)) < 0)
    246 				fatal("%s: bad rotational delay\n", optarg);
    247 			break;
    248 		case 'e':
    249 			if ((maxbpg = atoi(optarg)) <= 0)
    250 		fatal("%s: bad blocks per file in a cylinder group\n",
    251 				    optarg);
    252 			break;
    253 		case 'f':
    254 			if ((fsize = atoi(optarg)) <= 0)
    255 				fatal("%s: bad fragment size", optarg);
    256 			break;
    257 		case 'i':
    258 			if ((density = atoi(optarg)) <= 0)
    259 				fatal("%s: bad bytes per inode\n", optarg);
    260 			break;
    261 		case 'k':
    262 			if ((trackskew = atoi(optarg)) < 0)
    263 				fatal("%s: bad track skew", optarg);
    264 			break;
    265 		case 'l':
    266 			if ((interleave = atoi(optarg)) <= 0)
    267 				fatal("%s: bad interleave", optarg);
    268 			break;
    269 		case 'm':
    270 			if ((minfree = atoi(optarg)) < 0 || minfree > 99)
    271 				fatal("%s: bad free space %%\n", optarg);
    272 			break;
    273 		case 'n':
    274 			if ((nrpos = atoi(optarg)) <= 0)
    275 				fatal("%s: bad rotational layout count\n",
    276 				    optarg);
    277 			break;
    278 		case 'o':
    279 			if (mfs)
    280 				getmntopts(optarg, mopts, &mntflags, 0);
    281 			else {
    282 				if (strcmp(optarg, "space") == 0)
    283 					opt = FS_OPTSPACE;
    284 				else if (strcmp(optarg, "time") == 0)
    285 					opt = FS_OPTTIME;
    286 				else
    287 	fatal("%s: unknown optimization preference: use `space' or `time'.");
    288 			}
    289 			break;
    290 		case 'p':
    291 			if ((trackspares = atoi(optarg)) < 0)
    292 				fatal("%s: bad spare sectors per track",
    293 				    optarg);
    294 			break;
    295 		case 'r':
    296 			if ((rpm = atoi(optarg)) <= 0)
    297 				fatal("%s: bad revolutions/minute\n", optarg);
    298 			break;
    299 		case 's':
    300 			if ((fssize = atoi(optarg)) <= 0)
    301 				fatal("%s: bad file system size", optarg);
    302 			break;
    303 		case 't':
    304 			if ((ntracks = atoi(optarg)) <= 0)
    305 				fatal("%s: bad total tracks", optarg);
    306 			break;
    307 		case 'u':
    308 			if ((nsectors = atoi(optarg)) <= 0)
    309 				fatal("%s: bad sectors/track", optarg);
    310 			break;
    311 		case 'x':
    312 			if ((cylspares = atoi(optarg)) < 0)
    313 				fatal("%s: bad spare sectors per cylinder",
    314 				    optarg);
    315 			break;
    316 		case '?':
    317 		default:
    318 			usage();
    319 		}
    320 	argc -= optind;
    321 	argv += optind;
    322 
    323 	if (argc != 2 && (mfs || argc != 1))
    324 		usage();
    325 
    326 	special = argv[0];
    327 	cp = strrchr(special, '/');
    328 	if (cp == 0) {
    329 		/*
    330 		 * No path prefix; try /dev/r%s then /dev/%s.
    331 		 */
    332 		(void)sprintf(device, "%sr%s", _PATH_DEV, special);
    333 		if (stat(device, &st) == -1)
    334 			(void)sprintf(device, "%s%s", _PATH_DEV, special);
    335 		special = device;
    336 	}
    337 	if (Nflag) {
    338 		fso = -1;
    339 	} else {
    340 		fso = open(special, O_WRONLY);
    341 		if (fso < 0)
    342 			fatal("%s: %s", special, strerror(errno));
    343 
    344 		/* Bail if target special is mounted */
    345 		n = getmntinfo(&mp, MNT_NOWAIT);
    346 		if (n == 0)
    347 			fatal("%s: getmntinfo: %s", special, strerror(errno));
    348 
    349 		len = sizeof(_PATH_DEV) - 1;
    350 		s1 = special;
    351 		if (strncmp(_PATH_DEV, s1, len) == 0)
    352 			s1 += len;
    353 
    354 		while (--n >= 0) {
    355 			s2 = mp->f_mntfromname;
    356 			if (strncmp(_PATH_DEV, s2, len) == 0) {
    357 				s2 += len - 1;
    358 				*s2 = 'r';
    359 			}
    360 			if (strcmp(s1, s2) == 0 || strcmp(s1, &s2[1]) == 0)
    361 				fatal("%s is mounted on %s",
    362 				    special, mp->f_mntonname);
    363 			++mp;
    364 		}
    365 	}
    366 	if (mfs && disktype != NULL) {
    367 		lp = (struct disklabel *)getdiskbyname(disktype);
    368 		if (lp == NULL)
    369 			fatal("%s: unknown disk type", disktype);
    370 		pp = &lp->d_partitions[1];
    371 	} else {
    372 		fsi = open(special, O_RDONLY);
    373 		if (fsi < 0)
    374 			fatal("%s: %s", special, strerror(errno));
    375 		if (fstat(fsi, &st) < 0)
    376 			fatal("%s: %s", special, strerror(errno));
    377 		if ((st.st_mode & S_IFMT) != S_IFCHR && !mfs)
    378 			printf("%s: %s: not a character-special device\n",
    379 			    progname, special);
    380 		cp = strchr(argv[0], '\0') - 1;
    381 		if (cp == (char *)-1 ||
    382 		    (*cp < 'a' || *cp > 'h') && !isdigit(*cp))
    383 			fatal("%s: can't figure out file system partition",
    384 			    argv[0]);
    385 #ifdef COMPAT
    386 		if (!mfs && disktype == NULL)
    387 			disktype = argv[1];
    388 #endif
    389 		lp = getdisklabel(special, fsi);
    390 		if (isdigit(*cp))
    391 			pp = &lp->d_partitions[0];
    392 		else
    393 			pp = &lp->d_partitions[*cp - 'a'];
    394 		if (pp->p_size == 0)
    395 			fatal("%s: `%c' partition is unavailable",
    396 			    argv[0], *cp);
    397 		if (pp->p_fstype == FS_BOOT)
    398 			fatal("%s: `%c' partition overlaps boot program",
    399 			      argv[0], *cp);
    400 	}
    401 	if (fssize == 0)
    402 		fssize = pp->p_size;
    403 	if (fssize > pp->p_size && !mfs)
    404 	       fatal("%s: maximum file system size on the `%c' partition is %d",
    405 			argv[0], *cp, pp->p_size);
    406 	if (rpm == 0) {
    407 		rpm = lp->d_rpm;
    408 		if (rpm <= 0)
    409 			rpm = 3600;
    410 	}
    411 	if (ntracks == 0) {
    412 		ntracks = lp->d_ntracks;
    413 		if (ntracks <= 0)
    414 			fatal("%s: no default #tracks", argv[0]);
    415 	}
    416 	if (nsectors == 0) {
    417 		nsectors = lp->d_nsectors;
    418 		if (nsectors <= 0)
    419 			fatal("%s: no default #sectors/track", argv[0]);
    420 	}
    421 	if (sectorsize == 0) {
    422 		sectorsize = lp->d_secsize;
    423 		if (sectorsize <= 0)
    424 			fatal("%s: no default sector size", argv[0]);
    425 	}
    426 	if (trackskew == -1) {
    427 		trackskew = lp->d_trackskew;
    428 		if (trackskew < 0)
    429 			trackskew = 0;
    430 	}
    431 	if (interleave == 0) {
    432 		interleave = lp->d_interleave;
    433 		if (interleave <= 0)
    434 			interleave = 1;
    435 	}
    436 	if (fsize == 0) {
    437 		fsize = pp->p_fsize;
    438 		if (fsize <= 0)
    439 			fsize = MAX(DFL_FRAGSIZE, lp->d_secsize);
    440 	}
    441 	if (bsize == 0) {
    442 		bsize = pp->p_frag * pp->p_fsize;
    443 		if (bsize <= 0)
    444 			bsize = MIN(DFL_BLKSIZE, 8 * fsize);
    445 	}
    446 	/*
    447 	 * Maxcontig sets the default for the maximum number of blocks
    448 	 * that may be allocated sequentially. With filesystem clustering
    449 	 * it is possible to allocate contiguous blocks up to the maximum
    450 	 * transfer size permitted by the controller or buffering.
    451 	 */
    452 	if (maxcontig == 0)
    453 		maxcontig = MAX(1, MIN(MAXPHYS, MAXBSIZE) / bsize);
    454 	if (density == 0)
    455 		density = NFPI * fsize;
    456 	if (minfree < MINFREE && opt != FS_OPTSPACE) {
    457 		fprintf(stderr, "Warning: changing optimization to space ");
    458 		fprintf(stderr, "because minfree is less than %d%%\n", MINFREE);
    459 		opt = FS_OPTSPACE;
    460 	}
    461 	if (trackspares == -1) {
    462 		trackspares = lp->d_sparespertrack;
    463 		if (trackspares < 0)
    464 			trackspares = 0;
    465 	}
    466 	nphyssectors = nsectors + trackspares;
    467 	if (cylspares == -1) {
    468 		cylspares = lp->d_sparespercyl;
    469 		if (cylspares < 0)
    470 			cylspares = 0;
    471 	}
    472 	secpercyl = nsectors * ntracks - cylspares;
    473 	if (secpercyl != lp->d_secpercyl)
    474 		fprintf(stderr, "%s (%d) %s (%lu)\n",
    475 			"Warning: calculated sectors per cylinder", secpercyl,
    476 			"disagrees with disk label", lp->d_secpercyl);
    477 	if (maxbpg == 0)
    478 		maxbpg = MAXBLKPG(bsize);
    479 	headswitch = lp->d_headswitch;
    480 	trackseek = lp->d_trkseek;
    481 #ifdef notdef /* label may be 0 if faked up by kernel */
    482 	bbsize = lp->d_bbsize;
    483 	sbsize = lp->d_sbsize;
    484 #endif
    485 	oldpartition = *pp;
    486 #ifdef tahoe
    487 	realsectorsize = sectorsize;
    488 	if (sectorsize != DEV_BSIZE) {		/* XXX */
    489 		int secperblk = DEV_BSIZE / sectorsize;
    490 
    491 		sectorsize = DEV_BSIZE;
    492 		nsectors /= secperblk;
    493 		nphyssectors /= secperblk;
    494 		secpercyl /= secperblk;
    495 		fssize /= secperblk;
    496 		pp->p_size /= secperblk;
    497 	}
    498 #endif
    499 	mkfs(pp, special, fsi, fso);
    500 #ifdef tahoe
    501 	if (realsectorsize != DEV_BSIZE)
    502 		pp->p_size *= DEV_BSIZE / realsectorsize;
    503 #endif
    504 	if (!Nflag && memcmp(pp, &oldpartition, sizeof(oldpartition)))
    505 		rewritelabel(special, fso, lp);
    506 	if (!Nflag)
    507 		close(fso);
    508 	close(fsi);
    509 #ifdef MFS
    510 	if (mfs) {
    511 		struct mfs_args args;
    512 
    513 		sprintf(buf, "mfs:%d", getpid());
    514 		args.fspec = buf;
    515 		args.export.ex_root = -2;
    516 		if (mntflags & MNT_RDONLY)
    517 			args.export.ex_flags = MNT_EXRDONLY;
    518 		else
    519 			args.export.ex_flags = 0;
    520 		args.base = membase;
    521 		args.size = fssize * sectorsize;
    522 		if (mount("mfs", argv[1], mntflags, &args) < 0)
    523 			fatal("%s: %s", argv[1], strerror(errno));
    524 	}
    525 #endif
    526 	exit(0);
    527 }
    528 
    529 #ifdef COMPAT
    530 char lmsg[] = "%s: can't read disk label; disk type must be specified";
    531 #else
    532 char lmsg[] = "%s: can't read disk label";
    533 #endif
    534 
    535 struct disklabel *
    536 getdisklabel(s, fd)
    537 	char *s;
    538 	int fd;
    539 {
    540 	static struct disklabel lab;
    541 
    542 	if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) {
    543 #ifdef COMPAT
    544 		if (disktype) {
    545 			struct disklabel *lp, *getdiskbyname();
    546 
    547 			unlabeled++;
    548 			lp = getdiskbyname(disktype);
    549 			if (lp == NULL)
    550 				fatal("%s: unknown disk type", disktype);
    551 			return (lp);
    552 		}
    553 #endif
    554 		warn("ioctl (GDINFO)");
    555 		fatal(lmsg, s);
    556 	}
    557 	return (&lab);
    558 }
    559 
    560 rewritelabel(s, fd, lp)
    561 	char *s;
    562 	int fd;
    563 	register struct disklabel *lp;
    564 {
    565 #ifdef COMPAT
    566 	if (unlabeled)
    567 		return;
    568 #endif
    569 	lp->d_checksum = 0;
    570 	lp->d_checksum = dkcksum(lp);
    571 	if (ioctl(fd, DIOCWDINFO, (char *)lp) < 0) {
    572 		warn("ioctl (WDINFO)");
    573 		fatal("%s: can't rewrite disk label", s);
    574 	}
    575 #if vax
    576 	if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) {
    577 		register i;
    578 		int cfd;
    579 		daddr_t alt;
    580 		char specname[64];
    581 		char blk[1024];
    582 		char *cp;
    583 
    584 		/*
    585 		 * Make name for 'c' partition.
    586 		 */
    587 		strcpy(specname, s);
    588 		cp = specname + strlen(specname) - 1;
    589 		if (!isdigit(*cp))
    590 			*cp = 'c';
    591 		cfd = open(specname, O_WRONLY);
    592 		if (cfd < 0)
    593 			fatal("%s: %s", specname, strerror(errno));
    594 		memset(blk, 0, sizeof(blk));
    595 		*(struct disklabel *)(blk + LABELOFFSET) = *lp;
    596 		alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors;
    597 		for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) {
    598 			if (lseek(cfd, (off_t)(alt + i) * lp->d_secsize,
    599 			    L_SET) == -1)
    600 				fatal("lseek to badsector area: %s",
    601 				    strerror(errno));
    602 			if (write(cfd, blk, lp->d_secsize) < lp->d_secsize)
    603 				warn("alternate label %d write", i/2);
    604 		}
    605 		close(cfd);
    606 	}
    607 #endif
    608 }
    609 
    610 /*VARARGS*/
    611 void
    612 #if __STDC__
    613 fatal(const char *fmt, ...)
    614 #else
    615 fatal(fmt, va_alist)
    616 	char *fmt;
    617 	va_dcl
    618 #endif
    619 {
    620 	va_list ap;
    621 
    622 #if __STDC__
    623 	va_start(ap, fmt);
    624 #else
    625 	va_start(ap);
    626 #endif
    627 	if (fcntl(STDERR_FILENO, F_GETFL) < 0) {
    628 		openlog(progname, LOG_CONS, LOG_DAEMON);
    629 		vsyslog(LOG_ERR, fmt, ap);
    630 		closelog();
    631 	} else {
    632 		vwarnx(fmt, ap);
    633 	}
    634 	va_end(ap);
    635 	exit(1);
    636 	/*NOTREACHED*/
    637 }
    638 
    639 usage()
    640 {
    641 	if (mfs) {
    642 		fprintf(stderr,
    643 		    "usage: %s [ -fsoptions ] special-device mount-point\n",
    644 			progname);
    645 	} else
    646 		fprintf(stderr,
    647 		    "usage: %s [ -fsoptions ] special-device%s\n",
    648 		    progname,
    649 #ifdef COMPAT
    650 		    " [device-type]");
    651 #else
    652 		    "");
    653 #endif
    654 	fprintf(stderr, "where fsoptions are:\n");
    655 	fprintf(stderr,
    656 	    "\t-N do not create file system, just print out parameters\n");
    657 	fprintf(stderr, "\t-O create a 4.3BSD format filesystem\n");
    658 	fprintf(stderr, "\t-S sector size\n");
    659 #ifdef COMPAT
    660 	fprintf(stderr, "\t-T disktype\n");
    661 #endif
    662 	fprintf(stderr, "\t-a maximum contiguous blocks\n");
    663 	fprintf(stderr, "\t-b block size\n");
    664 	fprintf(stderr, "\t-c cylinders/group\n");
    665 	fprintf(stderr, "\t-d rotational delay between contiguous blocks\n");
    666 	fprintf(stderr, "\t-e maximum blocks per file in a cylinder group\n");
    667 	fprintf(stderr, "\t-f frag size\n");
    668 	fprintf(stderr, "\t-i number of bytes per inode\n");
    669 	fprintf(stderr, "\t-k sector 0 skew, per track\n");
    670 	fprintf(stderr, "\t-l hardware sector interleave\n");
    671 	fprintf(stderr, "\t-m minimum free space %%\n");
    672 	fprintf(stderr, "\t-n number of distinguished rotational positions\n");
    673 	fprintf(stderr, "\t-o optimization preference (`space' or `time')\n");
    674 	fprintf(stderr, "\t-p spare sectors per track\n");
    675 	fprintf(stderr, "\t-s file system size (sectors)\n");
    676 	fprintf(stderr, "\t-r revolutions/minute\n");
    677 	fprintf(stderr, "\t-t tracks/cylinder\n");
    678 	fprintf(stderr, "\t-u sectors/track\n");
    679 	fprintf(stderr, "\t-x spare sectors per cylinder\n");
    680 	exit(1);
    681 }
    682