xref: /openbsd/sbin/newfs/mkfs.c (revision 91f110e0)
1 /*	$OpenBSD: mkfs.c,v 1.85 2014/01/24 22:29:21 miod Exp $	*/
2 /*	$NetBSD: mkfs.c,v 1.25 1995/06/18 21:35:38 cgd Exp $	*/
3 
4 /*
5  * Copyright (c) 2002 Networks Associates Technology, Inc.
6  * All rights reserved.
7  *
8  * This software was developed for the FreeBSD Project by Marshall
9  * Kirk McKusick and Network Associates Laboratories, the Security
10  * Research Division of Network Associates, Inc. under DARPA/SPAWAR
11  * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS
12  * research program.
13  *
14  * Copyright (c) 1980, 1989, 1993
15  *	The Regents of the University of California.  All rights reserved.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions
19  * are met:
20  * 1. Redistributions of source code must retain the above copyright
21  *    notice, this list of conditions and the following disclaimer.
22  * 2. Redistributions in binary form must reproduce the above copyright
23  *    notice, this list of conditions and the following disclaimer in the
24  *    documentation and/or other materials provided with the distribution.
25  * 3. Neither the name of the University nor the names of its contributors
26  *    may be used to endorse or promote products derived from this software
27  *    without specific prior written permission.
28  *
29  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39  * SUCH DAMAGE.
40  */
41 
42 #include <sys/param.h>
43 #include <sys/time.h>
44 #include <sys/disklabel.h>
45 #include <sys/ioctl.h>
46 #include <sys/mman.h>
47 #include <sys/sysctl.h>
48 
49 #include <ufs/ufs/dinode.h>
50 #include <ufs/ufs/dir.h>
51 #include <ufs/ffs/fs.h>
52 
53 #include <err.h>
54 #include <string.h>
55 #include <stdlib.h>
56 #include <stdint.h>
57 #include <unistd.h>
58 
59 #ifndef STANDALONE
60 #include <a.out.h>
61 #include <stdio.h>
62 #include <errno.h>
63 #endif
64 
65 /*
66  * Default directory umask.
67  */
68 #define UMASK		0755
69 
70 #define POWEROF2(num)	(((num) & ((num) - 1)) == 0)
71 
72 /*
73  * 'Standard' bad FFS magic.
74  */
75 #define FS_BAD_MAGIC	0x19960408
76 
77 /*
78  * The minimum number of cylinder groups that should be created.
79  */
80 #define MINCYLGRPS	4
81 
82 /*
83  * variables set up by front end.
84  */
85 extern int	mfs;		/* run as the memory based filesystem */
86 extern int	Nflag;		/* run mkfs without writing file system */
87 extern int	Oflag;		/* format as an 4.3BSD file system */
88 extern daddr_t fssize;		/* file system size in 512-byte blocks. */
89 extern long long	sectorsize;	/* bytes/sector */
90 extern int	fsize;		/* fragment size */
91 extern int	bsize;		/* block size */
92 extern int	maxfrgspercg;	/* maximum fragments per cylinder group */
93 extern int	minfree;	/* free space threshold */
94 extern int	opt;		/* optimization preference (space or time) */
95 extern int	density;	/* number of bytes per inode */
96 extern int	maxbpg;		/* maximum blocks per file in a cyl group */
97 extern int	avgfilesize;	/* expected average file size */
98 extern int	avgfilesperdir;	/* expected number of files per directory */
99 extern int	quiet;		/* quiet flag */
100 extern caddr_t	membase;	/* start address of memory based filesystem */
101 
102 union fs_u {
103 	struct fs fs;
104 	char pad[SBSIZE];
105 } *fsun;
106 #define sblock	fsun->fs
107 
108 struct	csum *fscs;
109 
110 union cg_u {
111 	struct cg cg;
112 	char pad[MAXBSIZE];
113 } *cgun;
114 #define acg	cgun->cg
115 
116 union dinode {
117 	struct ufs1_dinode dp1;
118 	struct ufs2_dinode dp2;
119 };
120 
121 int	fsi, fso;
122 
123 static caddr_t iobuf;
124 static long iobufsize;
125 
126 daddr_t	alloc(int, int);
127 static int	charsperline(void);
128 static int	ilog2(int);
129 void		initcg(int, time_t);
130 void		wtfs(daddr_t, int, void *);
131 int		fsinit1(time_t, mode_t, uid_t, gid_t);
132 int		fsinit2(time_t);
133 int		makedir(struct direct *, int);
134 void		iput(union dinode *, ino_t);
135 void		setblock(struct fs *, unsigned char *, int);
136 void		clrblock(struct fs *, unsigned char *, int);
137 int		isblock(struct fs *, unsigned char *, int);
138 void		rdfs(daddr_t, int, void *);
139 void		mkfs(struct partition *, char *, int, int,
140 		    mode_t, uid_t, gid_t);
141 static		void checksz(void);
142 
143 #ifndef STANDALONE
144 volatile sig_atomic_t cur_cylno;
145 volatile const char *cur_fsys;
146 void	siginfo(int sig);
147 
148 void
149 siginfo(int sig)
150 {
151 	int save_errno = errno;
152 	char buf[128];
153 
154 	snprintf(buf, sizeof(buf), "%s: initializing cg %ld/%d\n",
155 	    cur_fsys, (long)cur_cylno, sblock.fs_ncg);
156 	write(STDERR_FILENO, buf, strlen(buf));
157 	errno = save_errno;
158 }
159 #endif
160 
161 void
162 mkfs(struct partition *pp, char *fsys, int fi, int fo, mode_t mfsmode,
163     uid_t mfsuid, gid_t mfsgid)
164 {
165 	time_t utime;
166 	quad_t sizepb;
167 	int i, j, width, origdensity, fragsperinode, minfpg, optimalfpg;
168 	int lastminfpg, mincylgrps;
169 	long cylno, csfrags;
170 	char tmpbuf[100];	/* XXX this will break in about 2,500 years */
171 
172 	if ((fsun = calloc(1, sizeof (union fs_u))) == NULL ||
173 	    (cgun = calloc(1, sizeof (union cg_u))) == NULL)
174 		err(1, "calloc");
175 
176 #ifndef STANDALONE
177 	time(&utime);
178 #endif
179 	if (mfs) {
180 		quad_t sz = (quad_t)fssize * DEV_BSIZE;
181 		if (sz > SIZE_T_MAX) {
182 			errno = ENOMEM;
183 			err(12, "mmap");
184 		}
185 		membase = mmap(NULL, sz, PROT_READ|PROT_WRITE,
186 		    MAP_ANON|MAP_PRIVATE, -1, (off_t)0);
187 		if (membase == MAP_FAILED)
188 			err(12, "mmap");
189 		madvise(membase, sz, MADV_RANDOM);
190 	}
191 	fsi = fi;
192 	fso = fo;
193 	/*
194 	 * Validate the given file system size.
195 	 * Verify that its last block can actually be accessed.
196 	 */
197 	if (Oflag <= 1 && fssize > INT_MAX)
198 		errx(13, "preposterous size %lld, max is %d", (long long)fssize,
199 		    INT_MAX);
200 	if (Oflag == 2 && fssize > MAXDISKSIZE)
201 		errx(13, "preposterous size %lld, max is %lld",
202 		    (long long)fssize, MAXDISKSIZE);
203 
204 	wtfs(fssize - (sectorsize / DEV_BSIZE), sectorsize, (char *)&sblock);
205 
206 	sblock.fs_postblformat = FS_DYNAMICPOSTBLFMT;
207 	sblock.fs_avgfilesize = avgfilesize;
208 	sblock.fs_avgfpdir = avgfilesperdir;
209 
210 	/*
211 	 * Collect and verify the block and fragment sizes.
212 	 */
213 	if (!POWEROF2(bsize)) {
214 		errx(16, "block size must be a power of 2, not %d", bsize);
215 	}
216 	if (!POWEROF2(fsize)) {
217 		errx(17, "fragment size must be a power of 2, not %d",
218 		     fsize);
219 	}
220 	if (fsize < sectorsize) {
221 		errx(18, "fragment size %d is too small, minimum is %lld",
222 		     fsize, sectorsize);
223 	}
224 	if (bsize < MINBSIZE) {
225 		errx(19, "block size %d is too small, minimum is %d",
226 		     bsize, MINBSIZE);
227 	}
228 	if (bsize > MAXBSIZE) {
229 		errx(19, "block size %d is too large, maximum is %d",
230 		     bsize, MAXBSIZE);
231 	}
232 	if (bsize < fsize) {
233 		errx(20, "block size (%d) cannot be smaller than fragment size (%d)",
234 		     bsize, fsize);
235 	}
236 	sblock.fs_bsize = bsize;
237 	sblock.fs_fsize = fsize;
238 
239 	/*
240 	 * Calculate the superblock bitmasks and shifts.
241 	 */
242 	sblock.fs_bmask = ~(sblock.fs_bsize - 1);
243 	sblock.fs_fmask = ~(sblock.fs_fsize - 1);
244 	sblock.fs_qbmask = ~sblock.fs_bmask;
245 	sblock.fs_qfmask = ~sblock.fs_fmask;
246 	sblock.fs_bshift = ilog2(sblock.fs_bsize);
247 	sblock.fs_fshift = ilog2(sblock.fs_fsize);
248 	sblock.fs_frag = numfrags(&sblock, sblock.fs_bsize);
249 	if (sblock.fs_frag > MAXFRAG) {
250 		errx(21, "fragment size %d is too small, minimum with block "
251 		    "size %d is %d", sblock.fs_fsize, sblock.fs_bsize,
252 		    sblock.fs_bsize / MAXFRAG);
253 	}
254 	sblock.fs_fragshift = ilog2(sblock.fs_frag);
255 	sblock.fs_fsbtodb = ilog2(sblock.fs_fsize / DEV_BSIZE);
256 	sblock.fs_size = dbtofsb(&sblock, fssize);
257 	sblock.fs_nspf = sblock.fs_fsize / DEV_BSIZE;
258 	sblock.fs_maxcontig = 1;
259 	sblock.fs_nrpos = 1;
260 	sblock.fs_cpg = 1;
261 
262 	/*
263 	 * Before the file system is fully initialized, mark it as invalid.
264 	 */
265 	sblock.fs_magic = FS_BAD_MAGIC;
266 
267 	/*
268 	 * Set the remaining superblock fields.  Note that for FFS1, media
269 	 * geometry fields are set to fake values.  This is for compatibility
270 	 * with really ancient kernels that might still inspect these values.
271 	 */
272 	if (Oflag <= 1) {
273 		sblock.fs_sblockloc = SBLOCK_UFS1;
274 		sblock.fs_nindir = sblock.fs_bsize / sizeof(int32_t);
275 		sblock.fs_inopb = sblock.fs_bsize / sizeof(struct ufs1_dinode);
276 		if (Oflag == 0) {
277 			sblock.fs_maxsymlinklen = 0;
278 			sblock.fs_inodefmt = FS_42INODEFMT;
279 		} else {
280 			sblock.fs_maxsymlinklen = MAXSYMLINKLEN_UFS1;
281 			sblock.fs_inodefmt = FS_44INODEFMT;
282 		}
283 		sblock.fs_cgoffset = 0;
284 		sblock.fs_cgmask = 0xffffffff;
285 		sblock.fs_ffs1_size = sblock.fs_size;
286 		sblock.fs_rotdelay = 0;
287 		sblock.fs_rps = 60;
288 		sblock.fs_interleave = 1;
289 		sblock.fs_trackskew = 0;
290 		sblock.fs_cpc = 0;
291 	} else {
292 		sblock.fs_inodefmt = FS_44INODEFMT;
293 		sblock.fs_sblockloc = SBLOCK_UFS2;
294 		sblock.fs_nindir = sblock.fs_bsize / sizeof(int64_t);
295 		sblock.fs_inopb = sblock.fs_bsize / sizeof(struct ufs2_dinode);
296 		sblock.fs_maxsymlinklen = MAXSYMLINKLEN_UFS2;
297 	}
298 	sblock.fs_sblkno =
299 	    roundup(howmany(sblock.fs_sblockloc + SBLOCKSIZE, sblock.fs_fsize),
300 		sblock.fs_frag);
301 	sblock.fs_cblkno = (int32_t)(sblock.fs_sblkno +
302 	    roundup(howmany(SBSIZE, sblock.fs_fsize), sblock.fs_frag));
303 	sblock.fs_iblkno = sblock.fs_cblkno + sblock.fs_frag;
304 	sblock.fs_maxfilesize = sblock.fs_bsize * NDADDR - 1;
305 	for (sizepb = sblock.fs_bsize, i = 0; i < NIADDR; i++) {
306 		sizepb *= NINDIR(&sblock);
307 		sblock.fs_maxfilesize += sizepb;
308 	}
309 #ifdef notyet
310 	/*
311 	 * It is impossible to create a snapshot in case fs_maxfilesize is
312 	 * smaller than fssize.
313 	 */
314 	if (sblock.fs_maxfilesize < (u_quad_t)fssize)
315 		warnx("WARNING: You will be unable to create snapshots on this "
316 		    "file system. Correct by using a larger blocksize.");
317 #endif
318 	/*
319 	 * Calculate the number of blocks to put into each cylinder group. The
320 	 * first goal is to have at least enough data blocks in each cylinder
321 	 * group to meet the density requirement. Once this goal is achieved
322 	 * we try to expand to have at least mincylgrps cylinder groups. Once
323 	 * this goal is achieved, we pack as many blocks into each cylinder
324 	 * group map as will fit.
325 	 *
326 	 * We start by calculating the smallest number of blocks that we can
327 	 * put into each cylinder group. If this is too big, we reduce the
328 	 * density until it fits.
329 	 */
330 	origdensity = density;
331 	for (;;) {
332 		fragsperinode = MAX(numfrags(&sblock, density), 1);
333 
334 		minfpg = fragsperinode * INOPB(&sblock);
335 		if (minfpg > sblock.fs_size)
336 			minfpg = sblock.fs_size;
337 
338 		sblock.fs_ipg = INOPB(&sblock);
339 		sblock.fs_fpg = roundup(sblock.fs_iblkno +
340 		    sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag);
341 		if (sblock.fs_fpg < minfpg)
342 			sblock.fs_fpg = minfpg;
343 
344 		sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode),
345 		    INOPB(&sblock));
346 		sblock.fs_fpg = roundup(sblock.fs_iblkno +
347 		    sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag);
348 		if (sblock.fs_fpg < minfpg)
349 			sblock.fs_fpg = minfpg;
350 
351 		sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode),
352 		    INOPB(&sblock));
353 
354 		if (CGSIZE(&sblock) < (unsigned long)sblock.fs_bsize)
355 			break;
356 
357 		density -= sblock.fs_fsize;
358 	}
359 	if (density != origdensity)
360 		warnx("density reduced from %d to %d bytes per inode",
361 		    origdensity, density);
362 
363 	/*
364 	 * Use a lower value for mincylgrps if the user specified a large
365 	 * number of blocks per cylinder group.  This is needed for, e.g. the
366 	 * install media which needs to pack 2 files very tightly.
367 	 */
368 	mincylgrps = MINCYLGRPS;
369 	if (maxfrgspercg != INT_MAX) {
370 		i = sblock.fs_size / maxfrgspercg;
371 		if (i < MINCYLGRPS)
372 			mincylgrps = i <= 0 ? 1 : i;
373 	}
374 
375 	/*
376 	 * Start packing more blocks into the cylinder group until it cannot
377 	 * grow any larger, the number of cylinder groups drops below
378 	 * mincylgrps, or we reach the requested size.
379 	 */
380 	for (;;) {
381 		sblock.fs_fpg += sblock.fs_frag;
382 		sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode),
383 		    INOPB(&sblock));
384 
385 		if (sblock.fs_fpg > maxfrgspercg ||
386 		    sblock.fs_size / sblock.fs_fpg < mincylgrps ||
387 		    CGSIZE(&sblock) > (unsigned long)sblock.fs_bsize)
388 			break;
389 	}
390 	sblock.fs_fpg -= sblock.fs_frag;
391 	sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode),
392 	    INOPB(&sblock));
393 	if (sblock.fs_fpg > maxfrgspercg)
394 		warnx("can't honour -c: minimum is %d", sblock.fs_fpg);
395 
396 	/*
397 	 * Check to be sure that the last cylinder group has enough blocks to
398 	 * be viable. If it is too small, reduce the number of blocks per
399 	 * cylinder group which will have the effect of moving more blocks into
400 	 * the last cylinder group.
401 	 */
402 	optimalfpg = sblock.fs_fpg;
403 	for (;;) {
404 		sblock.fs_ncg = howmany(sblock.fs_size, sblock.fs_fpg);
405 		lastminfpg = roundup(sblock.fs_iblkno +
406 		    sblock.fs_ipg / INOPF(&sblock), sblock.fs_frag);
407 		if (sblock.fs_size < lastminfpg)
408 			errx(28, "file system size %jd < minimum size of %d "
409 			    "fragments", (intmax_t)sblock.fs_size, lastminfpg);
410 
411 		if (sblock.fs_size % sblock.fs_fpg >= lastminfpg ||
412 		    sblock.fs_size % sblock.fs_fpg == 0)
413 			break;
414 
415 		sblock.fs_fpg -= sblock.fs_frag;
416 		sblock.fs_ipg = roundup(howmany(sblock.fs_fpg, fragsperinode),
417 		    INOPB(&sblock));
418 	}
419 
420 	if (optimalfpg != sblock.fs_fpg)
421 		warnx("reduced number of fragments per cylinder group from %d"
422 		    " to %d to enlarge last cylinder group", optimalfpg,
423 		    sblock.fs_fpg);
424 
425 	/*
426 	 * Back to filling superblock fields.
427 	 */
428 	if (Oflag <= 1) {
429 		sblock.fs_spc = sblock.fs_fpg * sblock.fs_nspf;
430 		sblock.fs_nsect = sblock.fs_spc;
431 		sblock.fs_npsect = sblock.fs_spc;
432 		sblock.fs_ncyl = sblock.fs_ncg;
433 	}
434 	sblock.fs_cgsize = fragroundup(&sblock, CGSIZE(&sblock));
435 	sblock.fs_dblkno = sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock);
436 	sblock.fs_csaddr = cgdmin(&sblock, 0);
437 	sblock.fs_cssize =
438 	    fragroundup(&sblock, sblock.fs_ncg * sizeof(struct csum));
439 
440 	fscs = (struct csum *)calloc(1, sblock.fs_cssize);
441 	if (fscs == NULL)
442 		errx(31, "calloc failed");
443 
444 	sblock.fs_sbsize = fragroundup(&sblock, sizeof(struct fs));
445 	if (sblock.fs_sbsize > SBLOCKSIZE)
446 		sblock.fs_sbsize = SBLOCKSIZE;
447 
448 	sblock.fs_minfree = minfree;
449 	sblock.fs_maxbpg = maxbpg;
450 	sblock.fs_optim = opt;
451 	sblock.fs_cgrotor = 0;
452 	sblock.fs_pendingblocks = 0;
453 	sblock.fs_pendinginodes = 0;
454 	sblock.fs_fmod = 0;
455 	sblock.fs_ronly = 0;
456 	sblock.fs_state = 0;
457 	sblock.fs_clean = 1;
458 	sblock.fs_id[0] = (u_int32_t)utime;
459 	sblock.fs_id[1] = (u_int32_t)arc4random();
460 	sblock.fs_fsmnt[0] = '\0';
461 
462 	csfrags = howmany(sblock.fs_cssize, sblock.fs_fsize);
463 	sblock.fs_dsize = sblock.fs_size - sblock.fs_sblkno -
464 	    sblock.fs_ncg * (sblock.fs_dblkno - sblock.fs_sblkno);
465 
466 	sblock.fs_cstotal.cs_nbfree = fragstoblks(&sblock, sblock.fs_dsize) -
467 	    howmany(csfrags, sblock.fs_frag);
468 	sblock.fs_cstotal.cs_nffree = fragnum(&sblock, sblock.fs_size) +
469 	    (fragnum(&sblock, csfrags) > 0 ?
470 	    sblock.fs_frag - fragnum(&sblock, csfrags) : 0);
471 	sblock.fs_cstotal.cs_nifree = sblock.fs_ncg * sblock.fs_ipg - ROOTINO;
472 	sblock.fs_cstotal.cs_ndir = 0;
473 
474 	sblock.fs_dsize -= csfrags;
475 	sblock.fs_time = utime;
476 
477 	if (Oflag <= 1) {
478 		sblock.fs_ffs1_time = sblock.fs_time;
479 		sblock.fs_ffs1_dsize = sblock.fs_dsize;
480 		sblock.fs_ffs1_csaddr = sblock.fs_csaddr;
481 		sblock.fs_ffs1_cstotal.cs_ndir = sblock.fs_cstotal.cs_ndir;
482 		sblock.fs_ffs1_cstotal.cs_nbfree = sblock.fs_cstotal.cs_nbfree;
483 		sblock.fs_ffs1_cstotal.cs_nifree = sblock.fs_cstotal.cs_nifree;
484 		sblock.fs_ffs1_cstotal.cs_nffree = sblock.fs_cstotal.cs_nffree;
485 	}
486 
487 	/*
488 	 * Dump out summary information about file system.
489 	 */
490 	if (!mfs) {
491 #define B2MBFACTOR (1 / (1024.0 * 1024.0))
492 		printf("%s: %.1fMB in %jd sectors of %lld bytes\n", fsys,
493 		    (float)sblock.fs_size * sblock.fs_fsize * B2MBFACTOR,
494 		    (intmax_t)fsbtodb(&sblock, sblock.fs_size) /
495 		    (sectorsize / DEV_BSIZE), sectorsize);
496 		printf("%d cylinder groups of %.2fMB, %d blocks, %d"
497 		    " inodes each\n", sblock.fs_ncg,
498 		    (float)sblock.fs_fpg * sblock.fs_fsize * B2MBFACTOR,
499 		    sblock.fs_fpg / sblock.fs_frag, sblock.fs_ipg);
500 #undef B2MBFACTOR
501 		checksz();
502 	}
503 
504 	/*
505 	 * Wipe out old FFS1 superblock if necessary.
506 	 */
507 	if (Oflag >= 2) {
508 		union fs_u *fsun1;
509 		struct fs *fs1;
510 
511 		fsun1 = calloc(1, sizeof(union fs_u));
512 		if (fsun1 == NULL)
513 			err(39, "calloc");
514 		fs1 = &fsun1->fs;
515 		rdfs(SBLOCK_UFS1 / DEV_BSIZE, SBSIZE, (char *)fs1);
516 		if (fs1->fs_magic == FS_UFS1_MAGIC) {
517 			fs1->fs_magic = FS_BAD_MAGIC;
518 			wtfs(SBLOCK_UFS1 / DEV_BSIZE, SBSIZE, (char *)fs1);
519 		}
520 		free(fsun1);
521 	}
522 
523 	wtfs((int)sblock.fs_sblockloc / DEV_BSIZE, SBSIZE, (char *)&sblock);
524 	sblock.fs_magic = (Oflag <= 1) ? FS_UFS1_MAGIC : FS_UFS2_MAGIC;
525 
526 	/*
527 	 * Now build the cylinders group blocks and
528 	 * then print out indices of cylinder groups.
529 	 */
530 	if (!quiet)
531 		printf("super-block backups (for fsck -b #) at:\n");
532 #ifndef STANDALONE
533 	else if (!mfs && isatty(STDIN_FILENO)) {
534 		signal(SIGINFO, siginfo);
535 		cur_fsys = fsys;
536 	}
537 #endif
538 	i = 0;
539 	width = charsperline();
540 	/*
541 	* Allocate space for superblock, cylinder group map, and two sets of
542 	* inode blocks.
543 	*/
544 	if (sblock.fs_bsize < SBLOCKSIZE)
545 		iobufsize = SBLOCKSIZE + 3 * sblock.fs_bsize;
546 	else
547 		iobufsize = 4 * sblock.fs_bsize;
548 	if ((iobuf = malloc(iobufsize)) == 0)
549 		errx(38, "cannot allocate I/O buffer");
550 	bzero(iobuf, iobufsize);
551 	/*
552 	 * Make a copy of the superblock into the buffer that we will be
553 	 * writing out in each cylinder group.
554 	 */
555 	bcopy((char *)&sblock, iobuf, SBLOCKSIZE);
556 	for (cylno = 0; cylno < sblock.fs_ncg; cylno++) {
557 		cur_cylno = (sig_atomic_t)cylno;
558 		initcg(cylno, utime);
559 		if (quiet)
560 			continue;
561 		j = snprintf(tmpbuf, sizeof tmpbuf, " %lld,",
562 		    (long long)fsbtodb(&sblock, cgsblock(&sblock, cylno)));
563 		if (j >= sizeof tmpbuf)
564 			j = sizeof tmpbuf - 1;
565 		if (j == -1 || i+j >= width) {
566 			printf("\n");
567 			i = 0;
568 		}
569 		i += j;
570 		printf("%s", tmpbuf);
571 		fflush(stdout);
572 	}
573 	if (!quiet)
574 		printf("\n");
575 	if (Nflag && !mfs)
576 		exit(0);
577 	/*
578 	 * Now construct the initial file system, then write out the superblock.
579 	 */
580 	if (Oflag <= 1) {
581 		if (fsinit1(utime, mfsmode, mfsuid, mfsgid))
582 			errx(32, "fsinit1 failed");
583 		sblock.fs_ffs1_cstotal.cs_ndir = sblock.fs_cstotal.cs_ndir;
584 		sblock.fs_ffs1_cstotal.cs_nbfree = sblock.fs_cstotal.cs_nbfree;
585 		sblock.fs_ffs1_cstotal.cs_nifree = sblock.fs_cstotal.cs_nifree;
586 		sblock.fs_ffs1_cstotal.cs_nffree = sblock.fs_cstotal.cs_nffree;
587 	} else {
588 		if (fsinit2(utime))
589 			errx(32, "fsinit2 failed");
590 	}
591 
592 	wtfs((int)sblock.fs_sblockloc / DEV_BSIZE, SBSIZE, (char *)&sblock);
593 
594 	for (i = 0; i < sblock.fs_cssize; i += sblock.fs_bsize)
595 		wtfs(fsbtodb(&sblock, sblock.fs_csaddr + numfrags(&sblock, i)),
596 		    sblock.fs_cssize - i < sblock.fs_bsize ?
597 		    sblock.fs_cssize - i : sblock.fs_bsize,
598 		    ((char *)fscs) + i);
599 
600 	/*
601 	 * Update information about this partition in pack label, to that it may
602 	 * be updated on disk.
603 	 */
604 	pp->p_fstype = FS_BSDFFS;
605 	pp->p_fragblock =
606 	    DISKLABELV1_FFS_FRAGBLOCK(sblock.fs_fsize, sblock.fs_frag);
607 	pp->p_cpg = sblock.fs_cpg;
608 }
609 
610 /*
611  * Initialize a cylinder group.
612  */
613 void
614 initcg(int cylno, time_t utime)
615 {
616 	int i, j, d, dlower, dupper, blkno, start;
617 	daddr_t cbase, dmax;
618 	struct ufs1_dinode *dp1;
619 	struct ufs2_dinode *dp2;
620 	struct csum *cs;
621 
622 	/*
623 	 * Determine block bounds for cylinder group.  Allow space for
624 	 * super block summary information in first cylinder group.
625 	 */
626 	cbase = cgbase(&sblock, cylno);
627 	dmax = cbase + sblock.fs_fpg;
628 	if (dmax > sblock.fs_size)
629 		dmax = sblock.fs_size;
630 	if (fsbtodb(&sblock, cgsblock(&sblock, cylno)) + iobufsize / DEV_BSIZE
631 	    > fssize)
632 		errx(40, "inode table does not fit in cylinder group");
633 
634 	dlower = cgsblock(&sblock, cylno) - cbase;
635 	dupper = cgdmin(&sblock, cylno) - cbase;
636 	if (cylno == 0)
637 		dupper += howmany(sblock.fs_cssize, sblock.fs_fsize);
638 	cs = &fscs[cylno];
639 	memset(&acg, 0, sblock.fs_cgsize);
640 	acg.cg_ffs2_time = utime;
641 	acg.cg_magic = CG_MAGIC;
642 	acg.cg_cgx = cylno;
643 	acg.cg_ffs2_niblk = sblock.fs_ipg;
644 	acg.cg_initediblk = MIN(sblock.fs_ipg, 2 * INOPB(&sblock));
645 	acg.cg_ndblk = dmax - cbase;
646 
647 	start = sizeof(struct cg);
648 	if (Oflag <= 1) {
649 		/* Hack to maintain compatibility with old fsck. */
650 		if (cylno == sblock.fs_ncg - 1)
651 			acg.cg_ncyl = 0;
652 		else
653 			acg.cg_ncyl = sblock.fs_cpg;
654 		acg.cg_time = acg.cg_ffs2_time;
655 		acg.cg_ffs2_time = 0;
656 		acg.cg_niblk = acg.cg_ffs2_niblk;
657 		acg.cg_ffs2_niblk = 0;
658 		acg.cg_initediblk = 0;
659 		acg.cg_btotoff = start;
660 		acg.cg_boff = acg.cg_btotoff + sblock.fs_cpg * sizeof(int32_t);
661 		acg.cg_iusedoff = acg.cg_boff +
662 		    sblock.fs_cpg * sizeof(u_int16_t);
663 	} else {
664 		acg.cg_iusedoff = start;
665 	}
666 
667 	acg.cg_freeoff = acg.cg_iusedoff + howmany(sblock.fs_ipg, CHAR_BIT);
668 	acg.cg_nextfreeoff = acg.cg_freeoff + howmany(sblock.fs_fpg, CHAR_BIT);
669 	if (acg.cg_nextfreeoff > sblock.fs_cgsize)
670 		errx(37, "panic: cylinder group too big: %d > %d",
671 		    acg.cg_nextfreeoff, sblock.fs_cgsize);
672 	acg.cg_cs.cs_nifree += sblock.fs_ipg;
673 	if (cylno == 0) {
674 		for (i = 0; i < ROOTINO; i++) {
675 			setbit(cg_inosused(&acg), i);
676 			acg.cg_cs.cs_nifree--;
677 		}
678 	}
679 	if (cylno > 0) {
680 		/*
681 		 * In cylno 0, space is reserved for boot and super blocks.
682 		 */
683 		for (d = 0; d < dlower; d += sblock.fs_frag) {
684 			blkno = d / sblock.fs_frag;
685 			setblock(&sblock, cg_blksfree(&acg), blkno);
686 			acg.cg_cs.cs_nbfree++;
687 			if (Oflag <= 1) {
688 				cg_blktot(&acg)[cbtocylno(&sblock, d)]++;
689 				cg_blks(&sblock, &acg, cbtocylno(&sblock, d))
690 				    [cbtorpos(&sblock, d)]++;
691 			}
692 		}
693 	}
694 	if ((i = dupper % sblock.fs_frag)) {
695 		acg.cg_frsum[sblock.fs_frag - i]++;
696 		for (d = dupper + sblock.fs_frag - i; dupper < d; dupper++) {
697 			setbit(cg_blksfree(&acg), dupper);
698 			acg.cg_cs.cs_nffree++;
699 		}
700 	}
701 	for (d = dupper;
702 	    d + sblock.fs_frag <= acg.cg_ndblk;
703 	    d += sblock.fs_frag) {
704 		blkno = d / sblock.fs_frag;
705 		setblock(&sblock, cg_blksfree(&acg), blkno);
706 		acg.cg_cs.cs_nbfree++;
707 		if (Oflag <= 1) {
708 			cg_blktot(&acg)[cbtocylno(&sblock, d)]++;
709 			cg_blks(&sblock, &acg, cbtocylno(&sblock, d))
710 			    [cbtorpos(&sblock, d)]++;
711 		}
712 	}
713 	if (d < acg.cg_ndblk) {
714 		acg.cg_frsum[acg.cg_ndblk - d]++;
715 		for (; d < acg.cg_ndblk; d++) {
716 			setbit(cg_blksfree(&acg), d);
717 			acg.cg_cs.cs_nffree++;
718 		}
719 	}
720 	*cs = acg.cg_cs;
721 
722 	/*
723 	 * Write out the duplicate superblock, the cylinder group map
724 	 * and two blocks worth of inodes in a single write.
725 	 */
726 	start = sblock.fs_bsize > SBLOCKSIZE ? sblock.fs_bsize : SBLOCKSIZE;
727 	bcopy((char *)&acg, &iobuf[start], sblock.fs_cgsize);
728 	start += sblock.fs_bsize;
729 	dp1 = (struct ufs1_dinode *)(&iobuf[start]);
730 	dp2 = (struct ufs2_dinode *)(&iobuf[start]);
731 	for (i = MIN(sblock.fs_ipg, 2 * INOPB(&sblock)); i != 0; i--) {
732 		if (sblock.fs_magic == FS_UFS1_MAGIC) {
733 			dp1->di_gen = (u_int32_t)arc4random();
734 			dp1++;
735 		} else {
736 			dp2->di_gen = (u_int32_t)arc4random();
737 			dp2++;
738 		}
739 	}
740 	wtfs(fsbtodb(&sblock, cgsblock(&sblock, cylno)), iobufsize, iobuf);
741 
742 	if (Oflag <= 1) {
743 		/* Initialize inodes for FFS1. */
744 		for (i = 2 * sblock.fs_frag;
745 		    i < sblock.fs_ipg / INOPF(&sblock);
746 		    i += sblock.fs_frag) {
747 			dp1 = (struct ufs1_dinode *)(&iobuf[start]);
748 			for (j = 0; j < INOPB(&sblock); j++) {
749 				dp1->di_gen = (u_int32_t)arc4random();
750 				dp1++;
751 			}
752 			wtfs(fsbtodb(&sblock, cgimin(&sblock, cylno) + i),
753 			    sblock.fs_bsize, &iobuf[start]);
754 		}
755 	}
756 }
757 
758 #define PREDEFDIR 2
759 
760 struct direct root_dir[] = {
761 	{ ROOTINO, sizeof(struct direct), DT_DIR, 1, "." },
762 	{ ROOTINO, sizeof(struct direct), DT_DIR, 2, ".." },
763 };
764 struct odirect {
765 	u_int32_t d_ino;
766 	u_int16_t d_reclen;
767 	u_int16_t d_namlen;
768 	u_char	d_name[MAXNAMLEN + 1];
769 } oroot_dir[] = {
770 	{ ROOTINO, sizeof(struct direct), 1, "." },
771 	{ ROOTINO, sizeof(struct direct), 2, ".." },
772 };
773 
774 int
775 fsinit1(time_t utime, mode_t mfsmode, uid_t mfsuid, gid_t mfsgid)
776 {
777 	union dinode node;
778 
779 	/*
780 	 * Initialize the node
781 	 */
782 	memset(&node, 0, sizeof(node));
783 	node.dp1.di_atime = utime;
784 	node.dp1.di_mtime = utime;
785 	node.dp1.di_ctime = utime;
786 
787 	/*
788 	 * Create the root directory.
789 	 */
790 	if (mfs) {
791 		node.dp1.di_mode = IFDIR | mfsmode;
792 		node.dp1.di_uid = mfsuid;
793 		node.dp1.di_gid = mfsgid;
794 	} else {
795 		node.dp1.di_mode = IFDIR | UMASK;
796 		node.dp1.di_uid = geteuid();
797 		node.dp1.di_gid = getegid();
798 	}
799 	node.dp1.di_nlink = PREDEFDIR;
800 	if (Oflag == 0)
801 		node.dp1.di_size = makedir((struct direct *)oroot_dir,
802 		    PREDEFDIR);
803 	else
804 		node.dp1.di_size = makedir(root_dir, PREDEFDIR);
805 	node.dp1.di_db[0] = alloc(sblock.fs_fsize, node.dp1.di_mode);
806 	if (node.dp1.di_db[0] == 0)
807 		return (1);
808 
809 	node.dp1.di_blocks = btodb(fragroundup(&sblock, node.dp1.di_size));
810 
811 	wtfs(fsbtodb(&sblock, node.dp1.di_db[0]), sblock.fs_fsize, iobuf);
812 	iput(&node, ROOTINO);
813 
814 #ifdef notyet
815 	/*
816 	* Create the .snap directory.
817 	*/
818 	node.dp1.di_mode |= 020;
819 	node.dp1.di_gid = gid;
820 	node.dp1.di_nlink = SNAPLINKCNT;
821 	node.dp1.di_size = makedir(snap_dir, SNAPLINKCNT);
822 
823 	node.dp1.di_db[0] = alloc(sblock.fs_fsize, node.dp1.di_mode);
824 	if (node.dp1.di_db[0] == 0)
825 		return (1);
826 
827 	node.dp1.di_blocks = btodb(fragroundup(&sblock, node.dp1.di_size));
828 
829 	wtfs(fsbtodb(&sblock, node.dp1.di_db[0]), sblock.fs_fsize, iobuf);
830 	iput(&node, ROOTINO + 1);
831 #endif
832 	return (0);
833 }
834 
835 int
836 fsinit2(time_t utime)
837 {
838 	union dinode node;
839 
840 	/*
841 	 * Initialize the node.
842 	 */
843 	memset(&node, 0, sizeof(node));
844 	node.dp2.di_atime = utime;
845 	node.dp2.di_mtime = utime;
846 	node.dp2.di_ctime = utime;
847 
848 	/*
849 	 * Create the root directory.
850 	 */
851 	node.dp2.di_mode = IFDIR | UMASK;
852 	node.dp2.di_uid = geteuid();
853 	node.dp2.di_gid = getegid();
854 	node.dp2.di_nlink = PREDEFDIR;
855 	node.dp2.di_size = makedir(root_dir, PREDEFDIR);
856 
857 	node.dp2.di_db[0] = alloc(sblock.fs_fsize, node.dp2.di_mode);
858 	if (node.dp2.di_db[0] == 0)
859 		return (1);
860 
861 	node.dp2.di_blocks = btodb(fragroundup(&sblock, node.dp2.di_size));
862 
863 	wtfs(fsbtodb(&sblock, node.dp2.di_db[0]), sblock.fs_fsize, iobuf);
864 	iput(&node, ROOTINO);
865 
866 #ifdef notyet
867 	/*
868 	 * Create the .snap directory.
869 	 */
870 	node.dp2.di_mode |= 020;
871 	node.dp2.di_gid = gid;
872 	node.dp2.di_nlink = SNAPLINKCNT;
873 	node.dp2.di_size = makedir(snap_dir, SNAPLINKCNT);
874 
875 	node.dp2.di_db[0] = alloc(sblock.fs_fsize, node.dp2.di_mode);
876 	if (node.dp2.di_db[0] == 0)
877 		return (1);
878 
879 	node.dp2.di_blocks = btodb(fragroundup(&sblock, node.dp2.di_size));
880 
881 	wtfs(fsbtodb(&sblock, node.dp2.di_db[0]), sblock.fs_fsize, iobuf);
882 	iput(&node, ROOTINO + 1);
883 #endif
884 	return (0);
885 }
886 
887 /*
888  * construct a set of directory entries in "buf".
889  * return size of directory.
890  */
891 int
892 makedir(struct direct *protodir, int entries)
893 {
894 	char *cp;
895 	int i, spcleft;
896 
897 	spcleft = DIRBLKSIZ;
898 	for (cp = iobuf, i = 0; i < entries - 1; i++) {
899 		protodir[i].d_reclen = DIRSIZ(0, &protodir[i]);
900 		memcpy(cp, &protodir[i], protodir[i].d_reclen);
901 		cp += protodir[i].d_reclen;
902 		spcleft -= protodir[i].d_reclen;
903 	}
904 	protodir[i].d_reclen = spcleft;
905 	memcpy(cp, &protodir[i], DIRSIZ(0, &protodir[i]));
906 	return (DIRBLKSIZ);
907 }
908 
909 /*
910  * allocate a block or frag
911  */
912 daddr_t
913 alloc(int size, int mode)
914 {
915 	int i, frag;
916 	daddr_t d, blkno;
917 
918 	rdfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize,
919 	    (char *)&acg);
920 	if (acg.cg_magic != CG_MAGIC) {
921 		warnx("cg 0: bad magic number");
922 		return (0);
923 	}
924 	if (acg.cg_cs.cs_nbfree == 0) {
925 		warnx("first cylinder group ran out of space");
926 		return (0);
927 	}
928 	for (d = 0; d < acg.cg_ndblk; d += sblock.fs_frag)
929 		if (isblock(&sblock, cg_blksfree(&acg), d / sblock.fs_frag))
930 			goto goth;
931 	warnx("internal error: can't find block in cyl 0");
932 	return (0);
933 goth:
934 	blkno = fragstoblks(&sblock, d);
935 	clrblock(&sblock, cg_blksfree(&acg), blkno);
936 	acg.cg_cs.cs_nbfree--;
937 	sblock.fs_cstotal.cs_nbfree--;
938 	fscs[0].cs_nbfree--;
939 	if (mode & IFDIR) {
940 		acg.cg_cs.cs_ndir++;
941 		sblock.fs_cstotal.cs_ndir++;
942 		fscs[0].cs_ndir++;
943 	}
944 	if (Oflag <= 1) {
945 		cg_blktot(&acg)[cbtocylno(&sblock, d)]--;
946 		cg_blks(&sblock, &acg, cbtocylno(&sblock, d))
947 		    [cbtorpos(&sblock, d)]--;
948 	}
949 	if (size != sblock.fs_bsize) {
950 		frag = howmany(size, sblock.fs_fsize);
951 		fscs[0].cs_nffree += sblock.fs_frag - frag;
952 		sblock.fs_cstotal.cs_nffree += sblock.fs_frag - frag;
953 		acg.cg_cs.cs_nffree += sblock.fs_frag - frag;
954 		acg.cg_frsum[sblock.fs_frag - frag]++;
955 		for (i = frag; i < sblock.fs_frag; i++)
956 			setbit(cg_blksfree(&acg), d + i);
957 	}
958 	wtfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize,
959 	    (char *)&acg);
960 	return (d);
961 }
962 
963 /*
964  * Allocate an inode on the disk
965  */
966 void
967 iput(union dinode *ip, ino_t ino)
968 {
969 	daddr_t d;
970 
971 	if (Oflag <= 1)
972 		ip->dp1.di_gen = (u_int32_t)arc4random();
973 	else
974 		ip->dp2.di_gen = (u_int32_t)arc4random();
975 
976 	rdfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize,
977 	    (char *)&acg);
978 	if (acg.cg_magic != CG_MAGIC)
979 		errx(41, "cg 0: bad magic number");
980 
981 	acg.cg_cs.cs_nifree--;
982 	setbit(cg_inosused(&acg), ino);
983 
984 	wtfs(fsbtodb(&sblock, cgtod(&sblock, 0)), sblock.fs_cgsize,
985 	    (char *)&acg);
986 
987 	sblock.fs_cstotal.cs_nifree--;
988 	fscs[0].cs_nifree--;
989 	if (ino >= sblock.fs_ipg * sblock.fs_ncg)
990 		errx(32, "fsinit: inode value %llu out of range",
991 		    (unsigned long long)ino);
992 	d = fsbtodb(&sblock, ino_to_fsba(&sblock, ino));
993 	rdfs(d, sblock.fs_bsize, iobuf);
994 
995 	if (Oflag <= 1)
996 		((struct ufs1_dinode *)iobuf)[ino_to_fsbo(&sblock, ino)] =
997 		    ip->dp1;
998 	else
999 		((struct ufs2_dinode *)iobuf)[ino_to_fsbo(&sblock, ino)] =
1000 		    ip->dp2;
1001 
1002 	wtfs(d, sblock.fs_bsize, iobuf);
1003 }
1004 
1005 /*
1006  * read a block from the file system
1007  */
1008 void
1009 rdfs(daddr_t bno, int size, void *bf)
1010 {
1011 	int n;
1012 
1013 	if (mfs) {
1014 		memcpy(bf, membase + bno * DEV_BSIZE, size);
1015 		return;
1016 	}
1017 	n = pread(fsi, bf, size, (off_t)bno * DEV_BSIZE);
1018 	if (n != size) {
1019 		err(34, "rdfs: read error on block %lld", (long long)bno);
1020 	}
1021 }
1022 
1023 /*
1024  * write a block to the file system
1025  */
1026 void
1027 wtfs(daddr_t bno, int size, void *bf)
1028 {
1029 	int n;
1030 
1031 	if (mfs) {
1032 		memcpy(membase + bno * DEV_BSIZE, bf, size);
1033 		return;
1034 	}
1035 	if (Nflag)
1036 		return;
1037 	n = pwrite(fso, bf, size, (off_t)bno * DEV_BSIZE);
1038 	if (n != size) {
1039 		err(36, "wtfs: write error on block %lld", (long long)bno);
1040 	}
1041 }
1042 
1043 /*
1044  * check if a block is available
1045  */
1046 int
1047 isblock(struct fs *fs, unsigned char *cp, int h)
1048 {
1049 	unsigned char mask;
1050 
1051 	switch (fs->fs_frag) {
1052 	case 8:
1053 		return (cp[h] == 0xff);
1054 	case 4:
1055 		mask = 0x0f << ((h & 0x1) << 2);
1056 		return ((cp[h >> 1] & mask) == mask);
1057 	case 2:
1058 		mask = 0x03 << ((h & 0x3) << 1);
1059 		return ((cp[h >> 2] & mask) == mask);
1060 	case 1:
1061 		mask = 0x01 << (h & 0x7);
1062 		return ((cp[h >> 3] & mask) == mask);
1063 	default:
1064 #ifdef STANDALONE
1065 		printf("isblock bad fs_frag %d\n", fs->fs_frag);
1066 #else
1067 		warnx("isblock bad fs_frag %d", fs->fs_frag);
1068 #endif
1069 		return (0);
1070 	}
1071 }
1072 
1073 /*
1074  * take a block out of the map
1075  */
1076 void
1077 clrblock(struct fs *fs, unsigned char *cp, int h)
1078 {
1079 	switch ((fs)->fs_frag) {
1080 	case 8:
1081 		cp[h] = 0;
1082 		return;
1083 	case 4:
1084 		cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
1085 		return;
1086 	case 2:
1087 		cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
1088 		return;
1089 	case 1:
1090 		cp[h >> 3] &= ~(0x01 << (h & 0x7));
1091 		return;
1092 	default:
1093 #ifdef STANDALONE
1094 		printf("clrblock bad fs_frag %d\n", fs->fs_frag);
1095 #else
1096 		warnx("clrblock bad fs_frag %d", fs->fs_frag);
1097 #endif
1098 		return;
1099 	}
1100 }
1101 
1102 /*
1103  * put a block into the map
1104  */
1105 void
1106 setblock(struct fs *fs, unsigned char *cp, int h)
1107 {
1108 	switch (fs->fs_frag) {
1109 	case 8:
1110 		cp[h] = 0xff;
1111 		return;
1112 	case 4:
1113 		cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
1114 		return;
1115 	case 2:
1116 		cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
1117 		return;
1118 	case 1:
1119 		cp[h >> 3] |= (0x01 << (h & 0x7));
1120 		return;
1121 	default:
1122 #ifdef STANDALONE
1123 		printf("setblock bad fs_frag %d\n", fs->fs_frag);
1124 #else
1125 		warnx("setblock bad fs_frag %d", fs->fs_frag);
1126 #endif
1127 		return;
1128 	}
1129 }
1130 
1131 /*
1132  * Determine the number of characters in a
1133  * single line.
1134  */
1135 static int
1136 charsperline(void)
1137 {
1138 	int columns;
1139 	char *cp;
1140 	struct winsize ws;
1141 
1142 	columns = 0;
1143 	if (ioctl(0, TIOCGWINSZ, &ws) != -1)
1144 		columns = ws.ws_col;
1145 	if (columns == 0 && (cp = getenv("COLUMNS")))
1146 		columns = atoi(cp);
1147 	if (columns == 0)
1148 		columns = 80;   /* last resort */
1149 	return columns;
1150 }
1151 
1152 static int
1153 ilog2(int val)
1154 {
1155 	int n;
1156 
1157 	for (n = 0; n < sizeof(n) * CHAR_BIT; n++)
1158 		if (1 << n == val)
1159 			return (n);
1160 
1161 	errx(1, "ilog2: %d is not a power of 2\n", val);
1162 }
1163 
1164 struct inoinfo {
1165         struct  inoinfo *i_nexthash;    /* next entry in hash chain */
1166         struct  inoinfo *i_child, *i_sibling, *i_parentp;
1167         size_t  i_isize;                /* size of inode */
1168         ino_t   i_number;               /* inode number of this entry */
1169         ino_t   i_parent;               /* inode number of parent */
1170 
1171         ino_t   i_dotdot;               /* inode number of `..' */
1172         u_int   i_numblks;              /* size of block array in bytes */
1173         daddr_t i_blks[1];              /* actually longer */
1174 };
1175 
1176 static void
1177 checksz(void)
1178 {
1179 	unsigned long long allocate, maxino, maxfsblock, ndir, bound;
1180 	int mib[2];
1181 	size_t len;
1182 
1183 	mib[0] = CTL_HW;
1184 	mib[1] = HW_PHYSMEM64;
1185 	len = sizeof(bound);
1186 
1187 	if (sysctl(mib, 2, &bound, &len, NULL, 0) != 0)
1188 		err(1, "can't get physmem");
1189 	bound = MIN(MAXDSIZ, bound);
1190 
1191 	allocate = 0;
1192 	maxino = sblock.fs_ncg * (unsigned long long)sblock.fs_ipg;
1193 	maxfsblock = sblock.fs_size;
1194 	ndir = maxino / avgfilesperdir;
1195 
1196 	allocate += roundup(howmany(maxfsblock, NBBY), sizeof(int16_t));
1197 	allocate += (maxino + 1) * 3;
1198 	allocate += sblock.fs_ncg * sizeof(long);
1199 	allocate += (MAX(ndir, 128) + 10) * sizeof(struct inoinfo);
1200 	allocate += MAX(ndir, 128) * sizeof(struct inoinfo);
1201 
1202 	if (allocate > bound)
1203 		warnx("warning: fsck_ffs will need %lluMB; "
1204 		    "min(MAXDSIZ,physmem) is %lluMB",
1205 		    allocate / (1024ULL * 1024ULL),
1206 		    bound / (1024ULL * 1024ULL));
1207 }
1208