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