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