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