xref: /openbsd-src/sbin/newfs/newfs.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*	$OpenBSD: newfs.c,v 1.28 2001/07/07 18:26:16 deraadt Exp $	*/
2 /*	$NetBSD: newfs.c,v 1.20 1996/05/16 07:13:03 thorpej Exp $	*/
3 
4 /*
5  * Copyright (c) 1983, 1989, 1993, 1994
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #ifndef lint
38 static char copyright[] =
39 "@(#) Copyright (c) 1983, 1989, 1993, 1994\n\
40 	The Regents of the University of California.  All rights reserved.\n";
41 #endif /* not lint */
42 
43 #ifndef lint
44 #if 0
45 static char sccsid[] = "@(#)newfs.c	8.8 (Berkeley) 4/18/94";
46 #else
47 static char rcsid[] = "$OpenBSD: newfs.c,v 1.28 2001/07/07 18:26:16 deraadt Exp $";
48 #endif
49 #endif /* not lint */
50 
51 /*
52  * newfs: friendly front end to mkfs
53  */
54 #include <sys/param.h>
55 #include <sys/stat.h>
56 #include <sys/ioctl.h>
57 #include <sys/disklabel.h>
58 #include <sys/mount.h>
59 #include <sys/sysctl.h>
60 
61 #include <ufs/ufs/dir.h>
62 #include <ufs/ffs/fs.h>
63 
64 #include <ctype.h>
65 #include <errno.h>
66 #include <fcntl.h>
67 #include <paths.h>
68 #include <stdio.h>
69 #include <stdlib.h>
70 #include <string.h>
71 #include <syslog.h>
72 #include <unistd.h>
73 #include <util.h>
74 #include <err.h>
75 
76 #ifdef __STDC__
77 #include <stdarg.h>
78 #else
79 #include <varargs.h>
80 #endif
81 
82 #include "mntopts.h"
83 #include "pathnames.h"
84 
85 struct mntopt mopts[] = {
86 	MOPT_STDOPTS,
87 	MOPT_ASYNC,
88 	MOPT_UPDATE,
89 	{ NULL },
90 };
91 
92 void	fatal __P((const char *fmt, ...));
93 void	usage __P((void));
94 void	mkfs __P((struct partition *, char *, int, int));
95 void	rewritelabel __P((char *, int, struct disklabel *));
96 u_short	dkcksum __P((struct disklabel *));
97 
98 #define	COMPAT			/* allow non-labeled disks */
99 
100 /*
101  * The following two constants set the default block and fragment sizes.
102  * Both constants must be a power of 2 and meet the following constraints:
103  *	MINBSIZE <= DESBLKSIZE <= MAXBSIZE
104  *	sectorsize <= DESFRAGSIZE <= DESBLKSIZE
105  *	DESBLKSIZE / DESFRAGSIZE <= 8
106  */
107 #define	DFL_FRAGSIZE	1024
108 #define	DFL_BLKSIZE	8192
109 
110 /*
111  * Cylinder groups may have up to many cylinders. The actual
112  * number used depends upon how much information can be stored
113  * on a single cylinder. The default is to use 16 cylinders
114  * per group.
115  */
116 #define	DESCPG		16	/* desired fs_cpg */
117 
118 /*
119  * ROTDELAY gives the minimum number of milliseconds to initiate
120  * another disk transfer on the same cylinder. It is used in
121  * determining the rotationally optimal layout for disk blocks
122  * within a file; the default of fs_rotdelay is 0ms.
123  */
124 #define ROTDELAY	0
125 
126 /*
127  * MAXBLKPG determines the maximum number of data blocks which are
128  * placed in a single cylinder group. The default is one indirect
129  * block worth of data blocks.
130  */
131 #define MAXBLKPG(bsize)	((bsize) / sizeof(daddr_t))
132 
133 /*
134  * Each file system has a number of inodes statically allocated.
135  * We allocate one inode slot per NFPI fragments, expecting this
136  * to be far more than we will ever need.
137  */
138 #define	NFPI		4
139 
140 /*
141  * For each cylinder we keep track of the availability of blocks at different
142  * rotational positions, so that we can lay out the data to be picked
143  * up with minimum rotational latency.  NRPOS is the default number of
144  * rotational positions that we distinguish.  With NRPOS of 8 the resolution
145  * of our summary information is 2ms for a typical 3600 rpm drive.  Caching
146  * and zoning pretty much defeats rotational optimization, so we now use a
147  * default of 1.
148  */
149 #define	NRPOS		1	/* number distinct rotational positions */
150 
151 
152 int	mfs;			/* run as the memory based filesystem */
153 int	Nflag;			/* run without writing file system */
154 int	Oflag;			/* format as an 4.3BSD file system */
155 int	fssize;			/* file system size */
156 int	ntracks;		/* # tracks/cylinder */
157 int	nsectors;		/* # sectors/track */
158 int	nphyssectors;		/* # sectors/track including spares */
159 int	secpercyl;		/* sectors per cylinder */
160 int	trackspares = -1;	/* spare sectors per track */
161 int	cylspares = -1;		/* spare sectors per cylinder */
162 int	sectorsize;		/* bytes/sector */
163 int	realsectorsize;		/* bytes/sector in hardware */
164 int	rpm;			/* revolutions/minute of drive */
165 int	interleave;		/* hardware sector interleave */
166 int	trackskew = -1;		/* sector 0 skew, per track */
167 int	fsize = 0;		/* fragment size */
168 int	bsize = 0;		/* block size */
169 int	cpg = DESCPG;		/* cylinders/cylinder group */
170 int	cpgflg;			/* cylinders/cylinder group flag was given */
171 int	minfree = MINFREE;	/* free space threshold */
172 int	opt = DEFAULTOPT;	/* optimization preference (space or time) */
173 int	reqopt = -1;		/* opt preference has not been specified */
174 int	density;		/* number of bytes per inode */
175 int	maxcontig = 8;		/* max contiguous blocks to allocate */
176 int	rotdelay = ROTDELAY;	/* rotational delay between blocks */
177 int	maxbpg;			/* maximum blocks per file in a cyl group */
178 int	nrpos = NRPOS;		/* # of distinguished rotational positions */
179 int	avgfilesize = AVFILESIZ;/* expected average file size */
180 int	avgfilesperdir = AFPDIR;/* expected number of files per directory */
181 int	bbsize = BBSIZE;	/* boot block size */
182 int	sbsize = SBSIZE;	/* superblock size */
183 int	mntflags = MNT_ASYNC;	/* flags to be passed to mount */
184 int	quiet = 0;		/* quiet flag */
185 u_long	memleft;		/* virtual memory available */
186 caddr_t	membase;		/* start address of memory based filesystem */
187 #ifdef COMPAT
188 char	*disktype;
189 int	unlabeled;
190 #endif
191 
192 char	device[MAXPATHLEN];
193 
194 extern	char *__progname;
195 
196 int
197 main(argc, argv)
198 	int argc;
199 	char *argv[];
200 {
201 	register int ch;
202 	register struct partition *pp;
203 	register struct disklabel *lp;
204 	struct disklabel mfsfakelabel;
205 	struct disklabel *getdisklabel();
206 	struct partition oldpartition;
207 	struct stat st;
208 	struct statfs *mp;
209 	int fsi = -1, fso, len, n, maxpartitions;
210 	char *cp, *s1, *s2, *special, *opstring, buf[BUFSIZ];
211 	char *fstype = NULL;
212 	char **saveargv = argv;
213 	int ffs = 1;
214 
215 	if (strstr(__progname, "mfs"))
216 		mfs = Nflag = quiet = 1;
217 
218 	maxpartitions = getmaxpartitions();
219 	if (maxpartitions > 26)
220 		fatal("insane maxpartitions value %d", maxpartitions);
221 
222 	opstring = mfs ?
223 	    "NT:a:b:c:d:e:f:i:m:o:s:" :
224 	    "NOS:T:a:b:c:d:e:f:g:h:i:k:l:m:n:o:p:qr:s:t:u:x:z:";
225 	while ((ch = getopt(argc, argv, opstring)) != -1) {
226 		switch (ch) {
227 		case 'N':
228 			Nflag = 1;
229 			break;
230 		case 'O':
231 			Oflag = 1;
232 			break;
233 		case 'S':
234 			if ((sectorsize = atoi(optarg)) <= 0)
235 				fatal("%s: bad sector size", optarg);
236 			break;
237 #ifdef COMPAT
238 		case 'T':
239 			disktype = optarg;
240 			break;
241 #endif
242 		case 'a':
243 			if ((maxcontig = atoi(optarg)) <= 0)
244 				fatal("%s: bad maximum contiguous blocks\n",
245 				    optarg);
246 			break;
247 		case 'b':
248 			if ((bsize = atoi(optarg)) < MINBSIZE)
249 				fatal("%s: bad block size", optarg);
250 			break;
251 		case 'c':
252 			if ((cpg = atoi(optarg)) <= 0)
253 				fatal("%s: bad cylinders/group", optarg);
254 			cpgflg++;
255 			break;
256 		case 'd':
257 			if ((rotdelay = atoi(optarg)) < 0)
258 				fatal("%s: bad rotational delay\n", optarg);
259 			break;
260 		case 'e':
261 			if ((maxbpg = atoi(optarg)) <= 0)
262 		fatal("%s: bad blocks per file in a cylinder group\n",
263 				    optarg);
264 			break;
265 		case 'f':
266 			if ((fsize = atoi(optarg)) <= 0)
267 				fatal("%s: bad fragment size", optarg);
268 			break;
269 		case 'g':
270 			if ((avgfilesize = atoi(optarg)) <= 0)
271 			       fatal("%s: bad average file size", optarg);
272 			break;
273 		case 'h':
274 			if ((avgfilesperdir = atoi(optarg)) <= 0)
275 				fatal("%s: bad average files per dir", optarg);
276 			break;
277 		case 'i':
278 			if ((density = atoi(optarg)) <= 0)
279 				fatal("%s: bad bytes per inode\n", optarg);
280 			break;
281 		case 'k':
282 			if ((trackskew = atoi(optarg)) < 0)
283 				fatal("%s: bad track skew", optarg);
284 			break;
285 		case 'l':
286 			if ((interleave = atoi(optarg)) <= 0)
287 				fatal("%s: bad interleave", optarg);
288 			break;
289 		case 'm':
290 			if ((minfree = atoi(optarg)) < 0 || minfree > 99)
291 				fatal("%s: bad free space %%\n", optarg);
292 			break;
293 		case 'n':
294 			if ((nrpos = atoi(optarg)) <= 0)
295 				fatal("%s: bad rotational layout count\n",
296 				    optarg);
297 			break;
298 		case 'o':
299 			if (mfs)
300 				getmntopts(optarg, mopts, &mntflags);
301 			else {
302 				if (strcmp(optarg, "space") == 0)
303 					reqopt = opt = FS_OPTSPACE;
304 				else if (strcmp(optarg, "time") == 0)
305 					reqopt = opt = FS_OPTTIME;
306 				else
307 	fatal("%s: unknown optimization preference: use `space' or `time'.");
308 			}
309 			break;
310 		case 'p':
311 			if ((trackspares = atoi(optarg)) < 0)
312 				fatal("%s: bad spare sectors per track",
313 				    optarg);
314 			break;
315 		case 'q':
316 			quiet = 1;
317 			break;
318 		case 'r':
319 			if ((rpm = atoi(optarg)) <= 0)
320 				fatal("%s: bad revolutions/minute\n", optarg);
321 			break;
322 		case 's':
323 			if ((fssize = atoi(optarg)) <= 0)
324 				fatal("%s: bad file system size", optarg);
325 			break;
326 		case 'z':
327 			if ((ntracks = atoi(optarg)) <= 0)
328 				fatal("%s: bad total tracks", optarg);
329 			break;
330 		case 't':
331 			fstype = optarg;
332 			if (strcmp(fstype, "ffs"))
333 				ffs = 0;
334 			break;
335 		case 'u':
336 			if ((nsectors = atoi(optarg)) <= 0)
337 				fatal("%s: bad sectors/track", optarg);
338 			break;
339 		case 'x':
340 			if ((cylspares = atoi(optarg)) < 0)
341 				fatal("%s: bad spare sectors per cylinder",
342 				    optarg);
343 			break;
344 		case '?':
345 		default:
346 			usage();
347 		}
348 		if (!ffs)
349 			break;
350 	}
351 	argc -= optind;
352 	argv += optind;
353 
354 	if (ffs && argc - mfs != 1)
355 		usage();
356 
357 	special = argv[0];
358 	if (!mfs) {
359 		char execname[MAXPATHLEN], name[MAXPATHLEN];
360 
361 		if (fstype == NULL)
362 			fstype = readlabelfs(special, 0);
363 		if (fstype != NULL && strcmp(fstype, "ffs")) {
364 			snprintf(name, sizeof name, "newfs_%s", fstype);
365 			saveargv[0] = name;
366 			snprintf(execname, sizeof execname, "%s/newfs_%s",
367 			    _PATH_SBIN, fstype);
368 			(void)execv(execname, saveargv);
369 			snprintf(execname, sizeof execname, "%s/newfs_%s",
370 			    _PATH_USRSBIN, fstype);
371 			(void)execv(execname, saveargv);
372 			err(1, "%s not found", name);
373 		}
374 	}
375 
376 	if (mfs && !strcmp(special, "swap")) {
377 		/*
378 		 * it's an MFS, mounted on "swap."  fake up a label.
379 		 * XXX XXX XXX
380 		 */
381 		fso = -1;	/* XXX; normally done below. */
382 
383 		memset(&mfsfakelabel, 0, sizeof(mfsfakelabel));
384 		mfsfakelabel.d_secsize = 512;
385 		mfsfakelabel.d_nsectors = 64;
386 		mfsfakelabel.d_ntracks = 16;
387 		mfsfakelabel.d_ncylinders = 16;
388 		mfsfakelabel.d_secpercyl = 1024;
389 		mfsfakelabel.d_secperunit = 16384;
390 		mfsfakelabel.d_rpm = 3600;
391 		mfsfakelabel.d_interleave = 1;
392 		mfsfakelabel.d_npartitions = 1;
393 		mfsfakelabel.d_partitions[0].p_size = 16384;
394 		mfsfakelabel.d_partitions[0].p_fsize = 1024;
395 		mfsfakelabel.d_partitions[0].p_frag = 8;
396 		mfsfakelabel.d_partitions[0].p_cpg = 16;
397 
398 		lp = &mfsfakelabel;
399 		pp = &mfsfakelabel.d_partitions[0];
400 
401 		goto havelabel;
402 	}
403 	cp = strrchr(special, '/');
404 	if (cp == NULL) {
405 		/*
406 		 * No path prefix; try /dev/r%s then /dev/%s.
407 		 */
408 		(void)snprintf(device, sizeof(device), "%sr%s",
409 			       _PATH_DEV, special);
410 		if (stat(device, &st) == -1)
411 			(void)snprintf(device, sizeof(device), "%s%s",
412 				       _PATH_DEV, special);
413 		special = device;
414 	}
415 	if (Nflag) {
416 		fso = -1;
417 	} else {
418 		fso = open(special, O_WRONLY);
419 		if (fso < 0)
420 			fatal("%s: %s", special, strerror(errno));
421 
422 		/* Bail if target special is mounted */
423 		n = getmntinfo(&mp, MNT_NOWAIT);
424 		if (n == 0)
425 			fatal("%s: getmntinfo: %s", special, strerror(errno));
426 
427 		len = sizeof(_PATH_DEV) - 1;
428 		s1 = special;
429 		if (strncmp(_PATH_DEV, s1, len) == 0)
430 			s1 += len;
431 
432 		while (--n >= 0) {
433 			s2 = mp->f_mntfromname;
434 			if (strncmp(_PATH_DEV, s2, len) == 0) {
435 				s2 += len - 1;
436 				*s2 = 'r';
437 			}
438 			if (strcmp(s1, s2) == 0 || strcmp(s1, &s2[1]) == 0)
439 				fatal("%s is mounted on %s",
440 				    special, mp->f_mntonname);
441 			++mp;
442 		}
443 	}
444 #ifdef COMPAT
445 	if (mfs && disktype != NULL) {
446 		lp = (struct disklabel *)getdiskbyname(disktype);
447 		if (lp == NULL)
448 			fatal("%s: unknown disk type", disktype);
449 		pp = &lp->d_partitions[1];
450 	} else
451 #endif
452 	{
453 		fsi = open(special, O_RDONLY);
454 		if (fsi < 0)
455 			fatal("%s: %s", special, strerror(errno));
456 		if (fstat(fsi, &st) < 0)
457 			fatal("%s: %s", special, strerror(errno));
458 		if (!S_ISCHR(st.st_mode) && !mfs)
459 			printf("%s: %s: not a character-special device\n",
460 			    __progname, special);
461 		cp = strchr(argv[0], '\0') - 1;
462 		if (cp == 0 || ((*cp < 'a' || *cp > ('a' + maxpartitions - 1))
463 		    && !isdigit(*cp)))
464 			fatal("%s: can't figure out file system partition",
465 			    argv[0]);
466 		lp = getdisklabel(special, fsi);
467 		if (isdigit(*cp))
468 			pp = &lp->d_partitions[0];
469 		else
470 			pp = &lp->d_partitions[*cp - 'a'];
471 		if (pp->p_size == 0)
472 			fatal("%s: `%c' partition is unavailable",
473 			    argv[0], *cp);
474 		if (pp->p_fstype == FS_BOOT)
475 			fatal("%s: `%c' partition overlaps boot program",
476 			      argv[0], *cp);
477 	}
478 havelabel:
479 	if (fssize == 0)
480 		fssize = pp->p_size;
481 	if (fssize > pp->p_size && !mfs)
482 	       fatal("%s: maximum file system size on the `%c' partition is %d",
483 			argv[0], *cp, pp->p_size);
484 	if (rpm == 0) {
485 		rpm = lp->d_rpm;
486 		if (rpm <= 0)
487 			rpm = 3600;
488 	}
489 	if (ntracks == 0) {
490 		ntracks = lp->d_ntracks;
491 		if (ntracks <= 0)
492 			fatal("%s: no default #tracks", argv[0]);
493 	}
494 	if (nsectors == 0) {
495 		nsectors = lp->d_nsectors;
496 		if (nsectors <= 0)
497 			fatal("%s: no default #sectors/track", argv[0]);
498 	}
499 	if (sectorsize == 0) {
500 		sectorsize = lp->d_secsize;
501 		if (sectorsize <= 0)
502 			fatal("%s: no default sector size", argv[0]);
503 	}
504 	if (trackskew == -1) {
505 		trackskew = lp->d_trackskew;
506 		if (trackskew < 0)
507 			trackskew = 0;
508 	}
509 	if (interleave == 0) {
510 		interleave = lp->d_interleave;
511 		if (interleave <= 0)
512 			interleave = 1;
513 	}
514 	if (fsize == 0) {
515 		fsize = pp->p_fsize;
516 		if (fsize <= 0)
517 			fsize = MAX(DFL_FRAGSIZE, lp->d_secsize);
518 	}
519 	if (bsize == 0) {
520 		bsize = pp->p_frag * pp->p_fsize;
521 		if (bsize <= 0)
522 			bsize = MIN(DFL_BLKSIZE, 8 * fsize);
523 	}
524 	/*
525 	 * Maxcontig sets the default for the maximum number of blocks
526 	 * that may be allocated sequentially. With filesystem clustering
527 	 * it is possible to allocate contiguous blocks up to the maximum
528 	 * transfer size permitted by the controller or buffering.
529 	 */
530 	if (maxcontig == 0)
531 		maxcontig = MAX(1, MIN(MAXPHYS, MAXBSIZE) / bsize - 1);
532 	if (density == 0)
533 		density = NFPI * fsize;
534 	if (minfree < MINFREE && opt != FS_OPTSPACE && reqopt == -1) {
535 		fprintf(stderr, "Warning: changing optimization to space ");
536 		fprintf(stderr, "because minfree is less than %d%%\n", MINFREE);
537 		opt = FS_OPTSPACE;
538 	}
539 	if (trackspares == -1) {
540 		trackspares = lp->d_sparespertrack;
541 		if (trackspares < 0)
542 			trackspares = 0;
543 	}
544 	nphyssectors = nsectors + trackspares;
545 	if (cylspares == -1) {
546 		cylspares = lp->d_sparespercyl;
547 		if (cylspares < 0)
548 			cylspares = 0;
549 	}
550 	secpercyl = nsectors * ntracks - cylspares;
551 	if (secpercyl != lp->d_secpercyl)
552 		fprintf(stderr, "%s (%d) %s (%lu)\n",
553 		    "Warning: calculated sectors per cylinder", secpercyl,
554 		    "disagrees with disk label",
555 		    (unsigned long)lp->d_secpercyl);
556 	if (maxbpg == 0)
557 		maxbpg = MAXBLKPG(bsize);
558 #ifdef notdef /* label may be 0 if faked up by kernel */
559 	bbsize = lp->d_bbsize;
560 	sbsize = lp->d_sbsize;
561 #endif
562 	oldpartition = *pp;
563 	realsectorsize = sectorsize;
564 	if (sectorsize < DEV_BSIZE) {
565 		int secperblk = DEV_BSIZE / sectorsize;
566 
567 		sectorsize = DEV_BSIZE;
568 		nsectors /= secperblk;
569 		nphyssectors /= secperblk;
570 		secpercyl /= secperblk;
571 		fssize /= secperblk;
572 		pp->p_size /= secperblk;
573 	} else if (sectorsize > DEV_BSIZE) {
574 		int blkpersec = sectorsize / DEV_BSIZE;
575 
576 		sectorsize = DEV_BSIZE;
577 		nsectors *= blkpersec;
578 		nphyssectors *= blkpersec;
579 		secpercyl *= blkpersec;
580 		fssize *= blkpersec;
581 		pp->p_size *= blkpersec;
582 	}
583 	mkfs(pp, special, fsi, fso);
584 	if (realsectorsize < DEV_BSIZE)
585 		pp->p_size *= DEV_BSIZE / realsectorsize;
586 	else if (realsectorsize > DEV_BSIZE)
587 		pp->p_size /= realsectorsize / DEV_BSIZE;
588 	if (!Nflag && memcmp(pp, &oldpartition, sizeof(oldpartition)))
589 		rewritelabel(special, fso, lp);
590 	if (!Nflag)
591 		close(fso);
592 	close(fsi);
593 #ifdef MFS
594 	if (mfs) {
595 		struct mfs_args args;
596 
597 		sprintf(buf, "mfs:%d", getpid());
598 		args.fspec = buf;
599 		args.export.ex_root = -2;
600 		if (mntflags & MNT_RDONLY)
601 			args.export.ex_flags = MNT_EXRDONLY;
602 		else
603 			args.export.ex_flags = 0;
604 		args.base = membase;
605 		args.size = fssize * sectorsize;
606 		if (mount(MOUNT_MFS, argv[1], mntflags, &args) < 0)
607 			fatal("%s: %s", argv[1], strerror(errno));
608 	}
609 #endif
610 	exit(0);
611 }
612 
613 #ifdef COMPAT
614 char lmsg[] = "%s: can't read disk label; disk type must be specified";
615 #else
616 char lmsg[] = "%s: can't read disk label";
617 #endif
618 
619 struct disklabel *
620 getdisklabel(s, fd)
621 	char *s;
622 	int fd;
623 {
624 	static struct disklabel lab;
625 
626 	if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) {
627 #ifdef COMPAT
628 		if (disktype) {
629 			struct disklabel *lp, *getdiskbyname();
630 
631 			unlabeled++;
632 			lp = getdiskbyname(disktype);
633 			if (lp == NULL)
634 				fatal("%s: unknown disk type", disktype);
635 			return (lp);
636 		}
637 #endif
638 		warn("ioctl (GDINFO)");
639 		fatal(lmsg, s);
640 	}
641 	return (&lab);
642 }
643 
644 void
645 rewritelabel(s, fd, lp)
646 	char *s;
647 	int fd;
648 	register struct disklabel *lp;
649 {
650 #ifdef COMPAT
651 	if (unlabeled)
652 		return;
653 #endif
654 	lp->d_checksum = 0;
655 	lp->d_checksum = dkcksum(lp);
656 	if (ioctl(fd, DIOCWDINFO, (char *)lp) < 0) {
657 		warn("ioctl (WDINFO)");
658 		fatal("%s: can't rewrite disk label", s);
659 	}
660 #ifdef __vax__
661 	if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) {
662 		register i;
663 		int cfd;
664 		daddr_t alt;
665 		char specname[64];
666 		char blk[1024];
667 		char *cp;
668 
669 		/*
670 		 * Make name for 'c' partition.
671 		 */
672 		strncpy(specname, s, sizeof(specname) - 1);
673 		specname[sizeof(specname) - 1] = '\0';
674 		cp = specname + strlen(specname) - 1;
675 		if (!isdigit(*cp))
676 			*cp = 'c';
677 		cfd = open(specname, O_WRONLY);
678 		if (cfd < 0)
679 			fatal("%s: %s", specname, strerror(errno));
680 		memset(blk, 0, sizeof(blk));
681 		*(struct disklabel *)(blk + LABELOFFSET) = *lp;
682 		alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors;
683 		for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) {
684 			off_t offset;
685 
686 			offset = alt + i;
687 			offset *= lp->d_secsize;
688 			if (lseek(cfd, offset, SEEK_SET) == -1)
689 				fatal("lseek to badsector area: %s",
690 				    strerror(errno));
691 			if (write(cfd, blk, lp->d_secsize) < lp->d_secsize)
692 				warn("alternate label %d write", i/2);
693 		}
694 		close(cfd);
695 	}
696 #endif	/*__vax__*/
697 }
698 
699 /*VARARGS*/
700 void
701 #ifdef __STDC__
702 fatal(const char *fmt, ...)
703 #else
704 fatal(fmt, va_alist)
705 	char *fmt;
706 	va_dcl
707 #endif
708 {
709 	va_list ap;
710 
711 #ifdef __STDC__
712 	va_start(ap, fmt);
713 #else
714 	va_start(ap);
715 #endif
716 	if (fcntl(STDERR_FILENO, F_GETFL) < 0) {
717 		openlog(__progname, LOG_CONS, LOG_DAEMON);
718 		vsyslog(LOG_ERR, fmt, ap);
719 		closelog();
720 	} else {
721 		vwarnx(fmt, ap);
722 	}
723 	va_end(ap);
724 	exit(1);
725 	/*NOTREACHED*/
726 }
727 
728 struct fsoptions {
729 	char *str;
730 	int mfs_too;
731 } fsopts[] = {
732 	{ "-N do not create file system, just print out parameters", 1 },
733 	{ "-O create a 4.3BSD format filesystem", 0 },
734 	{ "-S sector size", 0 },
735 #ifdef COMPAT
736 	{ "-T disktype", 0 },
737 #endif
738 	{ "-a maximum contiguous blocks", 1 },
739 	{ "-b block size", 1 },
740 	{ "-c cylinders/group", 1 },
741 	{ "-d rotational delay between contiguous blocks", 1 },
742 	{ "-e maximum blocks per file in a cylinder group", 1 },
743 	{ "-f frag size", 1 },
744 	{ "-g average file size", 0 },
745 	{ "-h average files per directory", 0 },
746 	{ "-i number of bytes per inode", 1 },
747 	{ "-k sector 0 skew, per track", 0 },
748 	{ "-l hardware sector interleave", 0 },
749 	{ "-m minimum free space %%", 1 },
750 	{ "-n number of distinguished rotational positions", 0 },
751 	{ "-o optimization preference (`space' or `time')", 1 },
752 	{ "-p spare sectors per track", 0 },
753 	{ "-r revolutions/minute", 0 },
754 	{ "-s file system size (sectors)", 1 },
755 	{ "-t file system type", 0 },
756 	{ "-u sectors/track", 0 },
757 	{ "-x spare sectors per cylinder", 0 },
758 	{ "-z tracks/cylinder", 0 },
759 	{ NULL, NULL }
760 };
761 
762 void
763 usage()
764 {
765 	struct fsoptions *fsopt;
766 
767 	if (mfs) {
768 		fprintf(stderr,
769 		    "usage: %s [ -fsoptions ] special-device mount-point\n",
770 			__progname);
771 	} else {
772 		fprintf(stderr,
773 		    "usage: %s [ -fsoptions ] special-device\n", __progname);
774 	}
775 	fprintf(stderr, "where fsoptions are:\n");
776 	for (fsopt = fsopts; fsopt->str; fsopt++) {
777 		if (!mfs || fsopt->mfs_too)
778 			fprintf(stderr, "\t%s\n", fsopt->str);
779 	}
780 	exit(1);
781 }
782