xref: /original-bsd/sbin/newfs/mkfs.c (revision 8431ec24)
1 /*
2  * Copyright (c) 1980, 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 static char sccsid[] = "@(#)mkfs.c	6.13 (Berkeley) 10/24/89";
20 #endif /* not lint */
21 
22 #ifndef STANDALONE
23 #include <stdio.h>
24 #include <a.out.h>
25 #endif
26 
27 #include <sys/param.h>
28 #include <sys/time.h>
29 #include <sys/wait.h>
30 #include <sys/resource.h>
31 #include <ufs/dinode.h>
32 #include <ufs/fs.h>
33 #include <ufs/dir.h>
34 #include <sys/disklabel.h>
35 #include <machine/endian.h>
36 
37 /*
38  * make file system for cylinder-group style file systems
39  */
40 
41 /*
42  * The size of a cylinder group is calculated by CGSIZE. The maximum size
43  * is limited by the fact that cylinder groups are at most one block.
44  * Its size is derived from the size of the maps maintained in the
45  * cylinder group and the (struct cg) size.
46  */
47 #define CGSIZE(fs) \
48     /* base cg */	(sizeof(struct cg) + \
49     /* blktot size */	(fs)->fs_cpg * sizeof(long) + \
50     /* blks size */	(fs)->fs_cpg * (fs)->fs_nrpos * sizeof(short) + \
51     /* inode map */	howmany((fs)->fs_ipg, NBBY) + \
52     /* block map */	howmany((fs)->fs_cpg * (fs)->fs_spc / NSPF(fs), NBBY))
53 
54 /*
55  * We limit the size of the inode map to be no more than a
56  * third of the cylinder group space, since we must leave at
57  * least an equal amount of space for the block map.
58  *
59  * N.B.: MAXIPG must be a multiple of INOPB(fs).
60  */
61 #define MAXIPG(fs)	roundup((fs)->fs_bsize * NBBY / 3, INOPB(fs))
62 
63 #define UMASK		0755
64 #define MAXINOPB	(MAXBSIZE / sizeof(struct dinode))
65 #define POWEROF2(num)	(((num) & ((num) - 1)) == 0)
66 
67 /*
68  * variables set up by front end.
69  */
70 extern int	mfs;		/* run as the memory based filesystem */
71 extern int	Nflag;		/* run mkfs without writing file system */
72 extern int	fssize;		/* file system size */
73 extern int	ntracks;	/* # tracks/cylinder */
74 extern int	nsectors;	/* # sectors/track */
75 extern int	nphyssectors;	/* # sectors/track including spares */
76 extern int	secpercyl;	/* sectors per cylinder */
77 extern int	sectorsize;	/* bytes/sector */
78 extern int	rpm;		/* revolutions/minute of drive */
79 extern int	interleave;	/* hardware sector interleave */
80 extern int	trackskew;	/* sector 0 skew, per track */
81 extern int	headswitch;	/* head switch time, usec */
82 extern int	trackseek;	/* track-to-track seek, usec */
83 extern int	fsize;		/* fragment size */
84 extern int	bsize;		/* block size */
85 extern int	cpg;		/* cylinders/cylinder group */
86 extern int	cpgflg;		/* cylinders/cylinder group flag was given */
87 extern int	minfree;	/* free space threshold */
88 extern int	opt;		/* optimization preference (space or time) */
89 extern int	density;	/* number of bytes per inode */
90 extern int	maxcontig;	/* max contiguous blocks to allocate */
91 extern int	rotdelay;	/* rotational delay between blocks */
92 extern int	maxbpg;		/* maximum blocks per file in a cyl group */
93 extern int	nrpos;		/* # of distinguished rotational positions */
94 extern int	bbsize;		/* boot block size */
95 extern int	sbsize;		/* superblock size */
96 extern u_long	memleft;	/* virtual memory available */
97 extern caddr_t	membase;	/* start address of memory based filesystem */
98 extern caddr_t	malloc(), calloc();
99 
100 union {
101 	struct fs fs;
102 	char pad[SBSIZE];
103 } fsun;
104 #define	sblock	fsun.fs
105 struct	csum *fscs;
106 
107 union {
108 	struct cg cg;
109 	char pad[MAXBSIZE];
110 } cgun;
111 #define	acg	cgun.cg
112 
113 struct dinode zino[MAXBSIZE / sizeof(struct dinode)];
114 
115 int	fsi, fso;
116 time_t	utime;
117 daddr_t	alloc();
118 
119 mkfs(pp, fsys, fi, fo)
120 	struct partition *pp;
121 	char *fsys;
122 	int fi, fo;
123 {
124 	register long i, mincpc, mincpg, inospercg;
125 	long cylno, rpos, blk, j, warn = 0;
126 	long used, mincpgcnt, bpcg;
127 	long mapcramped, inodecramped;
128 	long postblsize, rotblsize, totalsbsize;
129 	int ppid, status, started();
130 
131 #ifndef STANDALONE
132 	time(&utime);
133 #endif
134 	if (mfs) {
135 		ppid = getpid();
136 		(void) signal(SIGUSR1, started);
137 		if (i = fork()) {
138 			if (i == -1) {
139 				perror("mfs");
140 				exit(10);
141 			}
142 			if (waitpid(i, &status, 0) != -1 && WIFEXITED(status))
143 				exit(WEXITSTATUS(status));
144 			exit(11);
145 			/* NOTREACHED */
146 		}
147 		(void)malloc(0);
148 		if (fssize * sectorsize > memleft)
149 			fssize = (memleft - 16384) / sectorsize;
150 		if ((membase = malloc(fssize * sectorsize)) == 0)
151 			exit(12);
152 	}
153 	fsi = fi;
154 	fso = fo;
155 	/*
156 	 * Validate the given file system size.
157 	 * Verify that its last block can actually be accessed.
158 	 */
159 	if (fssize <= 0)
160 		printf("preposterous size %d\n", fssize), exit(13);
161 	wtfs(fssize - 1, sectorsize, (char *)&sblock);
162 	/*
163 	 * collect and verify the sector and track info
164 	 */
165 	sblock.fs_nsect = nsectors;
166 	sblock.fs_ntrak = ntracks;
167 	if (sblock.fs_ntrak <= 0)
168 		printf("preposterous ntrak %d\n", sblock.fs_ntrak), exit(14);
169 	if (sblock.fs_nsect <= 0)
170 		printf("preposterous nsect %d\n", sblock.fs_nsect), exit(15);
171 	/*
172 	 * collect and verify the block and fragment sizes
173 	 */
174 	sblock.fs_bsize = bsize;
175 	sblock.fs_fsize = fsize;
176 	if (!POWEROF2(sblock.fs_bsize)) {
177 		printf("block size must be a power of 2, not %d\n",
178 		    sblock.fs_bsize);
179 		exit(16);
180 	}
181 	if (!POWEROF2(sblock.fs_fsize)) {
182 		printf("fragment size must be a power of 2, not %d\n",
183 		    sblock.fs_fsize);
184 		exit(17);
185 	}
186 	if (sblock.fs_fsize < sectorsize) {
187 		printf("fragment size %d is too small, minimum is %d\n",
188 		    sblock.fs_fsize, sectorsize);
189 		exit(18);
190 	}
191 	if (sblock.fs_bsize < MINBSIZE) {
192 		printf("block size %d is too small, minimum is %d\n",
193 		    sblock.fs_bsize, MINBSIZE);
194 		exit(19);
195 	}
196 	if (sblock.fs_bsize < sblock.fs_fsize) {
197 		printf("block size (%d) cannot be smaller than fragment size (%d)\n",
198 		    sblock.fs_bsize, sblock.fs_fsize);
199 		exit(20);
200 	}
201 	sblock.fs_bmask = ~(sblock.fs_bsize - 1);
202 	sblock.fs_fmask = ~(sblock.fs_fsize - 1);
203 	/*
204 	 * Planning now for future expansion.
205 	 */
206 #	if (BYTE_ORDER == BIG_ENDIAN)
207 		sblock.fs_qbmask.val[0] = 0;
208 		sblock.fs_qbmask.val[1] = ~sblock.fs_bmask;
209 		sblock.fs_qfmask.val[0] = 0;
210 		sblock.fs_qfmask.val[1] = ~sblock.fs_fmask;
211 #	endif /* BIG_ENDIAN */
212 #	if (BYTE_ORDER == LITTLE_ENDIAN)
213 		sblock.fs_qbmask.val[0] = ~sblock.fs_bmask;
214 		sblock.fs_qbmask.val[1] = 0;
215 		sblock.fs_qfmask.val[0] = ~sblock.fs_fmask;
216 		sblock.fs_qfmask.val[1] = 0;
217 #	endif /* LITTLE_ENDIAN */
218 	for (sblock.fs_bshift = 0, i = sblock.fs_bsize; i > 1; i >>= 1)
219 		sblock.fs_bshift++;
220 	for (sblock.fs_fshift = 0, i = sblock.fs_fsize; i > 1; i >>= 1)
221 		sblock.fs_fshift++;
222 	sblock.fs_frag = numfrags(&sblock, sblock.fs_bsize);
223 	for (sblock.fs_fragshift = 0, i = sblock.fs_frag; i > 1; i >>= 1)
224 		sblock.fs_fragshift++;
225 	if (sblock.fs_frag > MAXFRAG) {
226 		printf("fragment size %d is too small, minimum with block size %d is %d\n",
227 		    sblock.fs_fsize, sblock.fs_bsize,
228 		    sblock.fs_bsize / MAXFRAG);
229 		exit(21);
230 	}
231 	sblock.fs_nrpos = nrpos;
232 	sblock.fs_nindir = sblock.fs_bsize / sizeof(daddr_t);
233 	sblock.fs_inopb = sblock.fs_bsize / sizeof(struct dinode);
234 	sblock.fs_nspf = sblock.fs_fsize / sectorsize;
235 	for (sblock.fs_fsbtodb = 0, i = NSPF(&sblock); i > 1; i >>= 1)
236 		sblock.fs_fsbtodb++;
237 	sblock.fs_sblkno =
238 	    roundup(howmany(bbsize + sbsize, sblock.fs_fsize), sblock.fs_frag);
239 	sblock.fs_cblkno = (daddr_t)(sblock.fs_sblkno +
240 	    roundup(howmany(sbsize, sblock.fs_fsize), sblock.fs_frag));
241 	sblock.fs_iblkno = sblock.fs_cblkno + sblock.fs_frag;
242 	sblock.fs_cgoffset = roundup(
243 	    howmany(sblock.fs_nsect, NSPF(&sblock)), sblock.fs_frag);
244 	for (sblock.fs_cgmask = 0xffffffff, i = sblock.fs_ntrak; i > 1; i >>= 1)
245 		sblock.fs_cgmask <<= 1;
246 	if (!POWEROF2(sblock.fs_ntrak))
247 		sblock.fs_cgmask <<= 1;
248 	/*
249 	 * Validate specified/determined secpercyl
250 	 * and calculate minimum cylinders per group.
251 	 */
252 	sblock.fs_spc = secpercyl;
253 	for (sblock.fs_cpc = NSPB(&sblock), i = sblock.fs_spc;
254 	     sblock.fs_cpc > 1 && (i & 1) == 0;
255 	     sblock.fs_cpc >>= 1, i >>= 1)
256 		/* void */;
257 	mincpc = sblock.fs_cpc;
258 	bpcg = sblock.fs_spc * sectorsize;
259 	inospercg = roundup(bpcg / sizeof(struct dinode), INOPB(&sblock));
260 	if (inospercg > MAXIPG(&sblock))
261 		inospercg = MAXIPG(&sblock);
262 	used = (sblock.fs_iblkno + inospercg / INOPF(&sblock)) * NSPF(&sblock);
263 	mincpgcnt = howmany(sblock.fs_cgoffset * (~sblock.fs_cgmask) + used,
264 	    sblock.fs_spc);
265 	mincpg = roundup(mincpgcnt, mincpc);
266 	/*
267 	 * Insure that cylinder group with mincpg has enough space
268 	 * for block maps
269 	 */
270 	sblock.fs_cpg = mincpg;
271 	sblock.fs_ipg = inospercg;
272 	mapcramped = 0;
273 	while (CGSIZE(&sblock) > sblock.fs_bsize) {
274 		mapcramped = 1;
275 		if (sblock.fs_bsize < MAXBSIZE) {
276 			sblock.fs_bsize <<= 1;
277 			if ((i & 1) == 0) {
278 				i >>= 1;
279 			} else {
280 				sblock.fs_cpc <<= 1;
281 				mincpc <<= 1;
282 				mincpg = roundup(mincpgcnt, mincpc);
283 				sblock.fs_cpg = mincpg;
284 			}
285 			sblock.fs_frag <<= 1;
286 			sblock.fs_fragshift += 1;
287 			if (sblock.fs_frag <= MAXFRAG)
288 				continue;
289 		}
290 		if (sblock.fs_fsize == sblock.fs_bsize) {
291 			printf("There is no block size that");
292 			printf(" can support this disk\n");
293 			exit(22);
294 		}
295 		sblock.fs_frag >>= 1;
296 		sblock.fs_fragshift -= 1;
297 		sblock.fs_fsize <<= 1;
298 		sblock.fs_nspf <<= 1;
299 	}
300 	/*
301 	 * Insure that cylinder group with mincpg has enough space for inodes
302 	 */
303 	inodecramped = 0;
304 	used *= sectorsize;
305 	inospercg = roundup((mincpg * bpcg - used) / density, INOPB(&sblock));
306 	sblock.fs_ipg = inospercg;
307 	while (inospercg > MAXIPG(&sblock)) {
308 		inodecramped = 1;
309 		if (mincpc == 1 || sblock.fs_frag == 1 ||
310 		    sblock.fs_bsize == MINBSIZE)
311 			break;
312 		printf("With a block size of %d %s %d\n", sblock.fs_bsize,
313 		    "minimum bytes per inode is",
314 		    (mincpg * bpcg - used) / MAXIPG(&sblock) + 1);
315 		sblock.fs_bsize >>= 1;
316 		sblock.fs_frag >>= 1;
317 		sblock.fs_fragshift -= 1;
318 		mincpc >>= 1;
319 		sblock.fs_cpg = roundup(mincpgcnt, mincpc);
320 		if (CGSIZE(&sblock) > sblock.fs_bsize) {
321 			sblock.fs_bsize <<= 1;
322 			break;
323 		}
324 		mincpg = sblock.fs_cpg;
325 		inospercg =
326 		    roundup((mincpg * bpcg - used) / density, INOPB(&sblock));
327 		sblock.fs_ipg = inospercg;
328 	}
329 	if (inodecramped) {
330 		if (inospercg > MAXIPG(&sblock)) {
331 			printf("Minimum bytes per inode is %d\n",
332 			    (mincpg * bpcg - used) / MAXIPG(&sblock) + 1);
333 		} else if (!mapcramped) {
334 			printf("With %d bytes per inode, ", density);
335 			printf("minimum cylinders per group is %d\n", mincpg);
336 		}
337 	}
338 	if (mapcramped) {
339 		printf("With %d sectors per cylinder, ", sblock.fs_spc);
340 		printf("minimum cylinders per group is %d\n", mincpg);
341 	}
342 	if (inodecramped || mapcramped) {
343 		if (sblock.fs_bsize != bsize)
344 			printf("%s to be changed from %d to %d\n",
345 			    "This requires the block size",
346 			    bsize, sblock.fs_bsize);
347 		if (sblock.fs_fsize != fsize)
348 			printf("\t%s to be changed from %d to %d\n",
349 			    "and the fragment size",
350 			    fsize, sblock.fs_fsize);
351 		exit(23);
352 	}
353 	/*
354 	 * Calculate the number of cylinders per group
355 	 */
356 	sblock.fs_cpg = cpg;
357 	if (sblock.fs_cpg % mincpc != 0) {
358 		printf("%s groups must have a multiple of %d cylinders\n",
359 			cpgflg ? "Cylinder" : "Warning: cylinder", mincpc);
360 		sblock.fs_cpg = roundup(sblock.fs_cpg, mincpc);
361 		if (!cpgflg)
362 			cpg = sblock.fs_cpg;
363 	}
364 	/*
365 	 * Must insure there is enough space for inodes
366 	 */
367 	sblock.fs_ipg = roundup((sblock.fs_cpg * bpcg - used) / density,
368 		INOPB(&sblock));
369 	while (sblock.fs_ipg > MAXIPG(&sblock)) {
370 		inodecramped = 1;
371 		sblock.fs_cpg -= mincpc;
372 		sblock.fs_ipg = roundup((sblock.fs_cpg * bpcg - used) / density,
373 			INOPB(&sblock));
374 	}
375 	/*
376 	 * Must insure there is enough space to hold block map
377 	 */
378 	while (CGSIZE(&sblock) > sblock.fs_bsize) {
379 		mapcramped = 1;
380 		sblock.fs_cpg -= mincpc;
381 		sblock.fs_ipg = roundup((sblock.fs_cpg * bpcg - used) / density,
382 			INOPB(&sblock));
383 	}
384 	sblock.fs_fpg = (sblock.fs_cpg * sblock.fs_spc) / NSPF(&sblock);
385 	if ((sblock.fs_cpg * sblock.fs_spc) % NSPB(&sblock) != 0) {
386 		printf("panic (fs_cpg * fs_spc) % NSPF != 0");
387 		exit(24);
388 	}
389 	if (sblock.fs_cpg < mincpg) {
390 		printf("cylinder groups must have at least %d cylinders\n",
391 			mincpg);
392 		exit(25);
393 	} else if (sblock.fs_cpg != cpg) {
394 		if (!cpgflg)
395 			printf("Warning: ");
396 		else if (!mapcramped && !inodecramped)
397 			exit(26);
398 		if (mapcramped && inodecramped)
399 			printf("Block size and bytes per inode restrict");
400 		else if (mapcramped)
401 			printf("Block size restricts");
402 		else
403 			printf("Bytes per inode restrict");
404 		printf(" cylinders per group to %d.\n", sblock.fs_cpg);
405 		if (cpgflg)
406 			exit(27);
407 	}
408 	sblock.fs_cgsize = fragroundup(&sblock, CGSIZE(&sblock));
409 	/*
410 	 * Now have size for file system and nsect and ntrak.
411 	 * Determine number of cylinders and blocks in the file system.
412 	 */
413 	sblock.fs_size = fssize = dbtofsb(&sblock, fssize);
414 	sblock.fs_ncyl = fssize * NSPF(&sblock) / sblock.fs_spc;
415 	if (fssize * NSPF(&sblock) > sblock.fs_ncyl * sblock.fs_spc) {
416 		sblock.fs_ncyl++;
417 		warn = 1;
418 	}
419 	if (sblock.fs_ncyl < 1) {
420 		printf("file systems must have at least one cylinder\n");
421 		exit(28);
422 	}
423 	/*
424 	 * Determine feasability/values of rotational layout tables.
425 	 *
426 	 * The size of the rotational layout tables is limited by the
427 	 * size of the superblock, SBSIZE. The amount of space available
428 	 * for tables is calculated as (SBSIZE - sizeof (struct fs)).
429 	 * The size of these tables is inversely proportional to the block
430 	 * size of the file system. The size increases if sectors per track
431 	 * are not powers of two, because more cylinders must be described
432 	 * by the tables before the rotational pattern repeats (fs_cpc).
433 	 */
434 	sblock.fs_interleave = interleave;
435 	sblock.fs_trackskew = trackskew;
436 	sblock.fs_npsect = nphyssectors;
437 	sblock.fs_postblformat = FS_DYNAMICPOSTBLFMT;
438 	sblock.fs_sbsize = fragroundup(&sblock, sizeof(struct fs));
439 	if (sblock.fs_ntrak == 1) {
440 		sblock.fs_cpc = 0;
441 		goto next;
442 	}
443 	postblsize = sblock.fs_nrpos * sblock.fs_cpc * sizeof(short);
444 	rotblsize = sblock.fs_cpc * sblock.fs_spc / NSPB(&sblock);
445 	totalsbsize = sizeof(struct fs) + rotblsize;
446 	if (sblock.fs_nrpos == 8 && sblock.fs_cpc <= 16) {
447 		/* use old static table space */
448 		sblock.fs_postbloff = (char *)(&sblock.fs_opostbl[0][0]) -
449 		    (char *)(&sblock.fs_link);
450 		sblock.fs_rotbloff = &sblock.fs_space[0] -
451 		    (u_char *)(&sblock.fs_link);
452 	} else {
453 		/* use dynamic table space */
454 		sblock.fs_postbloff = &sblock.fs_space[0] -
455 		    (u_char *)(&sblock.fs_link);
456 		sblock.fs_rotbloff = sblock.fs_postbloff + postblsize;
457 		totalsbsize += postblsize;
458 	}
459 	if (totalsbsize > SBSIZE ||
460 	    sblock.fs_nsect > (1 << NBBY) * NSPB(&sblock)) {
461 		printf("%s %s %d %s %d.%s",
462 		    "Warning: insufficient space in super block for\n",
463 		    "rotational layout tables with nsect", sblock.fs_nsect,
464 		    "and ntrak", sblock.fs_ntrak,
465 		    "\nFile system performance may be impaired.\n");
466 		sblock.fs_cpc = 0;
467 		goto next;
468 	}
469 	sblock.fs_sbsize = fragroundup(&sblock, totalsbsize);
470 	/*
471 	 * calculate the available blocks for each rotational position
472 	 */
473 	for (cylno = 0; cylno < sblock.fs_cpc; cylno++)
474 		for (rpos = 0; rpos < sblock.fs_nrpos; rpos++)
475 			fs_postbl(&sblock, cylno)[rpos] = -1;
476 	for (i = (rotblsize - 1) * sblock.fs_frag;
477 	     i >= 0; i -= sblock.fs_frag) {
478 		cylno = cbtocylno(&sblock, i);
479 		rpos = cbtorpos(&sblock, i);
480 		blk = fragstoblks(&sblock, i);
481 		if (fs_postbl(&sblock, cylno)[rpos] == -1)
482 			fs_rotbl(&sblock)[blk] = 0;
483 		else
484 			fs_rotbl(&sblock)[blk] =
485 			    fs_postbl(&sblock, cylno)[rpos] - blk;
486 		fs_postbl(&sblock, cylno)[rpos] = blk;
487 	}
488 next:
489 	/*
490 	 * Compute/validate number of cylinder groups.
491 	 */
492 	sblock.fs_ncg = sblock.fs_ncyl / sblock.fs_cpg;
493 	if (sblock.fs_ncyl % sblock.fs_cpg)
494 		sblock.fs_ncg++;
495 	sblock.fs_dblkno = sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock);
496 	i = MIN(~sblock.fs_cgmask, sblock.fs_ncg - 1);
497 	if (cgdmin(&sblock, i) - cgbase(&sblock, i) >= sblock.fs_fpg) {
498 		printf("inode blocks/cyl group (%d) >= data blocks (%d)\n",
499 		    cgdmin(&sblock, i) - cgbase(&sblock, i) / sblock.fs_frag,
500 		    sblock.fs_fpg / sblock.fs_frag);
501 		printf("number of cylinders per cylinder group (%d) %s.\n",
502 		    sblock.fs_cpg, "must be increased");
503 		exit(29);
504 	}
505 	j = sblock.fs_ncg - 1;
506 	if ((i = fssize - j * sblock.fs_fpg) < sblock.fs_fpg &&
507 	    cgdmin(&sblock, j) - cgbase(&sblock, j) > i) {
508 		if (j == 0) {
509 			printf("Filesystem must have at least %d sectors\n",
510 			    NSPF(&sblock) *
511 			    (cgdmin(&sblock, 0) + 3 * sblock.fs_frag));
512 			exit(30);
513 		}
514 		printf("Warning: inode blocks/cyl group (%d) >= data blocks (%d) in last\n",
515 		    (cgdmin(&sblock, j) - cgbase(&sblock, j)) / sblock.fs_frag,
516 		    i / sblock.fs_frag);
517 		printf("    cylinder group. This implies %d sector(s) cannot be allocated.\n",
518 		    i * NSPF(&sblock));
519 		sblock.fs_ncg--;
520 		sblock.fs_ncyl -= sblock.fs_ncyl % sblock.fs_cpg;
521 		sblock.fs_size = fssize = sblock.fs_ncyl * sblock.fs_spc /
522 		    NSPF(&sblock);
523 		warn = 0;
524 	}
525 	if (warn && !mfs) {
526 		printf("Warning: %d sector(s) in last cylinder unallocated\n",
527 		    sblock.fs_spc -
528 		    (fssize * NSPF(&sblock) - (sblock.fs_ncyl - 1)
529 		    * sblock.fs_spc));
530 	}
531 	/*
532 	 * fill in remaining fields of the super block
533 	 */
534 	sblock.fs_csaddr = cgdmin(&sblock, 0);
535 	sblock.fs_cssize =
536 	    fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum));
537 	i = sblock.fs_bsize / sizeof(struct csum);
538 	sblock.fs_csmask = ~(i - 1);
539 	for (sblock.fs_csshift = 0; i > 1; i >>= 1)
540 		sblock.fs_csshift++;
541 	fscs = (struct csum *)calloc(1, sblock.fs_cssize);
542 	sblock.fs_magic = FS_MAGIC;
543 	sblock.fs_rotdelay = rotdelay;
544 	sblock.fs_minfree = minfree;
545 	sblock.fs_maxcontig = maxcontig;
546 	sblock.fs_headswitch = headswitch;
547 	sblock.fs_trkseek = trackseek;
548 	sblock.fs_maxbpg = maxbpg;
549 	sblock.fs_rps = rpm / 60;
550 	sblock.fs_optim = opt;
551 	sblock.fs_cgrotor = 0;
552 	sblock.fs_cstotal.cs_ndir = 0;
553 	sblock.fs_cstotal.cs_nbfree = 0;
554 	sblock.fs_cstotal.cs_nifree = 0;
555 	sblock.fs_cstotal.cs_nffree = 0;
556 	sblock.fs_fmod = 0;
557 	sblock.fs_ronly = 0;
558 	/*
559 	 * Dump out summary information about file system.
560 	 */
561 	if (!mfs) {
562 		printf("%s:\t%d sectors in %d %s of %d tracks, %d sectors\n",
563 		    fsys, sblock.fs_size * NSPF(&sblock), sblock.fs_ncyl,
564 		    "cylinders", sblock.fs_ntrak, sblock.fs_nsect);
565 		printf("\t%.1fMB in %d cyl groups (%d c/g, %.2fMB/g, %d i/g)\n",
566 		    (float)sblock.fs_size * sblock.fs_fsize * 1e-6,
567 		    sblock.fs_ncg, sblock.fs_cpg,
568 		    (float)sblock.fs_fpg * sblock.fs_fsize * 1e-6,
569 		    sblock.fs_ipg);
570 	}
571 	/*
572 	 * Now build the cylinders group blocks and
573 	 * then print out indices of cylinder groups.
574 	 */
575 	if (!mfs)
576 		printf("super-block backups (for fsck -b #) at:");
577 	for (cylno = 0; cylno < sblock.fs_ncg; cylno++) {
578 		initcg(cylno);
579 		if (mfs)
580 			continue;
581 		if (cylno % 9 == 0)
582 			printf("\n");
583 		printf(" %d,", fsbtodb(&sblock, cgsblock(&sblock, cylno)));
584 	}
585 	if (!mfs)
586 		printf("\n");
587 	if (Nflag && !mfs)
588 		exit(0);
589 	/*
590 	 * Now construct the initial file system,
591 	 * then write out the super-block.
592 	 */
593 	fsinit();
594 	sblock.fs_time = utime;
595 	wtfs(SBOFF / sectorsize, sbsize, (char *)&sblock);
596 	for (i = 0; i < sblock.fs_cssize; i += sblock.fs_bsize)
597 		wtfs(fsbtodb(&sblock, sblock.fs_csaddr + numfrags(&sblock, i)),
598 			sblock.fs_cssize - i < sblock.fs_bsize ?
599 			    sblock.fs_cssize - i : sblock.fs_bsize,
600 			((char *)fscs) + i);
601 	/*
602 	 * Write out the duplicate super blocks
603 	 */
604 	for (cylno = 0; cylno < sblock.fs_ncg; cylno++)
605 		wtfs(fsbtodb(&sblock, cgsblock(&sblock, cylno)),
606 		    sbsize, (char *)&sblock);
607 	/*
608 	 * Update information about this partion in pack
609 	 * label, to that it may be updated on disk.
610 	 */
611 	pp->p_fstype = FS_BSDFFS;
612 	pp->p_fsize = sblock.fs_fsize;
613 	pp->p_frag = sblock.fs_frag;
614 	pp->p_cpg = sblock.fs_cpg;
615 	/*
616 	 * Notify parent process of success.
617 	 */
618 	if (mfs)
619 		kill(ppid, SIGUSR1);
620 }
621 
622 /*
623  * Initialize a cylinder group.
624  */
625 initcg(cylno)
626 	int cylno;
627 {
628 	daddr_t cbase, d, dlower, dupper, dmax;
629 	long i, j, s;
630 	register struct csum *cs;
631 
632 	/*
633 	 * Determine block bounds for cylinder group.
634 	 * Allow space for super block summary information in first
635 	 * cylinder group.
636 	 */
637 	cbase = cgbase(&sblock, cylno);
638 	dmax = cbase + sblock.fs_fpg;
639 	if (dmax > sblock.fs_size)
640 		dmax = sblock.fs_size;
641 	dlower = cgsblock(&sblock, cylno) - cbase;
642 	dupper = cgdmin(&sblock, cylno) - cbase;
643 	if (cylno == 0)
644 		dupper += howmany(sblock.fs_cssize, sblock.fs_fsize);
645 	cs = fscs + cylno;
646 	acg.cg_time = utime;
647 	acg.cg_magic = CG_MAGIC;
648 	acg.cg_cgx = cylno;
649 	if (cylno == sblock.fs_ncg - 1)
650 		acg.cg_ncyl = sblock.fs_ncyl % sblock.fs_cpg;
651 	else
652 		acg.cg_ncyl = sblock.fs_cpg;
653 	acg.cg_niblk = sblock.fs_ipg;
654 	acg.cg_ndblk = dmax - cbase;
655 	acg.cg_cs.cs_ndir = 0;
656 	acg.cg_cs.cs_nffree = 0;
657 	acg.cg_cs.cs_nbfree = 0;
658 	acg.cg_cs.cs_nifree = 0;
659 	acg.cg_rotor = 0;
660 	acg.cg_frotor = 0;
661 	acg.cg_irotor = 0;
662 	acg.cg_btotoff = &acg.cg_space[0] - (u_char *)(&acg.cg_link);
663 	acg.cg_boff = acg.cg_btotoff + sblock.fs_cpg * sizeof(long);
664 	acg.cg_iusedoff = acg.cg_boff +
665 		sblock.fs_cpg * sblock.fs_nrpos * sizeof(short);
666 	acg.cg_freeoff = acg.cg_iusedoff + howmany(sblock.fs_ipg, NBBY);
667 	acg.cg_nextfreeoff = acg.cg_freeoff +
668 		howmany(sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock), NBBY);
669 	for (i = 0; i < sblock.fs_frag; i++) {
670 		acg.cg_frsum[i] = 0;
671 	}
672 	bzero((caddr_t)cg_inosused(&acg), acg.cg_freeoff - acg.cg_iusedoff);
673 	acg.cg_cs.cs_nifree += sblock.fs_ipg;
674 	if (cylno == 0)
675 		for (i = 0; i < ROOTINO; i++) {
676 			setbit(cg_inosused(&acg), i);
677 			acg.cg_cs.cs_nifree--;
678 		}
679 	for (i = 0; i < sblock.fs_ipg / INOPF(&sblock); i += sblock.fs_frag)
680 		wtfs(fsbtodb(&sblock, cgimin(&sblock, cylno) + i),
681 		    sblock.fs_bsize, (char *)zino);
682 	bzero((caddr_t)cg_blktot(&acg), acg.cg_boff - acg.cg_btotoff);
683 	bzero((caddr_t)cg_blks(&sblock, &acg, 0),
684 	    acg.cg_iusedoff - acg.cg_boff);
685 	bzero((caddr_t)cg_blksfree(&acg), acg.cg_nextfreeoff - acg.cg_freeoff);
686 	if (cylno > 0) {
687 		/*
688 		 * In cylno 0, beginning space is reserved
689 		 * for boot and super blocks.
690 		 */
691 		for (d = 0; d < dlower; d += sblock.fs_frag) {
692 			setblock(&sblock, cg_blksfree(&acg), d/sblock.fs_frag);
693 			acg.cg_cs.cs_nbfree++;
694 			cg_blktot(&acg)[cbtocylno(&sblock, d)]++;
695 			cg_blks(&sblock, &acg, cbtocylno(&sblock, d))
696 			    [cbtorpos(&sblock, d)]++;
697 		}
698 		sblock.fs_dsize += dlower;
699 	}
700 	sblock.fs_dsize += acg.cg_ndblk - dupper;
701 	if (i = dupper % sblock.fs_frag) {
702 		acg.cg_frsum[sblock.fs_frag - i]++;
703 		for (d = dupper + sblock.fs_frag - i; dupper < d; dupper++) {
704 			setbit(cg_blksfree(&acg), dupper);
705 			acg.cg_cs.cs_nffree++;
706 		}
707 	}
708 	for (d = dupper; d + sblock.fs_frag <= dmax - cbase; ) {
709 		setblock(&sblock, cg_blksfree(&acg), d / sblock.fs_frag);
710 		acg.cg_cs.cs_nbfree++;
711 		cg_blktot(&acg)[cbtocylno(&sblock, d)]++;
712 		cg_blks(&sblock, &acg, cbtocylno(&sblock, d))
713 		    [cbtorpos(&sblock, d)]++;
714 		d += sblock.fs_frag;
715 	}
716 	if (d < dmax - cbase) {
717 		acg.cg_frsum[dmax - cbase - d]++;
718 		for (; d < dmax - cbase; d++) {
719 			setbit(cg_blksfree(&acg), d);
720 			acg.cg_cs.cs_nffree++;
721 		}
722 	}
723 	sblock.fs_cstotal.cs_ndir += acg.cg_cs.cs_ndir;
724 	sblock.fs_cstotal.cs_nffree += acg.cg_cs.cs_nffree;
725 	sblock.fs_cstotal.cs_nbfree += acg.cg_cs.cs_nbfree;
726 	sblock.fs_cstotal.cs_nifree += acg.cg_cs.cs_nifree;
727 	*cs = acg.cg_cs;
728 	wtfs(fsbtodb(&sblock, cgtod(&sblock, cylno)),
729 		sblock.fs_bsize, (char *)&acg);
730 }
731 
732 /*
733  * initialize the file system
734  */
735 struct dinode node;
736 
737 #ifdef LOSTDIR
738 #define PREDEFDIR 3
739 #else
740 #define PREDEFDIR 2
741 #endif
742 
743 struct direct root_dir[] = {
744 	{ ROOTINO, sizeof(struct direct), 1, "." },
745 	{ ROOTINO, sizeof(struct direct), 2, ".." },
746 #ifdef LOSTDIR
747 	{ LOSTFOUNDINO, sizeof(struct direct), 10, "lost+found" },
748 #endif
749 };
750 #ifdef LOSTDIR
751 struct direct lost_found_dir[] = {
752 	{ LOSTFOUNDINO, sizeof(struct direct), 1, "." },
753 	{ ROOTINO, sizeof(struct direct), 2, ".." },
754 	{ 0, DIRBLKSIZ, 0, 0 },
755 };
756 #endif
757 char buf[MAXBSIZE];
758 
759 fsinit()
760 {
761 	int i;
762 
763 	/*
764 	 * initialize the node
765 	 */
766 	node.di_atime = utime;
767 	node.di_mtime = utime;
768 	node.di_ctime = utime;
769 #ifdef LOSTDIR
770 	/*
771 	 * create the lost+found directory
772 	 */
773 	(void)makedir(lost_found_dir, 2);
774 	for (i = DIRBLKSIZ; i < sblock.fs_bsize; i += DIRBLKSIZ)
775 		bcopy(&lost_found_dir[2], &buf[i], DIRSIZ(&lost_found_dir[2]));
776 	node.di_mode = IFDIR | UMASK;
777 	node.di_nlink = 2;
778 	node.di_size = sblock.fs_bsize;
779 	node.di_db[0] = alloc(node.di_size, node.di_mode);
780 	node.di_blocks = btodb(fragroundup(&sblock, node.di_size));
781 	wtfs(fsbtodb(&sblock, node.di_db[0]), node.di_size, buf);
782 	iput(&node, LOSTFOUNDINO);
783 #endif
784 	/*
785 	 * create the root directory
786 	 */
787 	if (mfs)
788 		node.di_mode = IFDIR | 01777;
789 	else
790 		node.di_mode = IFDIR | UMASK;
791 	node.di_nlink = PREDEFDIR;
792 	node.di_size = makedir(root_dir, PREDEFDIR);
793 	node.di_db[0] = alloc(sblock.fs_fsize, node.di_mode);
794 	node.di_blocks = btodb(fragroundup(&sblock, node.di_size));
795 	wtfs(fsbtodb(&sblock, node.di_db[0]), sblock.fs_fsize, buf);
796 	iput(&node, ROOTINO);
797 }
798 
799 /*
800  * construct a set of directory entries in "buf".
801  * return size of directory.
802  */
803 makedir(protodir, entries)
804 	register struct direct *protodir;
805 	int entries;
806 {
807 	char *cp;
808 	int i, spcleft;
809 
810 	spcleft = DIRBLKSIZ;
811 	for (cp = buf, i = 0; i < entries - 1; i++) {
812 		protodir[i].d_reclen = DIRSIZ(&protodir[i]);
813 		bcopy(&protodir[i], cp, protodir[i].d_reclen);
814 		cp += protodir[i].d_reclen;
815 		spcleft -= protodir[i].d_reclen;
816 	}
817 	protodir[i].d_reclen = spcleft;
818 	bcopy(&protodir[i], cp, DIRSIZ(&protodir[i]));
819 	return (DIRBLKSIZ);
820 }
821 
822 /*
823  * allocate a block or frag
824  */
825 daddr_t
826 alloc(size, mode)
827 	int size;
828 	int mode;
829 {
830 	int i, frag;
831 	daddr_t d;
832 
833 	rdfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize,
834 	    (char *)&acg);
835 	if (acg.cg_magic != CG_MAGIC) {
836 		printf("cg 0: bad magic number\n");
837 		return (0);
838 	}
839 	if (acg.cg_cs.cs_nbfree == 0) {
840 		printf("first cylinder group ran out of space\n");
841 		return (0);
842 	}
843 	for (d = 0; d < acg.cg_ndblk; d += sblock.fs_frag)
844 		if (isblock(&sblock, cg_blksfree(&acg), d / sblock.fs_frag))
845 			goto goth;
846 	printf("internal error: can't find block in cyl 0\n");
847 	return (0);
848 goth:
849 	clrblock(&sblock, cg_blksfree(&acg), d / sblock.fs_frag);
850 	acg.cg_cs.cs_nbfree--;
851 	sblock.fs_cstotal.cs_nbfree--;
852 	fscs[0].cs_nbfree--;
853 	if (mode & IFDIR) {
854 		acg.cg_cs.cs_ndir++;
855 		sblock.fs_cstotal.cs_ndir++;
856 		fscs[0].cs_ndir++;
857 	}
858 	cg_blktot(&acg)[cbtocylno(&sblock, d)]--;
859 	cg_blks(&sblock, &acg, cbtocylno(&sblock, d))[cbtorpos(&sblock, d)]--;
860 	if (size != sblock.fs_bsize) {
861 		frag = howmany(size, sblock.fs_fsize);
862 		fscs[0].cs_nffree += sblock.fs_frag - frag;
863 		sblock.fs_cstotal.cs_nffree += sblock.fs_frag - frag;
864 		acg.cg_cs.cs_nffree += sblock.fs_frag - frag;
865 		acg.cg_frsum[sblock.fs_frag - frag]++;
866 		for (i = frag; i < sblock.fs_frag; i++)
867 			setbit(cg_blksfree(&acg), d + i);
868 	}
869 	wtfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize,
870 	    (char *)&acg);
871 	return (d);
872 }
873 
874 /*
875  * Allocate an inode on the disk
876  */
877 iput(ip, ino)
878 	register struct dinode *ip;
879 	register ino_t ino;
880 {
881 	struct dinode buf[MAXINOPB];
882 	daddr_t d;
883 	int c;
884 
885 	c = itog(&sblock, ino);
886 	rdfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize,
887 	    (char *)&acg);
888 	if (acg.cg_magic != CG_MAGIC) {
889 		printf("cg 0: bad magic number\n");
890 		exit(31);
891 	}
892 	acg.cg_cs.cs_nifree--;
893 	setbit(cg_inosused(&acg), ino);
894 	wtfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize,
895 	    (char *)&acg);
896 	sblock.fs_cstotal.cs_nifree--;
897 	fscs[0].cs_nifree--;
898 	if (ino >= sblock.fs_ipg * sblock.fs_ncg) {
899 		printf("fsinit: inode value out of range (%d).\n", ino);
900 		exit(32);
901 	}
902 	d = fsbtodb(&sblock, itod(&sblock, ino));
903 	rdfs(d, sblock.fs_bsize, buf);
904 	buf[itoo(&sblock, ino)] = *ip;
905 	wtfs(d, sblock.fs_bsize, buf);
906 }
907 
908 /*
909  * Notify parent process that the filesystem has created itself successfully.
910  */
911 started()
912 {
913 
914 	exit(0);
915 }
916 
917 /*
918  * Replace libc function with one suited to our needs.
919  */
920 caddr_t
921 malloc(size)
922 	register u_long size;
923 {
924 	u_long base, i;
925 	static u_long pgsz;
926 	struct rlimit rlp;
927 
928 	if (pgsz == 0) {
929 		base = sbrk(0);
930 		pgsz = getpagesize() - 1;
931 		i = (base + pgsz) &~ pgsz;
932 		base = sbrk(i - base);
933 		if (getrlimit(RLIMIT_DATA, &rlp) < 0)
934 			perror("getrlimit");
935 		rlp.rlim_cur = rlp.rlim_max;
936 		if (setrlimit(RLIMIT_DATA, &rlp) < 0)
937 			perror("setrlimit");
938 		memleft = rlp.rlim_max - base;
939 	}
940 	size = (size + pgsz) &~ pgsz;
941 	if (size > memleft)
942 		size = memleft;
943 	memleft -= size;
944 	if (size == 0)
945 		return (0);
946 	return ((caddr_t)sbrk(size));
947 }
948 
949 /*
950  * Replace libc function with one suited to our needs.
951  */
952 caddr_t
953 realloc(ptr, size)
954 	char *ptr;
955 	u_long size;
956 {
957 
958 	/* always fail for now */
959 	return ((caddr_t)0);
960 }
961 
962 /*
963  * Replace libc function with one suited to our needs.
964  */
965 char *
966 calloc(size, numelm)
967 	u_long size, numelm;
968 {
969 	caddr_t base;
970 
971 	size *= numelm;
972 	base = malloc(size);
973 	bzero(base, size);
974 	return (base);
975 }
976 
977 /*
978  * Replace libc function with one suited to our needs.
979  */
980 free(ptr)
981 	char *ptr;
982 {
983 
984 	/* do not worry about it for now */
985 }
986 
987 /*
988  * read a block from the file system
989  */
990 rdfs(bno, size, bf)
991 	daddr_t bno;
992 	int size;
993 	char *bf;
994 {
995 	int n;
996 
997 	if (mfs) {
998 		bcopy(membase + bno * sectorsize, bf, size);
999 		return;
1000 	}
1001 	if (lseek(fsi, bno * sectorsize, 0) < 0) {
1002 		printf("seek error: %ld\n", bno);
1003 		perror("rdfs");
1004 		exit(33);
1005 	}
1006 	n = read(fsi, bf, size);
1007 	if(n != size) {
1008 		printf("read error: %ld\n", bno);
1009 		perror("rdfs");
1010 		exit(34);
1011 	}
1012 }
1013 
1014 /*
1015  * write a block to the file system
1016  */
1017 wtfs(bno, size, bf)
1018 	daddr_t bno;
1019 	int size;
1020 	char *bf;
1021 {
1022 	int n;
1023 
1024 	if (mfs) {
1025 		bcopy(bf, membase + bno * sectorsize, size);
1026 		return;
1027 	}
1028 	if (Nflag)
1029 		return;
1030 	if (lseek(fso, bno * sectorsize, 0) < 0) {
1031 		printf("seek error: %ld\n", bno);
1032 		perror("wtfs");
1033 		exit(35);
1034 	}
1035 	n = write(fso, bf, size);
1036 	if(n != size) {
1037 		printf("write error: %ld\n", bno);
1038 		perror("wtfs");
1039 		exit(36);
1040 	}
1041 }
1042 
1043 /*
1044  * check if a block is available
1045  */
1046 isblock(fs, cp, h)
1047 	struct fs *fs;
1048 	unsigned char *cp;
1049 	int h;
1050 {
1051 	unsigned char mask;
1052 
1053 	switch (fs->fs_frag) {
1054 	case 8:
1055 		return (cp[h] == 0xff);
1056 	case 4:
1057 		mask = 0x0f << ((h & 0x1) << 2);
1058 		return ((cp[h >> 1] & mask) == mask);
1059 	case 2:
1060 		mask = 0x03 << ((h & 0x3) << 1);
1061 		return ((cp[h >> 2] & mask) == mask);
1062 	case 1:
1063 		mask = 0x01 << (h & 0x7);
1064 		return ((cp[h >> 3] & mask) == mask);
1065 	default:
1066 #ifdef STANDALONE
1067 		printf("isblock bad fs_frag %d\n", fs->fs_frag);
1068 #else
1069 		fprintf(stderr, "isblock bad fs_frag %d\n", fs->fs_frag);
1070 #endif
1071 		return (0);
1072 	}
1073 }
1074 
1075 /*
1076  * take a block out of the map
1077  */
1078 clrblock(fs, cp, h)
1079 	struct fs *fs;
1080 	unsigned char *cp;
1081 	int h;
1082 {
1083 	switch ((fs)->fs_frag) {
1084 	case 8:
1085 		cp[h] = 0;
1086 		return;
1087 	case 4:
1088 		cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
1089 		return;
1090 	case 2:
1091 		cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
1092 		return;
1093 	case 1:
1094 		cp[h >> 3] &= ~(0x01 << (h & 0x7));
1095 		return;
1096 	default:
1097 #ifdef STANDALONE
1098 		printf("clrblock bad fs_frag %d\n", fs->fs_frag);
1099 #else
1100 		fprintf(stderr, "clrblock bad fs_frag %d\n", fs->fs_frag);
1101 #endif
1102 		return;
1103 	}
1104 }
1105 
1106 /*
1107  * put a block into the map
1108  */
1109 setblock(fs, cp, h)
1110 	struct fs *fs;
1111 	unsigned char *cp;
1112 	int h;
1113 {
1114 	switch (fs->fs_frag) {
1115 	case 8:
1116 		cp[h] = 0xff;
1117 		return;
1118 	case 4:
1119 		cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
1120 		return;
1121 	case 2:
1122 		cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
1123 		return;
1124 	case 1:
1125 		cp[h >> 3] |= (0x01 << (h & 0x7));
1126 		return;
1127 	default:
1128 #ifdef STANDALONE
1129 		printf("setblock bad fs_frag %d\n", fs->fs_frag);
1130 #else
1131 		fprintf(stderr, "setblock bad fs_frag %d\n", fs->fs_frag);
1132 #endif
1133 		return;
1134 	}
1135 }
1136