xref: /openbsd-src/sbin/newfs/mkfs.c (revision b2ea75c1b17e1a9a339660e7ed45cd24946b230e)
1 /*	$OpenBSD: mkfs.c,v 1.19 2001/07/07 18:26:16 deraadt Exp $	*/
2 /*	$NetBSD: mkfs.c,v 1.25 1995/06/18 21:35:38 cgd Exp $	*/
3 
4 /*
5  * Copyright (c) 1980, 1989, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. All advertising materials mentioning features or use of this software
17  *    must display the following acknowledgement:
18  *	This product includes software developed by the University of
19  *	California, Berkeley and its contributors.
20  * 4. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36 
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "@(#)mkfs.c	8.3 (Berkeley) 2/3/94";
40 #else
41 static char rcsid[] = "$OpenBSD: mkfs.c,v 1.19 2001/07/07 18:26:16 deraadt Exp $";
42 #endif
43 #endif /* not lint */
44 
45 #include <sys/param.h>
46 #include <sys/time.h>
47 #include <sys/wait.h>
48 #include <sys/resource.h>
49 #include <ufs/ufs/dinode.h>
50 #include <ufs/ufs/dir.h>
51 #include <ufs/ffs/fs.h>
52 #include <sys/disklabel.h>
53 #include <sys/ioctl.h>
54 
55 #include <string.h>
56 #include <stdlib.h>
57 #include <signal.h>
58 #include <unistd.h>
59 
60 #ifndef STANDALONE
61 #include <a.out.h>
62 #include <stdio.h>
63 #endif
64 
65 /*
66  * make file system for cylinder-group style file systems
67  */
68 
69 /*
70  * We limit the size of the inode map to be no more than a
71  * third of the cylinder group space, since we must leave at
72  * least an equal amount of space for the block map.
73  *
74  * N.B.: MAXIPG must be a multiple of INOPB(fs).
75  */
76 #define MAXIPG(fs)	roundup((fs)->fs_bsize * NBBY / 3, INOPB(fs))
77 
78 #define UMASK		0755
79 #define MAXINOPB	(MAXBSIZE / sizeof(struct dinode))
80 #define POWEROF2(num)	(((num) & ((num) - 1)) == 0)
81 
82 /*
83  * variables set up by front end.
84  */
85 extern int	mfs;		/* run as the memory based filesystem */
86 extern int	Nflag;		/* run mkfs without writing file system */
87 extern int	Oflag;		/* format as an 4.3BSD file system */
88 extern int	fssize;		/* file system size */
89 extern int	ntracks;	/* # tracks/cylinder */
90 extern int	nsectors;	/* # sectors/track */
91 extern int	nphyssectors;	/* # sectors/track including spares */
92 extern int	secpercyl;	/* sectors per cylinder */
93 extern int	sectorsize;	/* bytes/sector */
94 extern int	rpm;		/* revolutions/minute of drive */
95 extern int	interleave;	/* hardware sector interleave */
96 extern int	trackskew;	/* sector 0 skew, per track */
97 extern int	fsize;		/* fragment size */
98 extern int	bsize;		/* block size */
99 extern int	cpg;		/* cylinders/cylinder group */
100 extern int	cpgflg;		/* cylinders/cylinder group flag was given */
101 extern int	minfree;	/* free space threshold */
102 extern int	opt;		/* optimization preference (space or time) */
103 extern int	density;	/* number of bytes per inode */
104 extern int	maxcontig;	/* max contiguous blocks to allocate */
105 extern int	rotdelay;	/* rotational delay between blocks */
106 extern int	maxbpg;		/* maximum blocks per file in a cyl group */
107 extern int	nrpos;		/* # of distinguished rotational positions */
108 extern int	bbsize;		/* boot block size */
109 extern int	sbsize;		/* superblock size */
110 extern int	avgfilesize;	/* expected average file size */
111 extern int	avgfilesperdir;	/* expected number of files per directory */
112 extern int	quiet;		/* quiet flag */
113 extern u_long	memleft;	/* virtual memory available */
114 extern caddr_t	membase;	/* start address of memory based filesystem */
115 
116 union fs_u {
117 	struct fs fs;
118 	char pad[SBSIZE];
119 } *fsun;
120 #define sblock	fsun->fs
121 
122 struct	csum *fscs;
123 
124 union cg_u {
125 	struct cg cg;
126 	char pad[MAXBSIZE];
127 } *cgun;
128 #define acg	cgun->cg
129 
130 struct dinode *zino;
131 char	*buf;
132 
133 int	fsi, fso;
134 
135 daddr_t		alloc(int, int);
136 static int	charsperline();
137 void		initcg(int, time_t);
138 void		wtfs(daddr_t, int, void *);
139 void		fsinit(time_t);
140 int		makedir(struct direct *, int);
141 void		iput(struct dinode *, ino_t);
142 void		setblock(struct fs *, unsigned char *, int);
143 void		clrblock(struct fs *, unsigned char *, int);
144 int		isblock(struct fs *, unsigned char *, int);
145 void		rdfs(daddr_t, int, void *);
146 
147 void
148 mkfs(pp, fsys, fi, fo)
149 	struct partition *pp;
150 	char *fsys;
151 	int fi, fo;
152 {
153 	register long i, mincpc, mincpg, inospercg;
154 	long cylno, rpos, blk, j, warn = 0;
155 	long used, mincpgcnt, bpcg;
156 	long mapcramped, inodecramped;
157 	long postblsize, rotblsize, totalsbsize;
158 	pid_t ppid = -1;
159 	int status;
160 	time_t utime;
161 	quad_t sizepb;
162 	void started();
163 	int width;
164 	char tmpbuf[100];	/* XXX this will break in about 2,500 years */
165 
166 	if ((fsun = (union fs_u *)calloc(1, sizeof (union fs_u))) == 0 ||
167 	    (cgun = (union cg_u *)malloc(sizeof (union cg_u))) == 0 ||
168 	    (zino = (struct dinode *)malloc(MAXBSIZE)) == 0 ||
169 	    (buf = (char *)malloc(MAXBSIZE)) == 0) {
170 		printf("buffer malloc failed\n");
171 		exit(1);
172 	}
173 
174 #ifndef STANDALONE
175 	time(&utime);
176 #endif
177 	if (mfs) {
178 		ppid = getpid();
179 		(void) signal(SIGUSR1, started);
180 		if ((i = fork())) {
181 			if (i == -1) {
182 				perror("mfs");
183 				exit(10);
184 			}
185 			if (waitpid(i, &status, 0) != -1 && WIFEXITED(status))
186 				exit(WEXITSTATUS(status));
187 			exit(11);
188 			/* NOTREACHED */
189 		}
190 		(void)malloc(0);
191 		if (fssize * sectorsize > memleft)
192 			fssize = (memleft - 16384) / sectorsize;
193 		if ((membase = malloc(fssize * sectorsize)) == 0)
194 			exit(12);
195 	}
196 	fsi = fi;
197 	fso = fo;
198 	if (Oflag) {
199 		sblock.fs_inodefmt = FS_42INODEFMT;
200 		sblock.fs_maxsymlinklen = 0;
201 	} else {
202 		sblock.fs_inodefmt = FS_44INODEFMT;
203 		sblock.fs_maxsymlinklen = MAXSYMLINKLEN;
204 	}
205 	/*
206 	 * Validate the given file system size.
207 	 * Verify that its last block can actually be accessed.
208 	 */
209 	if (fssize <= 0)
210 		printf("preposterous size %d\n", fssize), exit(13);
211 	wtfs(fssize - 1, sectorsize, (char *)&sblock);
212 recalc:
213 	/*
214 	 * collect and verify the sector and track info
215 	 */
216 	sblock.fs_nsect = nsectors;
217 	sblock.fs_ntrak = ntracks;
218 	if (sblock.fs_ntrak <= 0)
219 		printf("preposterous ntrak %d\n", sblock.fs_ntrak), exit(14);
220 	if (sblock.fs_nsect <= 0)
221 		printf("preposterous nsect %d\n", sblock.fs_nsect), exit(15);
222 	/*
223 	 * collect and verify the filesystem density info
224 	 */
225 	sblock.fs_avgfilesize = avgfilesize;
226 	sblock.fs_avgfpdir = avgfilesperdir;
227 	if (sblock.fs_avgfilesize <= 0)
228 		printf("illegal expected average file size %d\n",
229 		    sblock.fs_avgfilesize), exit(14);
230 	if (sblock.fs_avgfpdir <= 0)
231 		printf("illegal expected number of files per directory %d\n",
232 		    sblock.fs_avgfpdir), exit(15);
233 	/*
234 	 * collect and verify the block and fragment sizes
235 	 */
236 	sblock.fs_bsize = bsize;
237 	sblock.fs_fsize = fsize;
238 	if (!POWEROF2(sblock.fs_bsize)) {
239 		printf("block size must be a power of 2, not %d\n",
240 		    sblock.fs_bsize);
241 		exit(16);
242 	}
243 	if (!POWEROF2(sblock.fs_fsize)) {
244 		printf("fragment size must be a power of 2, not %d\n",
245 		    sblock.fs_fsize);
246 		exit(17);
247 	}
248 	if (sblock.fs_fsize < sectorsize) {
249 		printf("fragment size %d is too small, minimum is %d\n",
250 		    sblock.fs_fsize, sectorsize);
251 		exit(18);
252 	}
253 	if (sblock.fs_bsize < MINBSIZE) {
254 		printf("block size %d is too small, minimum is %d\n",
255 		    sblock.fs_bsize, MINBSIZE);
256 		exit(19);
257 	}
258 	if (sblock.fs_bsize < sblock.fs_fsize) {
259 		printf("block size (%d) cannot be smaller than fragment size (%d)\n",
260 		    sblock.fs_bsize, sblock.fs_fsize);
261 		exit(20);
262 	}
263 	sblock.fs_bmask = ~(sblock.fs_bsize - 1);
264 	sblock.fs_fmask = ~(sblock.fs_fsize - 1);
265 	sblock.fs_qbmask = ~sblock.fs_bmask;
266 	sblock.fs_qfmask = ~sblock.fs_fmask;
267 	for (sblock.fs_bshift = 0, i = sblock.fs_bsize; i > 1; i >>= 1)
268 		sblock.fs_bshift++;
269 	for (sblock.fs_fshift = 0, i = sblock.fs_fsize; i > 1; i >>= 1)
270 		sblock.fs_fshift++;
271 	sblock.fs_frag = numfrags(&sblock, sblock.fs_bsize);
272 	for (sblock.fs_fragshift = 0, i = sblock.fs_frag; i > 1; i >>= 1)
273 		sblock.fs_fragshift++;
274 	if (sblock.fs_frag > MAXFRAG) {
275 		printf("fragment size %d is too small, minimum with block size %d is %d\n",
276 		    sblock.fs_fsize, sblock.fs_bsize,
277 		    sblock.fs_bsize / MAXFRAG);
278 		exit(21);
279 	}
280 	sblock.fs_nrpos = nrpos;
281 	sblock.fs_nindir = sblock.fs_bsize / sizeof(daddr_t);
282 	sblock.fs_inopb = sblock.fs_bsize / sizeof(struct dinode);
283 	sblock.fs_nspf = sblock.fs_fsize / sectorsize;
284 	for (sblock.fs_fsbtodb = 0, i = NSPF(&sblock); i > 1; i >>= 1)
285 		sblock.fs_fsbtodb++;
286 	sblock.fs_sblkno =
287 	    roundup(howmany(bbsize + sbsize, sblock.fs_fsize), sblock.fs_frag);
288 	sblock.fs_cblkno = (daddr_t)(sblock.fs_sblkno +
289 	    roundup(howmany(sbsize, sblock.fs_fsize), sblock.fs_frag));
290 	sblock.fs_iblkno = sblock.fs_cblkno + sblock.fs_frag;
291 	sblock.fs_cgoffset = roundup(
292 	    howmany(sblock.fs_nsect, NSPF(&sblock)), sblock.fs_frag);
293 	for (sblock.fs_cgmask = 0xffffffff, i = sblock.fs_ntrak; i > 1; i >>= 1)
294 		sblock.fs_cgmask <<= 1;
295 	if (!POWEROF2(sblock.fs_ntrak))
296 		sblock.fs_cgmask <<= 1;
297 	sblock.fs_maxfilesize = sblock.fs_bsize * NDADDR - 1;
298 	for (sizepb = sblock.fs_bsize, i = 0; i < NIADDR; i++) {
299 		sizepb *= NINDIR(&sblock);
300 		sblock.fs_maxfilesize += sizepb;
301 	}
302 	/*
303 	 * Validate specified/determined secpercyl
304 	 * and calculate minimum cylinders per group.
305 	 */
306 	sblock.fs_spc = secpercyl;
307 	for (sblock.fs_cpc = NSPB(&sblock), i = sblock.fs_spc;
308 	     sblock.fs_cpc > 1 && (i & 1) == 0;
309 	     sblock.fs_cpc >>= 1, i >>= 1)
310 		/* void */;
311 	mincpc = sblock.fs_cpc;
312 	bpcg = sblock.fs_spc * sectorsize;
313 	inospercg = roundup(bpcg / sizeof(struct dinode), INOPB(&sblock));
314 	if (inospercg > MAXIPG(&sblock))
315 		inospercg = MAXIPG(&sblock);
316 	used = (sblock.fs_iblkno + inospercg / INOPF(&sblock)) * NSPF(&sblock);
317 	mincpgcnt = howmany(sblock.fs_cgoffset * (~sblock.fs_cgmask) + used,
318 	    sblock.fs_spc);
319 	mincpg = roundup(mincpgcnt, mincpc);
320 	/*
321 	 * Ensure that cylinder group with mincpg has enough space
322 	 * for block maps.
323 	 */
324 	sblock.fs_cpg = mincpg;
325 	sblock.fs_ipg = inospercg;
326 	if (maxcontig > 1)
327 		sblock.fs_contigsumsize = MIN(maxcontig, FS_MAXCONTIG);
328 	mapcramped = 0;
329 	/* A cylinder group *must* fit inside one block so force it if not. */
330 	if (CGSIZE(&sblock) > sblock.fs_bsize && secpercyl > 1024 && ntracks > 1) {
331 		secpercyl /= 2;
332 		ntracks /= 2;
333 		goto recalc;
334 	}
335 	while (CGSIZE(&sblock) > sblock.fs_bsize) {
336 		mapcramped = 1;
337 		if (sblock.fs_bsize < MAXBSIZE) {
338 			sblock.fs_bsize <<= 1;
339 			if ((i & 1) == 0) {
340 				i >>= 1;
341 			} else {
342 				sblock.fs_cpc <<= 1;
343 				mincpc <<= 1;
344 				mincpg = roundup(mincpgcnt, mincpc);
345 				sblock.fs_cpg = mincpg;
346 			}
347 			sblock.fs_frag <<= 1;
348 			sblock.fs_fragshift += 1;
349 			if (sblock.fs_frag <= MAXFRAG)
350 				continue;
351 		}
352 		if (sblock.fs_fsize == sblock.fs_bsize) {
353 			printf("There is no block size that");
354 			printf(" can support this disk\n");
355 			exit(22);
356 		}
357 		sblock.fs_frag >>= 1;
358 		sblock.fs_fragshift -= 1;
359 		sblock.fs_fsize <<= 1;
360 		sblock.fs_nspf <<= 1;
361 	}
362 	/*
363 	 * Ensure that cylinder group with mincpg has enough space for inodes.
364 	 */
365 	inodecramped = 0;
366 	used *= sectorsize;
367 	inospercg = roundup((mincpg * bpcg - used) / density, INOPB(&sblock));
368 	sblock.fs_ipg = inospercg;
369 	while (inospercg > MAXIPG(&sblock)) {
370 		inodecramped = 1;
371 		if (mincpc == 1 || sblock.fs_frag == 1 ||
372 		    sblock.fs_bsize == MINBSIZE)
373 			break;
374 		printf("With a block size of %ld %s %ld\n",
375 		    (long)sblock.fs_bsize,
376 		    "minimum bytes per inode is",
377 		    (mincpg * bpcg - used) / MAXIPG(&sblock) + 1);
378 		sblock.fs_bsize >>= 1;
379 		sblock.fs_frag >>= 1;
380 		sblock.fs_fragshift -= 1;
381 		mincpc >>= 1;
382 		sblock.fs_cpg = roundup(mincpgcnt, mincpc);
383 		if (CGSIZE(&sblock) > sblock.fs_bsize) {
384 			sblock.fs_bsize <<= 1;
385 			break;
386 		}
387 		mincpg = sblock.fs_cpg;
388 		inospercg =
389 		    roundup((mincpg * bpcg - used) / density, INOPB(&sblock));
390 		sblock.fs_ipg = inospercg;
391 	}
392 	if (inodecramped) {
393 		if (inospercg > MAXIPG(&sblock)) {
394 			printf("Minimum bytes per inode is %ld\n",
395 			    (mincpg * bpcg - used) / MAXIPG(&sblock) + 1);
396 		} else if (!mapcramped) {
397 			printf("With %d bytes per inode, ", density);
398 			printf("minimum cylinders per group is %ld\n", mincpg);
399 		}
400 	}
401 	if (mapcramped) {
402 		printf("With %d sectors per cylinder, ", sblock.fs_spc);
403 		printf("minimum cylinders per group is %ld\n", mincpg);
404 	}
405 	if (inodecramped || mapcramped) {
406 		if (sblock.fs_bsize != bsize)
407 			printf("%s to be changed from %d to %d\n",
408 			    "This requires the block size",
409 			    bsize, sblock.fs_bsize);
410 		if (sblock.fs_fsize != fsize)
411 			printf("\t%s to be changed from %d to %d\n",
412 			    "and the fragment size",
413 			    fsize, sblock.fs_fsize);
414 		exit(23);
415 	}
416 	/*
417 	 * Calculate the number of cylinders per group
418 	 */
419 	sblock.fs_cpg = cpg;
420 	if (sblock.fs_cpg % mincpc != 0) {
421 		printf("%s groups must have a multiple of %ld cylinders\n",
422 			cpgflg ? "Cylinder" : "Warning: cylinder", mincpc);
423 		sblock.fs_cpg = roundup(sblock.fs_cpg, mincpc);
424 		if (!cpgflg)
425 			cpg = sblock.fs_cpg;
426 	}
427 	/*
428 	 * Must ensure there is enough space for inodes.
429 	 */
430 	sblock.fs_ipg = roundup((sblock.fs_cpg * bpcg - used) / density,
431 		INOPB(&sblock));
432 	while (sblock.fs_ipg > MAXIPG(&sblock)) {
433 		inodecramped = 1;
434 		sblock.fs_cpg -= mincpc;
435 		sblock.fs_ipg = roundup((sblock.fs_cpg * bpcg - used) / density,
436 			INOPB(&sblock));
437 	}
438 	/*
439 	 * Must ensure there is enough space to hold block map.
440 	 */
441 	if (CGSIZE(&sblock) > sblock.fs_bsize && secpercyl > 1024 && ntracks > 1) {
442 		secpercyl /= 2;
443 		ntracks /= 2;
444 		goto recalc;
445 	}
446 	while (CGSIZE(&sblock) > sblock.fs_bsize) {
447 		mapcramped = 1;
448 		sblock.fs_cpg -= mincpc;
449 		sblock.fs_ipg = roundup((sblock.fs_cpg * bpcg - used) / density,
450 			INOPB(&sblock));
451 	}
452 	sblock.fs_fpg = (sblock.fs_cpg * sblock.fs_spc) / NSPF(&sblock);
453 	if ((sblock.fs_cpg * sblock.fs_spc) % NSPB(&sblock) != 0) {
454 		printf("panic (fs_cpg * fs_spc) %% NSPF != 0");
455 		exit(24);
456 	}
457 	if (sblock.fs_cpg < mincpg) {
458 		printf("cylinder groups must have at least %ld cylinders\n",
459 			mincpg);
460 		exit(25);
461 	} else if (sblock.fs_cpg != cpg) {
462 		if (!cpgflg)
463 			printf("Warning: ");
464 		else if (!mapcramped && !inodecramped)
465 			exit(26);
466 		if (mapcramped && inodecramped)
467 			printf("Block size and bytes per inode restrict");
468 		else if (mapcramped)
469 			printf("Block size restricts");
470 		else
471 			printf("Bytes per inode restrict");
472 		printf(" cylinders per group to %d.\n", sblock.fs_cpg);
473 		if (cpgflg)
474 			exit(27);
475 	}
476 	sblock.fs_cgsize = fragroundup(&sblock, CGSIZE(&sblock));
477 	/*
478 	 * Now have size for file system and nsect and ntrak.
479 	 * Determine number of cylinders and blocks in the file system.
480 	 */
481 	sblock.fs_size = dbtofsb(&sblock, fssize);
482 	sblock.fs_ncyl = sblock.fs_size * NSPF(&sblock) / sblock.fs_spc;
483 	if (sblock.fs_size * NSPF(&sblock) > sblock.fs_ncyl * sblock.fs_spc) {
484 		sblock.fs_ncyl++;
485 		warn = 1;
486 	}
487 	if (sblock.fs_ncyl < 1) {
488 		printf("file systems must have at least one cylinder\n");
489 		exit(28);
490 	}
491 	/*
492 	 * Determine feasability/values of rotational layout tables.
493 	 *
494 	 * The size of the rotational layout tables is limited by the
495 	 * size of the superblock, SBSIZE. The amount of space available
496 	 * for tables is calculated as (SBSIZE - sizeof (struct fs)).
497 	 * The size of these tables is inversely proportional to the block
498 	 * size of the file system. The size increases if sectors per track
499 	 * are not powers of two, because more cylinders must be described
500 	 * by the tables before the rotational pattern repeats (fs_cpc).
501 	 */
502 	sblock.fs_interleave = interleave;
503 	sblock.fs_trackskew = trackskew;
504 	sblock.fs_npsect = nphyssectors;
505 	sblock.fs_postblformat = FS_DYNAMICPOSTBLFMT;
506 	sblock.fs_sbsize = fragroundup(&sblock, sizeof(struct fs));
507 	if (sblock.fs_ntrak == 1) {
508 		sblock.fs_cpc = 0;
509 		goto next;
510 	}
511 	postblsize = sblock.fs_nrpos * sblock.fs_cpc * sizeof(int16_t);
512 	rotblsize = sblock.fs_cpc * sblock.fs_spc / NSPB(&sblock);
513 	totalsbsize = sizeof(struct fs) + rotblsize;
514 	if (sblock.fs_nrpos == 8 && sblock.fs_cpc <= 16) {
515 		/* use old static table space */
516 		sblock.fs_postbloff = (char *)(&sblock.fs_opostbl[0][0]) -
517 		    (char *)(&sblock.fs_firstfield);
518 		sblock.fs_rotbloff = &sblock.fs_space[0] -
519 		    (u_char *)(&sblock.fs_firstfield);
520 	} else {
521 		/* use dynamic table space */
522 		sblock.fs_postbloff = &sblock.fs_space[0] -
523 		    (u_char *)(&sblock.fs_firstfield);
524 		sblock.fs_rotbloff = sblock.fs_postbloff + postblsize;
525 		totalsbsize += postblsize;
526 	}
527 	if (totalsbsize > SBSIZE ||
528 	    sblock.fs_nsect > (1 << NBBY) * NSPB(&sblock)) {
529 		printf("%s %s %d %s %d.%s",
530 		    "Warning: insufficient space in super block for\n",
531 		    "rotational layout tables with nsect", sblock.fs_nsect,
532 		    "and ntrak", sblock.fs_ntrak,
533 		    "\nFile system performance may be impaired.\n");
534 		sblock.fs_cpc = 0;
535 		goto next;
536 	}
537 	sblock.fs_sbsize = fragroundup(&sblock, totalsbsize);
538 	/*
539 	 * calculate the available blocks for each rotational position
540 	 */
541 	for (cylno = 0; cylno < sblock.fs_cpc; cylno++)
542 		for (rpos = 0; rpos < sblock.fs_nrpos; rpos++)
543 			fs_postbl(&sblock, cylno)[rpos] = -1;
544 	for (i = (rotblsize - 1) * sblock.fs_frag;
545 	     i >= 0; i -= sblock.fs_frag) {
546 		cylno = cbtocylno(&sblock, i);
547 		rpos = cbtorpos(&sblock, i);
548 		blk = fragstoblks(&sblock, i);
549 		if (fs_postbl(&sblock, cylno)[rpos] == -1)
550 			fs_rotbl(&sblock)[blk] = 0;
551 		else
552 			fs_rotbl(&sblock)[blk] =
553 			    fs_postbl(&sblock, cylno)[rpos] - blk;
554 		fs_postbl(&sblock, cylno)[rpos] = blk;
555 	}
556 next:
557 	/*
558 	 * Compute/validate number of cylinder groups.
559 	 */
560 	sblock.fs_ncg = sblock.fs_ncyl / sblock.fs_cpg;
561 	if (sblock.fs_ncyl % sblock.fs_cpg)
562 		sblock.fs_ncg++;
563 	sblock.fs_dblkno = sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock);
564 	i = MIN(~sblock.fs_cgmask, sblock.fs_ncg - 1);
565 	if (cgdmin(&sblock, i) - cgbase(&sblock, i) >= sblock.fs_fpg) {
566 		printf("inode blocks/cyl group (%ld) >= data blocks (%d)\n",
567 		    cgdmin(&sblock, i) - cgbase(&sblock, i) / sblock.fs_frag,
568 		    sblock.fs_fpg / sblock.fs_frag);
569 		printf("number of cylinders per cylinder group (%d) %s.\n",
570 		    sblock.fs_cpg, "must be increased");
571 		exit(29);
572 	}
573 	j = sblock.fs_ncg - 1;
574 	if ((i = sblock.fs_size - j * sblock.fs_fpg) < sblock.fs_fpg &&
575 	    cgdmin(&sblock, j) - cgbase(&sblock, j) > i) {
576 		if (j == 0) {
577 			printf("Filesystem must have at least %d sectors\n",
578 			    NSPF(&sblock) *
579 			    (cgdmin(&sblock, 0) + 3 * sblock.fs_frag));
580 			exit(30);
581 		}
582 		printf("Warning: inode blocks/cyl group (%ld) >= data blocks (%ld) in last\n",
583 		    (cgdmin(&sblock, j) - cgbase(&sblock, j)) / sblock.fs_frag,
584 		    i / sblock.fs_frag);
585 		printf("    cylinder group. This implies %ld sector(s) cannot be allocated.\n",
586 		    i * NSPF(&sblock));
587 		sblock.fs_ncg--;
588 		sblock.fs_ncyl -= sblock.fs_ncyl % sblock.fs_cpg;
589 		sblock.fs_size = sblock.fs_ncyl * sblock.fs_spc / NSPF(&sblock);
590 		fssize = fsbtodb(&sblock, sblock.fs_size);
591 		warn = 0;
592 	}
593 	if (warn && !mfs) {
594 		printf("Warning: %d sector(s) in last cylinder unallocated\n",
595 		    sblock.fs_spc -
596 		    (dbtofsb(&sblock, fssize) * NSPF(&sblock) -
597 		    (sblock.fs_ncyl - 1) * sblock.fs_spc));
598 	}
599 	/*
600 	 * fill in remaining fields of the super block
601 	 */
602 	sblock.fs_csaddr = cgdmin(&sblock, 0);
603 	sblock.fs_cssize =
604 	    fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum));
605 
606 	/*
607 	 * The superblock fields 'fs_csmask' and 'fs_csshift' are no
608 	 * longer used. However, we still initialise them so that the
609 	 * filesystem remains compatible with old kernels.
610 	 */
611 	i = sblock.fs_bsize / sizeof(struct csum);
612 	sblock.fs_csmask = ~(i - 1);
613 	for (sblock.fs_csshift = 0; i > 1; i >>= 1)
614 		sblock.fs_csshift++;
615 	if ((fscs = (struct csum *)calloc(1, sblock.fs_cssize)) == 0) {
616 		printf("cg summary malloc failed\n");
617 		exit(1);
618 	}
619 	sblock.fs_magic = FS_MAGIC;
620 	sblock.fs_rotdelay = rotdelay;
621 	sblock.fs_minfree = minfree;
622 	sblock.fs_maxcontig = maxcontig;
623 	sblock.fs_maxbpg = maxbpg;
624 	sblock.fs_rps = rpm / 60;
625 	sblock.fs_optim = opt;
626 	sblock.fs_cgrotor = 0;
627 	sblock.fs_cstotal.cs_ndir = 0;
628 	sblock.fs_cstotal.cs_nbfree = 0;
629 	sblock.fs_cstotal.cs_nifree = 0;
630 	sblock.fs_cstotal.cs_nffree = 0;
631 	sblock.fs_fmod = 0;
632 	sblock.fs_ronly = 0;
633 	sblock.fs_clean = FS_ISCLEAN;
634 #ifdef FSIRAND
635 	sblock.fs_id[0] = (u_int32_t)utime;
636 	sblock.fs_id[1] = (u_int32_t)arc4random();
637 #endif
638 	/*
639 	 * Dump out summary information about file system.
640 	 */
641 	if (!mfs) {
642 		printf("%s:\t%d sectors in %d %s of %d tracks, %d sectors\n",
643 		    fsys, sblock.fs_size * NSPF(&sblock), sblock.fs_ncyl,
644 		    "cylinders", sblock.fs_ntrak, sblock.fs_nsect);
645 #define B2MBFACTOR (1 / (1024.0 * 1024.0))
646 		printf("\t%.1fMB in %d cyl groups (%d c/g, %.2fMB/g, %d i/g)\n",
647 		    (float)sblock.fs_size * sblock.fs_fsize * B2MBFACTOR,
648 		    sblock.fs_ncg, sblock.fs_cpg,
649 		    (float)sblock.fs_fpg * sblock.fs_fsize * B2MBFACTOR,
650 		    sblock.fs_ipg);
651 #undef B2MBFACTOR
652 	}
653 	/*
654 	 * Now build the cylinders group blocks and
655 	 * then print out indices of cylinder groups.
656 	 */
657 	if (!quiet)
658 		printf("super-block backups (for fsck -b #) at:\n");
659 	i = 0;
660 	width = charsperline();
661 	for (cylno = 0; cylno < sblock.fs_ncg; cylno++) {
662 		initcg(cylno, utime);
663 		if (quiet)
664 			continue;
665 		j = sprintf(tmpbuf, " %ld,",
666 		    fsbtodb(&sblock, cgsblock(&sblock, cylno)));
667 		if (i+j >= width) {
668 			printf("\n");
669 			i = 0;
670 		}
671 		i += j;
672 		printf("%s", tmpbuf);
673 		fflush(stdout);
674 	}
675 	if (!quiet)
676 		printf("\n");
677 	if (Nflag && !mfs)
678 		exit(0);
679 	/*
680 	 * Now construct the initial file system,
681 	 * then write out the super-block.
682 	 */
683 	fsinit(utime);
684 	sblock.fs_time = utime;
685 	wtfs((int)SBOFF / sectorsize, sbsize, (char *)&sblock);
686 	for (i = 0; i < sblock.fs_cssize; i += sblock.fs_bsize)
687 		wtfs(fsbtodb(&sblock, sblock.fs_csaddr + numfrags(&sblock, i)),
688 			sblock.fs_cssize - i < sblock.fs_bsize ?
689 			    sblock.fs_cssize - i : sblock.fs_bsize,
690 			((char *)fscs) + i);
691 	/*
692 	 * Write out the duplicate super blocks
693 	 */
694 	for (cylno = 0; cylno < sblock.fs_ncg; cylno++)
695 		wtfs(fsbtodb(&sblock, cgsblock(&sblock, cylno)),
696 		    sbsize, (char *)&sblock);
697 	/*
698 	 * Update information about this partion in pack
699 	 * label, to that it may be updated on disk.
700 	 */
701 	pp->p_fstype = FS_BSDFFS;
702 	pp->p_fsize = sblock.fs_fsize;
703 	pp->p_frag = sblock.fs_frag;
704 	pp->p_cpg = sblock.fs_cpg;
705 	/*
706 	 * Notify parent process of success.
707 	 * Dissociate from session and tty.
708 	 */
709 	if (mfs) {
710 		kill(ppid, SIGUSR1);
711 		(void) setsid();
712 		(void) close(0);
713 		(void) close(1);
714 		(void) close(2);
715 		(void) chdir("/");
716 	}
717 }
718 
719 /*
720  * Initialize a cylinder group.
721  */
722 void
723 initcg(cylno, utime)
724 	int cylno;
725 	time_t utime;
726 {
727 	daddr_t cbase, d, dlower, dupper, dmax, blkno;
728 	long i, j;
729 	register struct csum *cs;
730 
731 	/*
732 	 * Determine block bounds for cylinder group.
733 	 * Allow space for super block summary information in first
734 	 * cylinder group.
735 	 */
736 	cbase = cgbase(&sblock, cylno);
737 	dmax = cbase + sblock.fs_fpg;
738 	if (dmax > sblock.fs_size)
739 		dmax = sblock.fs_size;
740 	dlower = cgsblock(&sblock, cylno) - cbase;
741 	dupper = cgdmin(&sblock, cylno) - cbase;
742 	if (cylno == 0)
743 		dupper += howmany(sblock.fs_cssize, sblock.fs_fsize);
744 	cs = fscs + cylno;
745 	memset(&acg, 0, sblock.fs_cgsize);
746 	acg.cg_time = utime;
747 	acg.cg_magic = CG_MAGIC;
748 	acg.cg_cgx = cylno;
749 	if (cylno == sblock.fs_ncg - 1)
750 		acg.cg_ncyl = sblock.fs_ncyl % sblock.fs_cpg;
751 	else
752 		acg.cg_ncyl = sblock.fs_cpg;
753 	acg.cg_niblk = sblock.fs_ipg;
754 	acg.cg_ndblk = dmax - cbase;
755 	if (sblock.fs_contigsumsize > 0)
756 		acg.cg_nclusterblks = acg.cg_ndblk / sblock.fs_frag;
757 	acg.cg_btotoff = &acg.cg_space[0] - (u_char *)(&acg.cg_firstfield);
758 	acg.cg_boff = acg.cg_btotoff + sblock.fs_cpg * sizeof(int32_t);
759 	acg.cg_iusedoff = acg.cg_boff +
760 		sblock.fs_cpg * sblock.fs_nrpos * sizeof(int16_t);
761 	acg.cg_freeoff = acg.cg_iusedoff + howmany(sblock.fs_ipg, NBBY);
762 	if (sblock.fs_contigsumsize <= 0) {
763 		acg.cg_nextfreeoff = acg.cg_freeoff +
764 		   howmany(sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock), NBBY);
765 	} else {
766 		acg.cg_clustersumoff = acg.cg_freeoff + howmany
767 		    (sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock), NBBY) -
768 		    sizeof(int32_t);
769 		acg.cg_clustersumoff =
770 		    roundup(acg.cg_clustersumoff, sizeof(int32_t));
771 		acg.cg_clusteroff = acg.cg_clustersumoff +
772 		    (sblock.fs_contigsumsize + 1) * sizeof(int32_t);
773 		acg.cg_nextfreeoff = acg.cg_clusteroff + howmany
774 		    (sblock.fs_cpg * sblock.fs_spc / NSPB(&sblock), NBBY);
775 	}
776 	if (acg.cg_nextfreeoff - (long)(&acg.cg_firstfield) > sblock.fs_cgsize) {
777 		printf("Panic: cylinder group too big\n");
778 		exit(37);
779 	}
780 	acg.cg_cs.cs_nifree += sblock.fs_ipg;
781 	if (cylno == 0)
782 		for (i = 0; i < ROOTINO; i++) {
783 			setbit(cg_inosused(&acg), i);
784 			acg.cg_cs.cs_nifree--;
785 		}
786 	for (i = 0; i < sblock.fs_ipg / INOPF(&sblock); i += sblock.fs_frag) {
787 #ifdef FSIRAND
788 		for (j = 0; j < sblock.fs_bsize / sizeof(struct dinode); j++)
789 			zino[j].di_gen = (u_int32_t)arc4random();
790 #endif
791 		wtfs(fsbtodb(&sblock, cgimin(&sblock, cylno) + i),
792 		    sblock.fs_bsize, (char *)zino);
793 	}
794 	if (cylno > 0) {
795 		/*
796 		 * In cylno 0, beginning space is reserved
797 		 * for boot and super blocks.
798 		 */
799 		for (d = 0; d < dlower; d += sblock.fs_frag) {
800 			blkno = d / sblock.fs_frag;
801 			setblock(&sblock, cg_blksfree(&acg), blkno);
802 			if (sblock.fs_contigsumsize > 0)
803 				setbit(cg_clustersfree(&acg), blkno);
804 			acg.cg_cs.cs_nbfree++;
805 			cg_blktot(&acg)[cbtocylno(&sblock, d)]++;
806 			cg_blks(&sblock, &acg, cbtocylno(&sblock, d))
807 			    [cbtorpos(&sblock, d)]++;
808 		}
809 		sblock.fs_dsize += dlower;
810 	}
811 	sblock.fs_dsize += acg.cg_ndblk - dupper;
812 	if ((i = dupper % sblock.fs_frag)) {
813 		acg.cg_frsum[sblock.fs_frag - i]++;
814 		for (d = dupper + sblock.fs_frag - i; dupper < d; dupper++) {
815 			setbit(cg_blksfree(&acg), dupper);
816 			acg.cg_cs.cs_nffree++;
817 		}
818 	}
819 	for (d = dupper; d + sblock.fs_frag <= dmax - cbase; ) {
820 		blkno = d / sblock.fs_frag;
821 		setblock(&sblock, cg_blksfree(&acg), blkno);
822 		if (sblock.fs_contigsumsize > 0)
823 			setbit(cg_clustersfree(&acg), blkno);
824 		acg.cg_cs.cs_nbfree++;
825 		cg_blktot(&acg)[cbtocylno(&sblock, d)]++;
826 		cg_blks(&sblock, &acg, cbtocylno(&sblock, d))
827 		    [cbtorpos(&sblock, d)]++;
828 		d += sblock.fs_frag;
829 	}
830 	if (d < dmax - cbase) {
831 		acg.cg_frsum[dmax - cbase - d]++;
832 		for (; d < dmax - cbase; d++) {
833 			setbit(cg_blksfree(&acg), d);
834 			acg.cg_cs.cs_nffree++;
835 		}
836 	}
837 	if (sblock.fs_contigsumsize > 0) {
838 		int32_t *sump = cg_clustersum(&acg);
839 		u_char *mapp = cg_clustersfree(&acg);
840 		int map = *mapp++;
841 		int bit = 1;
842 		int run = 0;
843 
844 		for (i = 0; i < acg.cg_nclusterblks; i++) {
845 			if ((map & bit) != 0) {
846 				run++;
847 			} else if (run != 0) {
848 				if (run > sblock.fs_contigsumsize)
849 					run = sblock.fs_contigsumsize;
850 				sump[run]++;
851 				run = 0;
852 			}
853 			if ((i & (NBBY - 1)) != (NBBY - 1)) {
854 				bit <<= 1;
855 			} else {
856 				map = *mapp++;
857 				bit = 1;
858 			}
859 		}
860 		if (run != 0) {
861 			if (run > sblock.fs_contigsumsize)
862 				run = sblock.fs_contigsumsize;
863 			sump[run]++;
864 		}
865 	}
866 	sblock.fs_cstotal.cs_ndir += acg.cg_cs.cs_ndir;
867 	sblock.fs_cstotal.cs_nffree += acg.cg_cs.cs_nffree;
868 	sblock.fs_cstotal.cs_nbfree += acg.cg_cs.cs_nbfree;
869 	sblock.fs_cstotal.cs_nifree += acg.cg_cs.cs_nifree;
870 	*cs = acg.cg_cs;
871 	wtfs(fsbtodb(&sblock, cgtod(&sblock, cylno)),
872 	    sblock.fs_bsize, (char *)&acg);
873 }
874 
875 /*
876  * initialize the file system
877  */
878 struct dinode node;
879 
880 #ifdef LOSTDIR
881 #define PREDEFDIR 3
882 #else
883 #define PREDEFDIR 2
884 #endif
885 
886 struct direct root_dir[] = {
887 	{ ROOTINO, sizeof(struct direct), DT_DIR, 1, "." },
888 	{ ROOTINO, sizeof(struct direct), DT_DIR, 2, ".." },
889 #ifdef LOSTDIR
890 	{ LOSTFOUNDINO, sizeof(struct direct), DT_DIR, 10, "lost+found" },
891 #endif
892 };
893 struct odirect {
894 	u_int32_t d_ino;
895 	u_int16_t d_reclen;
896 	u_int16_t d_namlen;
897 	u_char	d_name[MAXNAMLEN + 1];
898 } oroot_dir[] = {
899 	{ ROOTINO, sizeof(struct direct), 1, "." },
900 	{ ROOTINO, sizeof(struct direct), 2, ".." },
901 #ifdef LOSTDIR
902 	{ LOSTFOUNDINO, sizeof(struct direct), 10, "lost+found" },
903 #endif
904 };
905 #ifdef LOSTDIR
906 struct direct lost_found_dir[] = {
907 	{ LOSTFOUNDINO, sizeof(struct direct), DT_DIR, 1, "." },
908 	{ ROOTINO, sizeof(struct direct), DT_DIR, 2, ".." },
909 	{ 0, DIRBLKSIZ, 0, 0, 0 },
910 };
911 struct odirect olost_found_dir[] = {
912 	{ LOSTFOUNDINO, sizeof(struct direct), 1, "." },
913 	{ ROOTINO, sizeof(struct direct), 2, ".." },
914 	{ 0, DIRBLKSIZ, 0, 0 },
915 };
916 #endif
917 
918 void
919 fsinit(utime)
920 	time_t utime;
921 {
922 	/*
923 	 * initialize the node
924 	 */
925 	node.di_atime = utime;
926 	node.di_mtime = utime;
927 	node.di_ctime = utime;
928 #ifdef LOSTDIR
929 	/*
930 	 * create the lost+found directory
931 	 */
932 	if (Oflag) {
933 		int i;
934 
935 		(void)makedir((struct direct *)olost_found_dir, 2);
936 		for (i = DIRBLKSIZ; i < sblock.fs_bsize; i += DIRBLKSIZ)
937 			memcpy(&buf[i], &olost_found_dir[2],
938 			    DIRSIZ(0, &olost_found_dir[2]));
939 	} else {
940 		int i;
941 
942 		(void)makedir(lost_found_dir, 2);
943 		for (i = DIRBLKSIZ; i < sblock.fs_bsize; i += DIRBLKSIZ)
944 			memcpy(&buf[i], &lost_found_dir[2],
945 			    DIRSIZ(0, &lost_found_dir[2]));
946 	}
947 	node.di_mode = IFDIR | 1700;
948 	node.di_nlink = 2;
949 	node.di_size = sblock.fs_bsize;
950 	node.di_db[0] = alloc(node.di_size, node.di_mode);
951 	node.di_blocks = btodb(fragroundup(&sblock, node.di_size));
952 	wtfs(fsbtodb(&sblock, node.di_db[0]), node.di_size, buf);
953 	iput(&node, LOSTFOUNDINO);
954 #endif
955 	/*
956 	 * create the root directory
957 	 */
958 	if (mfs)
959 		node.di_mode = IFDIR | 01777;
960 	else
961 		node.di_mode = IFDIR | UMASK;
962 	node.di_nlink = PREDEFDIR;
963 	if (Oflag)
964 		node.di_size = makedir((struct direct *)oroot_dir, PREDEFDIR);
965 	else
966 		node.di_size = makedir(root_dir, PREDEFDIR);
967 	node.di_db[0] = alloc(sblock.fs_fsize, node.di_mode);
968 	node.di_blocks = btodb(fragroundup(&sblock, node.di_size));
969 	wtfs(fsbtodb(&sblock, node.di_db[0]), sblock.fs_fsize, buf);
970 	iput(&node, ROOTINO);
971 }
972 
973 /*
974  * construct a set of directory entries in "buf".
975  * return size of directory.
976  */
977 int
978 makedir(protodir, entries)
979 	struct direct *protodir;
980 	int entries;
981 {
982 	char *cp;
983 	int i, spcleft;
984 
985 	spcleft = DIRBLKSIZ;
986 	for (cp = buf, i = 0; i < entries - 1; i++) {
987 		protodir[i].d_reclen = DIRSIZ(0, &protodir[i]);
988 		memcpy(cp, &protodir[i], protodir[i].d_reclen);
989 		cp += protodir[i].d_reclen;
990 		spcleft -= protodir[i].d_reclen;
991 	}
992 	protodir[i].d_reclen = spcleft;
993 	memcpy(cp, &protodir[i], DIRSIZ(0, &protodir[i]));
994 	return (DIRBLKSIZ);
995 }
996 
997 /*
998  * allocate a block or frag
999  */
1000 daddr_t
1001 alloc(size, mode)
1002 	int size;
1003 	int mode;
1004 {
1005 	int i, frag;
1006 	daddr_t d, blkno;
1007 
1008 	rdfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize,
1009 	    (char *)&acg);
1010 	if (acg.cg_magic != CG_MAGIC) {
1011 		printf("cg 0: bad magic number\n");
1012 		return (0);
1013 	}
1014 	if (acg.cg_cs.cs_nbfree == 0) {
1015 		printf("first cylinder group ran out of space\n");
1016 		return (0);
1017 	}
1018 	for (d = 0; d < acg.cg_ndblk; d += sblock.fs_frag)
1019 		if (isblock(&sblock, cg_blksfree(&acg), d / sblock.fs_frag))
1020 			goto goth;
1021 	printf("internal error: can't find block in cyl 0\n");
1022 	return (0);
1023 goth:
1024 	blkno = fragstoblks(&sblock, d);
1025 	clrblock(&sblock, cg_blksfree(&acg), blkno);
1026 	if (sblock.fs_contigsumsize > 0)
1027 		clrbit(cg_clustersfree(&acg), blkno);
1028 	acg.cg_cs.cs_nbfree--;
1029 	sblock.fs_cstotal.cs_nbfree--;
1030 	fscs[0].cs_nbfree--;
1031 	if (mode & IFDIR) {
1032 		acg.cg_cs.cs_ndir++;
1033 		sblock.fs_cstotal.cs_ndir++;
1034 		fscs[0].cs_ndir++;
1035 	}
1036 	cg_blktot(&acg)[cbtocylno(&sblock, d)]--;
1037 	cg_blks(&sblock, &acg, cbtocylno(&sblock, d))[cbtorpos(&sblock, d)]--;
1038 	if (size != sblock.fs_bsize) {
1039 		frag = howmany(size, sblock.fs_fsize);
1040 		fscs[0].cs_nffree += sblock.fs_frag - frag;
1041 		sblock.fs_cstotal.cs_nffree += sblock.fs_frag - frag;
1042 		acg.cg_cs.cs_nffree += sblock.fs_frag - frag;
1043 		acg.cg_frsum[sblock.fs_frag - frag]++;
1044 		for (i = frag; i < sblock.fs_frag; i++)
1045 			setbit(cg_blksfree(&acg), d + i);
1046 	}
1047 	wtfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize,
1048 	    (char *)&acg);
1049 	return (d);
1050 }
1051 
1052 /*
1053  * Allocate an inode on the disk
1054  */
1055 void
1056 iput(ip, ino)
1057 	register struct dinode *ip;
1058 	register ino_t ino;
1059 {
1060 	struct dinode *buf =
1061 	   (struct dinode *)malloc(MAXINOPB * sizeof (struct dinode));
1062 	daddr_t d;
1063 	int c;
1064 
1065 #ifdef FSIRAND
1066 	ip->di_gen = (u_int32_t)arc4random();
1067 #endif
1068 	c = ino_to_cg(&sblock, ino);
1069 	rdfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize,
1070 	    (char *)&acg);
1071 	if (acg.cg_magic != CG_MAGIC) {
1072 		printf("cg 0: bad magic number\n");
1073 		exit(31);
1074 	}
1075 	acg.cg_cs.cs_nifree--;
1076 	setbit(cg_inosused(&acg), ino);
1077 	wtfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize,
1078 	    (char *)&acg);
1079 	sblock.fs_cstotal.cs_nifree--;
1080 	fscs[0].cs_nifree--;
1081 	if (ino >= sblock.fs_ipg * sblock.fs_ncg) {
1082 		printf("fsinit: inode value out of range (%d).\n", ino);
1083 		exit(32);
1084 	}
1085 	d = fsbtodb(&sblock, ino_to_fsba(&sblock, ino));
1086 	rdfs(d, sblock.fs_bsize, buf);
1087 	buf[ino_to_fsbo(&sblock, ino)] = *ip;
1088 	wtfs(d, sblock.fs_bsize, buf);
1089 	free(buf);
1090 }
1091 
1092 /*
1093  * Notify parent process that the filesystem has created itself successfully.
1094  */
1095 void
1096 started()
1097 {
1098 
1099 	_exit(0);
1100 }
1101 
1102 /*
1103  * Replace libc function with one suited to our needs.
1104  */
1105 static void *
1106 malloc(size)
1107 	size_t size;
1108 {
1109 	void *base, *i;
1110 	static u_long pgsz;
1111 	struct rlimit rlp;
1112 
1113 	if (pgsz == 0) {
1114 		base = sbrk(0);
1115 		pgsz = getpagesize() - 1;
1116 		i = (char *)((u_long)(base + pgsz) &~ pgsz);
1117 		base = sbrk(i - base);
1118 		if (getrlimit(RLIMIT_DATA, &rlp) < 0)
1119 			perror("getrlimit");
1120 		rlp.rlim_cur = rlp.rlim_max;
1121 		if (setrlimit(RLIMIT_DATA, &rlp) < 0)
1122 			perror("setrlimit");
1123 		memleft = rlp.rlim_max - (u_long)base;
1124 	}
1125 	size = (size + pgsz) &~ pgsz;
1126 	if (size > memleft)
1127 		size = memleft;
1128 	memleft -= size;
1129 	if (size == 0)
1130 		return (0);
1131 	return (sbrk(size));
1132 }
1133 
1134 /*
1135  * Replace libc function with one suited to our needs.
1136  */
1137 static void *
1138 realloc(ptr, size)
1139 	void *ptr;
1140 	size_t size;
1141 {
1142 	void *p;
1143 
1144 	if ((p = malloc(size)) == NULL)
1145 		return (NULL);
1146 	if (ptr) {
1147 		memcpy(p, ptr, size);
1148 		free(ptr);
1149 	}
1150 	return (p);
1151 }
1152 
1153 /*
1154  * Replace libc function with one suited to our needs.
1155  */
1156 static void *
1157 calloc(size, numelm)
1158 	size_t size;
1159 	size_t numelm;
1160 {
1161 	void	*base;
1162 
1163 	size *= numelm;
1164 	if ((base = malloc(size)) != 0)
1165 		memset(base, 0, size);
1166 	return (base);
1167 }
1168 
1169 /*
1170  * Replace libc function with one suited to our needs.
1171  */
1172 static void
1173 free(ptr)
1174 	void *ptr;
1175 {
1176 
1177 	/* do not worry about it for now */
1178 }
1179 
1180 /*
1181  * read a block from the file system
1182  */
1183 void
1184 rdfs(bno, size, bf)
1185 	daddr_t bno;
1186 	int size;
1187 	void *bf;
1188 {
1189 	int n;
1190 	off_t offset;
1191 
1192 	if (mfs) {
1193 		memcpy(bf, membase + bno * sectorsize, size);
1194 		return;
1195 	}
1196 	offset = bno;
1197 	offset *= sectorsize;
1198 	if (lseek(fsi, offset, SEEK_SET) < 0) {
1199 		printf("seek error: %lld\n", (long long)bno);
1200 		perror("rdfs");
1201 		exit(33);
1202 	}
1203 	n = read(fsi, bf, size);
1204 	if (n != size) {
1205 		printf("read error: %lld\n", (long long)bno);
1206 		perror("rdfs");
1207 		exit(34);
1208 	}
1209 }
1210 
1211 /*
1212  * write a block to the file system
1213  */
1214 void
1215 wtfs(bno, size, bf)
1216 	daddr_t bno;
1217 	int size;
1218 	void *bf;
1219 {
1220 	int n;
1221 	off_t offset;
1222 
1223 	if (mfs) {
1224 		memcpy(membase + bno * sectorsize, bf, size);
1225 		return;
1226 	}
1227 	if (Nflag)
1228 		return;
1229 	offset = bno;
1230 	offset *= sectorsize;
1231 	if (lseek(fso, offset, SEEK_SET) < 0) {
1232 		printf("seek error: %lld\n", (long long)bno);
1233 		perror("wtfs");
1234 		exit(35);
1235 	}
1236 	n = write(fso, bf, size);
1237 	if (n != size) {
1238 		printf("write error: %lld\n", (long long)bno);
1239 		perror("wtfs");
1240 		exit(36);
1241 	}
1242 }
1243 
1244 /*
1245  * check if a block is available
1246  */
1247 int
1248 isblock(fs, cp, h)
1249 	struct fs *fs;
1250 	unsigned char *cp;
1251 	int h;
1252 {
1253 	unsigned char mask;
1254 
1255 	switch (fs->fs_frag) {
1256 	case 8:
1257 		return (cp[h] == 0xff);
1258 	case 4:
1259 		mask = 0x0f << ((h & 0x1) << 2);
1260 		return ((cp[h >> 1] & mask) == mask);
1261 	case 2:
1262 		mask = 0x03 << ((h & 0x3) << 1);
1263 		return ((cp[h >> 2] & mask) == mask);
1264 	case 1:
1265 		mask = 0x01 << (h & 0x7);
1266 		return ((cp[h >> 3] & mask) == mask);
1267 	default:
1268 #ifdef STANDALONE
1269 		printf("isblock bad fs_frag %d\n", fs->fs_frag);
1270 #else
1271 		fprintf(stderr, "isblock bad fs_frag %d\n", fs->fs_frag);
1272 #endif
1273 		return (0);
1274 	}
1275 }
1276 
1277 /*
1278  * take a block out of the map
1279  */
1280 void
1281 clrblock(fs, cp, h)
1282 	struct fs *fs;
1283 	unsigned char *cp;
1284 	int h;
1285 {
1286 	switch ((fs)->fs_frag) {
1287 	case 8:
1288 		cp[h] = 0;
1289 		return;
1290 	case 4:
1291 		cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
1292 		return;
1293 	case 2:
1294 		cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
1295 		return;
1296 	case 1:
1297 		cp[h >> 3] &= ~(0x01 << (h & 0x7));
1298 		return;
1299 	default:
1300 #ifdef STANDALONE
1301 		printf("clrblock bad fs_frag %d\n", fs->fs_frag);
1302 #else
1303 		fprintf(stderr, "clrblock bad fs_frag %d\n", fs->fs_frag);
1304 #endif
1305 		return;
1306 	}
1307 }
1308 
1309 /*
1310  * put a block into the map
1311  */
1312 void
1313 setblock(fs, cp, h)
1314 	struct fs *fs;
1315 	unsigned char *cp;
1316 	int h;
1317 {
1318 	switch (fs->fs_frag) {
1319 	case 8:
1320 		cp[h] = 0xff;
1321 		return;
1322 	case 4:
1323 		cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
1324 		return;
1325 	case 2:
1326 		cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
1327 		return;
1328 	case 1:
1329 		cp[h >> 3] |= (0x01 << (h & 0x7));
1330 		return;
1331 	default:
1332 #ifdef STANDALONE
1333 		printf("setblock bad fs_frag %d\n", fs->fs_frag);
1334 #else
1335 		fprintf(stderr, "setblock bad fs_frag %d\n", fs->fs_frag);
1336 #endif
1337 		return;
1338 	}
1339 }
1340 
1341 /*
1342  * Determine the number of characters in a
1343  * single line.
1344  */
1345 static int
1346 charsperline()
1347 {
1348 	int columns;
1349 	char *cp;
1350 	struct winsize ws;
1351 	extern char *getenv();
1352 
1353 	columns = 0;
1354 	if (ioctl(0, TIOCGWINSZ, &ws) != -1)
1355 		columns = ws.ws_col;
1356 	if (columns == 0 && (cp = getenv("COLUMNS")))
1357 		columns = atoi(cp);
1358 	if (columns == 0)
1359 		columns = 80;   /* last resort */
1360 	return columns;
1361 }
1362