xref: /original-bsd/sbin/newfs/newfs.c (revision fb9118b1)
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 char copyright[] =
9 "@(#) Copyright (c) 1983 Regents of the University of California.\n\
10  All rights reserved.\n";
11 #endif not lint
12 
13 #ifndef lint
14 static char sccsid[] = "@(#)newfs.c	6.8 (Berkeley) 05/08/87";
15 #endif not lint
16 
17 /*
18  * newfs: friendly front end to mkfs
19  */
20 #include <sys/param.h>
21 #include <sys/stat.h>
22 #include <sys/fs.h>
23 #include <sys/dir.h>
24 #include <sys/ioctl.h>
25 #include <sys/disklabel.h>
26 #include <sys/file.h>
27 
28 #include <stdio.h>
29 #include <ctype.h>
30 
31 /*
32  * The following two constants set the default block and fragment sizes.
33  * Both constants must be a power of 2 and meet the following constraints:
34  *	MINBSIZE <= DESBLKSIZE <= MAXBSIZE
35  *	sectorsize <= DESFRAGSIZE <= DESBLKSIZE
36  *	DESBLKSIZE / DESFRAGSIZE <= 8
37  */
38 #define	DFL_FRAGSIZE	1024
39 #define	DFL_BLKSIZE	8192
40 
41 /*
42  * Cylinder groups may have up to MAXCPG cylinders. The actual
43  * number used depends upon how much information can be stored
44  * on a single cylinder. The default is to used 16 cylinders
45  * per group.
46  */
47 #define	DESCPG		16	/* desired fs_cpg */
48 
49 /*
50  * MINFREE gives the minimum acceptable percentage of file system
51  * blocks which may be free. If the freelist drops below this level
52  * only the superuser may continue to allocate blocks. This may
53  * be set to 0 if no reserve of free blocks is deemed necessary,
54  * however throughput drops by fifty percent if the file system
55  * is run at between 90% and 100% full; thus the default value of
56  * fs_minfree is 10%. With 10% free space, fragmentation is not a
57  * problem, so we choose to optimize for time.
58  */
59 #define MINFREE		10
60 #define DEFAULTOPT	FS_OPTTIME
61 
62 /*
63  * ROTDELAY gives the minimum number of milliseconds to initiate
64  * another disk transfer on the same cylinder. It is used in
65  * determining the rotationally optimal layout for disk blocks
66  * within a file; the default of fs_rotdelay is 4ms.
67  */
68 #define ROTDELAY	4
69 
70 /*
71  * MAXCONTIG sets the default for the maximum number of blocks
72  * that may be allocated sequentially. Since UNIX drivers are
73  * not capable of scheduling multi-block transfers, this defaults
74  * to 1 (ie no contiguous blocks are allocated).
75  */
76 #define MAXCONTIG	1
77 
78 /*
79  * Each file system has a number of inodes statically allocated.
80  * We allocate one inode slot per NBPI bytes, expecting this
81  * to be far more than we will ever need.
82  */
83 #define	NBPI		2048
84 
85 int	Nflag;			/* run without writing file system */
86 int	fssize;			/* file system size */
87 int	ntracks;		/* # tracks/cylinder */
88 int	nsectors;		/* # sectors/track */
89 int	nphyssectors;		/* # sectors/track including spares */
90 int	secpercyl;		/* sectors per cylinder */
91 int	trackspares = -1;	/* spare sectors per track */
92 int	cylspares = -1;		/* spare sectors per cylinder */
93 int	sectorsize;		/* bytes/sector */
94 #ifdef tahoe
95 int	realsectorsize;		/* bytes/sector in hardware */
96 #endif
97 int	rpm;			/* revolutions/minute of drive */
98 int	interleave;		/* hardware sector interleave */
99 int	trackskew = -1;		/* sector 0 skew, per track */
100 int	headswitch;		/* head switch time, usec */
101 int	trackseek;		/* track-to-track seek, usec */
102 int	fsize = 0;		/* fragment size */
103 int	bsize = 0;		/* block size */
104 int	cpg = DESCPG;		/* cylinders/cylinder group */
105 int	minfree = MINFREE;	/* free space threshold */
106 int	opt = DEFAULTOPT;	/* optimization preference (space or time) */
107 int	density = NBPI;		/* number of bytes per inode */
108 int	maxcontig = MAXCONTIG;	/* max contiguous blocks to allocate */
109 int	rotdelay = ROTDELAY;	/* rotational delay between blocks */
110 int	bbsize = BBSIZE;	/* boot block size */
111 int	sbsize = SBSIZE;	/* superblock size */
112 
113 char	device[MAXPATHLEN];
114 
115 extern	int errno;
116 char	*index();
117 char	*rindex();
118 char	*sprintf();
119 
120 main(argc, argv)
121 	int argc;
122 	char *argv[];
123 {
124 	char *cp, *special;
125 	register struct partition *pp;
126 	register struct disklabel *lp;
127 	struct disklabel *getdisklabel();
128 	struct partition oldpartition;
129 	struct stat st;
130 	int fsi, fso;
131 	register int i;
132 	int status;
133 
134 	argc--, argv++;
135 	while (argc > 0 && argv[0][0] == '-') {
136 		for (cp = &argv[0][1]; *cp; cp++)
137 			switch (*cp) {
138 
139 			case 'N':
140 				Nflag++;
141 				break;
142 
143 			case 'S':
144 				if (argc < 1)
145 					fatal("-S: missing sector size");
146 				argc--, argv++;
147 				sectorsize = atoi(*argv);
148 				if (sectorsize <= 0)
149 					fatal("%s: bad sector size", *argv);
150 				goto next;
151 
152 			case 'a':
153 				if (argc < 1)
154 					fatal("-a: spare sectors per cylinder");
155 				argc--, argv++;
156 				cylspares = atoi(*argv);
157 				if (cylspares < 0)
158 					fatal("%s: bad spare sectors per cylinder", *argv);
159 				goto next;
160 
161 			case 'b':
162 				if (argc < 1)
163 					fatal("-b: missing block size");
164 				argc--, argv++;
165 				bsize = atoi(*argv);
166 				if (bsize < MINBSIZE)
167 					fatal("%s: bad block size", *argv);
168 				goto next;
169 
170 			case 'c':
171 				if (argc < 1)
172 					fatal("-c: missing cylinders/group");
173 				argc--, argv++;
174 				cpg = atoi(*argv);
175 				if (cpg <= 0)
176 					fatal("%s: bad cylinders/group", *argv);
177 				goto next;
178 
179 			case 'd':
180 				if (argc < 1)
181 					fatal("-d: missing sectors/track");
182 				argc--, argv++;
183 				nsectors = atoi(*argv);
184 				if (nsectors <= 0)
185 					fatal("%s: bad sectors/track", *argv);
186 				goto next;
187 
188 			case 'f':
189 				if (argc < 1)
190 					fatal("-f: missing frag size");
191 				argc--, argv++;
192 				fsize = atoi(*argv);
193 				if (fsize <= 0)
194 					fatal("%s: bad frag size", *argv);
195 				goto next;
196 
197 			case 'i':
198 				if (argc < 1)
199 					fatal("-i: missing bytes per inode\n");
200 				argc--, argv++;
201 				density = atoi(*argv);
202 				if (density <= 0)
203 					fatal("%s: bad bytes per inode\n",
204 						*argv);
205 				goto next;
206 
207 			case 'k':
208 				if (argc < 1)
209 					fatal("-k: track skew");
210 				argc--, argv++;
211 				trackskew = atoi(*argv);
212 				if (trackskew < 0)
213 					fatal("%s: bad track skew", *argv);
214 				goto next;
215 
216 			case 'l':
217 				if (argc < 1)
218 					fatal("-l: interleave");
219 				argc--, argv++;
220 				interleave = atoi(*argv);
221 				if (interleave <= 0)
222 					fatal("%s: bad interleave", *argv);
223 				goto next;
224 
225 			case 'm':
226 				if (argc < 1)
227 					fatal("-m: missing free space %%\n");
228 				argc--, argv++;
229 				minfree = atoi(*argv);
230 				if (minfree < 0 || minfree > 99)
231 					fatal("%s: bad free space %%\n",
232 						*argv);
233 				goto next;
234 
235 			case 'o':
236 				if (argc < 1)
237 					fatal("-o: missing optimization preference");
238 				argc--, argv++;
239 				if (strcmp(*argv, "space") == 0)
240 					opt = FS_OPTSPACE;
241 				else if (strcmp(*argv, "time") == 0)
242 					opt = FS_OPTTIME;
243 				else
244 					fatal("%s: bad optimization preference %s",
245 					    *argv,
246 					    "(options are `space' or `time')");
247 				goto next;
248 
249 			case 'p':
250 				if (argc < 1)
251 					fatal("-p: spare sectors per track");
252 				argc--, argv++;
253 				trackspares = atoi(*argv);
254 				if (trackspares < 0)
255 					fatal("%s: bad spare sectors per track", *argv);
256 				goto next;
257 
258 			case 'r':
259 				if (argc < 1)
260 					fatal("-r: missing revs/minute\n");
261 				argc--, argv++;
262 				rpm = atoi(*argv);
263 				if (rpm <= 0)
264 					fatal("%s: bad revs/minute\n", *argv);
265 				goto next;
266 
267 			case 's':
268 				if (argc < 1)
269 					fatal("-s: missing file system size");
270 				argc--, argv++;
271 				fssize = atoi(*argv);
272 				if (fssize <= 0)
273 					fatal("%s: bad file system size",
274 						*argv);
275 				goto next;
276 
277 			case 't':
278 				if (argc < 1)
279 					fatal("-t: missing track total");
280 				argc--, argv++;
281 				ntracks = atoi(*argv);
282 				if (ntracks <= 0)
283 					fatal("%s: bad total tracks", *argv);
284 				goto next;
285 
286 			default:
287 				fatal("-%c: unknown flag", cp);
288 			}
289 next:
290 		argc--, argv++;
291 	}
292 	if (argc < 1) {
293 		fprintf(stderr, "usage: newfs [ fsoptions ] special-device\n");
294 		fprintf(stderr, "where fsoptions are:\n");
295 		fprintf(stderr, "\t-N do not create file system, %s\n",
296 			"just print out parameters");
297 		fprintf(stderr, "\t-b block size\n");
298 		fprintf(stderr, "\t-f frag size\n");
299 		fprintf(stderr, "\t-m minimum free space %%\n");
300 		fprintf(stderr, "\t-o optimization preference %s\n",
301 			"(`space' or `time')");
302 		fprintf(stderr, "\t-i number of bytes per inode\n");
303 		fprintf(stderr, "\t-c cylinders/group\n");
304 		fprintf(stderr, "\t-s file system size (sectors)\n");
305 		fprintf(stderr, "\t-r revolutions/minute\n");
306 		fprintf(stderr, "\t-S sector size\n");
307 		fprintf(stderr, "\t-d sectors/track\n");
308 		fprintf(stderr, "\t-t tracks/cylinder\n");
309 		fprintf(stderr, "\t-p spare sectors per track\n");
310 		fprintf(stderr, "\t-a spare sectors per cylinder\n");
311 		fprintf(stderr, "\t-l hardware sector interleave\n");
312 		fprintf(stderr, "\t-k sector 0 skew, per track\n");
313 		exit(1);
314 	}
315 	special = argv[0];
316 	cp = rindex(special, '/');
317 	if (cp != 0)
318 		special = cp + 1;
319 	if (*special == 'r' && special[1] != 'a' && special[1] != 'b')
320 		special++;
321 	special = sprintf(device, "/dev/r%s", special);
322 	if (!Nflag) {
323 		fso = open(special, O_WRONLY);
324 		if (fso < 0) {
325 			perror(special);
326 			exit(1);
327 		}
328 	} else
329 		fso = -1;
330 	fsi = open(special, O_RDONLY);
331 	if (fsi < 0) {
332 		perror(special);
333 		exit(1);
334 	}
335 	if (fstat(fsi, &st) < 0) {
336 		fprintf(stderr, "newfs: "); perror(special);
337 		exit(2);
338 	}
339 	if ((st.st_mode & S_IFMT) != S_IFCHR)
340 		fatal("%s: not a character device", special);
341 	cp = index(argv[0], '\0') - 1;
342 	if (cp == 0 || (*cp < 'a' || *cp > 'h') && !isdigit(*cp))
343 		fatal("%s: can't figure out file system partition", argv[0]);
344 	lp = getdisklabel(special, fsi);
345 	if (isdigit(*cp))
346 		pp = &lp->d_partitions[0];
347 	else
348 		pp = &lp->d_partitions[*cp - 'a'];
349 	if (pp->p_size == 0)
350 		fatal("%s: `%c' partition is unavailable", argv[0], *cp);
351 	if (fssize == 0)
352 		fssize = pp->p_size;
353 	if (fssize > pp->p_size)
354 	       fatal("%s: maximum file system size on the `%c' partition is %d",
355 			argv[0], *cp, pp->p_size);
356 	if (rpm == 0) {
357 		rpm = lp->d_rpm;
358 		if (rpm <= 0)
359 			rpm = 3600;
360 	}
361 	if (ntracks == 0) {
362 		ntracks = lp->d_ntracks;
363 		if (ntracks <= 0)
364 			fatal("%s: no default #tracks", argv[0]);
365 	}
366 	if (nsectors == 0) {
367 		nsectors = lp->d_nsectors;
368 		if (nsectors <= 0)
369 			fatal("%s: no default #sectors/track", argv[0]);
370 	}
371 	if (sectorsize == 0) {
372 		sectorsize = lp->d_secsize;
373 		if (sectorsize <= 0)
374 			fatal("%s: no default sector size", argv[0]);
375 	}
376 	if (trackskew == -1) {
377 		trackskew = lp->d_trackskew;
378 		if (trackskew < 0)
379 			trackskew = 0;
380 	}
381 	if (interleave == 0) {
382 		interleave = lp->d_interleave;
383 		if (interleave <= 0)
384 			interleave = 1;
385 	}
386 	if (fsize == 0) {
387 		fsize = pp->p_fsize;
388 		if (fsize <= 0)
389 			fsize = MAX(DFL_FRAGSIZE, lp->d_secsize);
390 	}
391 	if (bsize == 0) {
392 		bsize = pp->p_frag * pp->p_fsize;
393 		if (bsize <= 0)
394 			bsize = MIN(DFL_BLKSIZE, 8 * fsize);
395 	}
396 	if (minfree < 10 && opt != FS_OPTSPACE) {
397 		fprintf(stderr, "Warning: changing optimization to space ");
398 		fprintf(stderr, "because minfree is less than 10%%\n");
399 		opt = FS_OPTSPACE;
400 	}
401 	if (trackspares == -1) {
402 		trackspares = lp->d_sparespertrack;
403 		if (trackspares < 0)
404 			trackspares = 0;
405 	}
406 	nphyssectors = nsectors + trackspares;
407 	if (cylspares == -1) {
408 		cylspares = lp->d_sparespercyl;
409 		if (cylspares < 0)
410 			cylspares = 0;
411 	}
412 	secpercyl = nsectors * ntracks - cylspares;
413 	if (secpercyl != lp->d_secpercyl)
414 		fprintf(stderr, "%s (%d) %s (%d)\n",
415 			"Warning: calculated sectors per cylinder", secpercyl,
416 			"disagrees with disk label", lp->d_secpercyl);
417 	headswitch = lp->d_headswitch;
418 	trackseek = lp->d_trkseek;
419 	bbsize = lp->d_bbsize;
420 	sbsize = lp->d_sbsize;
421 	oldpartition = *pp;
422 #ifdef tahoe
423 	realsectorsize = sectorsize;
424 	if (sectorsize != DEV_BSIZE) {		/* XXX */
425 		int secperblk = DEV_BSIZE / sectorsize;
426 
427 		sectorsize = DEV_BSIZE;
428 		nsectors /= secperblk;
429 		nphyssectors /= secperblk;
430 		secpercyl /= secperblk;
431 		fssize /= secperblk;
432 		pp->p_size /= secperblk;
433 	}
434 #endif
435 	mkfs(pp, special, fsi, fso);
436 #ifdef tahoe
437 	if (realsectorsize != DEV_BSIZE)
438 		pp->p_size *= DEV_BSIZE / realsectorsize;
439 #endif
440 	if (!Nflag && bcmp(pp, &oldpartition, sizeof(oldpartition)))
441 		rewritelabel(special, fso, lp);
442 	exit(0);
443 }
444 
445 struct disklabel *
446 getdisklabel(s, fd)
447 	char *s;
448 	int	fd;
449 {
450 	static struct disklabel lab;
451 
452 	if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) {
453 		perror("ioctl (GDINFO)");
454 		fatal("%s: can't read disk label", s);
455 	}
456 	return (&lab);
457 }
458 
459 rewritelabel(s, fd, lp)
460 	char *s;
461 	int fd;
462 	register struct disklabel *lp;
463 {
464 
465 	lp->d_checksum = 0;
466 	lp->d_checksum = dkcksum(lp);
467 	if (ioctl(fd, DIOCWDINFO, (char *)lp) < 0) {
468 		perror("ioctl (GWINFO)");
469 		fatal("%s: can't rewrite disk label", s);
470 	}
471 #if vax
472 	if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) {
473 		register i;
474 		int cfd;
475 		daddr_t alt;
476 		char specname[64];
477 		char blk[1024];
478 		char *cp;
479 
480 		/*
481 		 * Make name for 'c' partition.
482 		 */
483 		strcpy(specname, s);
484 		cp = specname + strlen(specname) - 1;
485 		if (!isdigit(*cp))
486 			*cp = 'c';
487 		cfd = open(specname, O_WRONLY);
488 		if (cfd < 0) {
489 			perror(specname);
490 			exit(2);
491 		}
492 		bzero(blk, sizeof(blk));
493 		*(struct disklabel *)(blk + LABELOFFSET) = *lp;
494 		alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors;
495 		for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) {
496 			lseek(cfd, (off_t)(alt + i) * lp->d_secsize, L_SET);
497 			if (write(cfd, blk, lp->d_secsize) < lp->d_secsize) {
498 				int oerrno = errno;
499 				fprintf(stderr, "alternate label %d ", i/2);
500 				errno = oerrno;
501 				perror("write");
502 			}
503 		}
504 	}
505 #endif
506 }
507 
508 /*VARARGS*/
509 fatal(fmt, arg1, arg2)
510 	char *fmt;
511 {
512 
513 	fprintf(stderr, "newfs: ");
514 	fprintf(stderr, fmt, arg1, arg2);
515 	putc('\n', stderr);
516 	exit(10);
517 }
518