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