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