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