xref: /freebsd/sbin/fsck_ffs/fsutil.c (revision e3466a89fd9c3d0be2f831d42a5b5cf65cb0fd53)
1 /*
2  * Copyright (c) 1980, 1986, 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  * 4. Neither the name of the University nor the names of its contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #if 0
31 #ifndef lint
32 static const char sccsid[] = "@(#)utilities.c	8.6 (Berkeley) 5/19/95";
33 #endif /* not lint */
34 #endif
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37 
38 #include <sys/param.h>
39 #include <sys/time.h>
40 #include <sys/types.h>
41 #include <sys/sysctl.h>
42 #include <sys/disk.h>
43 #include <sys/disklabel.h>
44 #include <sys/ioctl.h>
45 #include <sys/stat.h>
46 
47 #include <ufs/ufs/dinode.h>
48 #include <ufs/ufs/dir.h>
49 #include <ufs/ffs/fs.h>
50 
51 #include <err.h>
52 #include <errno.h>
53 #include <string.h>
54 #include <ctype.h>
55 #include <fstab.h>
56 #include <stdint.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <time.h>
60 #include <unistd.h>
61 
62 #include "fsck.h"
63 
64 static void slowio_start(void);
65 static void slowio_end(void);
66 static void printIOstats(void);
67 
68 static long diskreads, totaldiskreads, totalreads; /* Disk cache statistics */
69 static struct timespec startpass, finishpass;
70 struct timeval slowio_starttime;
71 int slowio_delay_usec = 10000;	/* Initial IO delay for background fsck */
72 int slowio_pollcnt;
73 static TAILQ_HEAD(buflist, bufarea) bufhead;	/* head of buffer cache list */
74 static int numbufs;				/* size of buffer cache */
75 static char *buftype[BT_NUMBUFTYPES] = BT_NAMES;
76 
77 int
78 ftypeok(union dinode *dp)
79 {
80 	switch (DIP(dp, di_mode) & IFMT) {
81 
82 	case IFDIR:
83 	case IFREG:
84 	case IFBLK:
85 	case IFCHR:
86 	case IFLNK:
87 	case IFSOCK:
88 	case IFIFO:
89 		return (1);
90 
91 	default:
92 		if (debug)
93 			printf("bad file type 0%o\n", DIP(dp, di_mode));
94 		return (0);
95 	}
96 }
97 
98 int
99 reply(const char *question)
100 {
101 	int persevere;
102 	char c;
103 
104 	if (preen)
105 		pfatal("INTERNAL ERROR: GOT TO reply()");
106 	persevere = !strcmp(question, "CONTINUE");
107 	printf("\n");
108 	if (!persevere && (nflag || (fswritefd < 0 && bkgrdflag == 0))) {
109 		printf("%s? no\n\n", question);
110 		resolved = 0;
111 		return (0);
112 	}
113 	if (yflag || (persevere && nflag)) {
114 		printf("%s? yes\n\n", question);
115 		return (1);
116 	}
117 	do	{
118 		printf("%s? [yn] ", question);
119 		(void) fflush(stdout);
120 		c = getc(stdin);
121 		while (c != '\n' && getc(stdin) != '\n') {
122 			if (feof(stdin)) {
123 				resolved = 0;
124 				return (0);
125 			}
126 		}
127 	} while (c != 'y' && c != 'Y' && c != 'n' && c != 'N');
128 	printf("\n");
129 	if (c == 'y' || c == 'Y')
130 		return (1);
131 	resolved = 0;
132 	return (0);
133 }
134 
135 /*
136  * Look up state information for an inode.
137  */
138 struct inostat *
139 inoinfo(ino_t inum)
140 {
141 	static struct inostat unallocated = { USTATE, 0, 0 };
142 	struct inostatlist *ilp;
143 	int iloff;
144 
145 	if (inum > maxino)
146 		errx(EEXIT, "inoinfo: inumber %ju out of range",
147 		    (uintmax_t)inum);
148 	ilp = &inostathead[inum / sblock.fs_ipg];
149 	iloff = inum % sblock.fs_ipg;
150 	if (iloff >= ilp->il_numalloced)
151 		return (&unallocated);
152 	return (&ilp->il_stat[iloff]);
153 }
154 
155 /*
156  * Malloc buffers and set up cache.
157  */
158 void
159 bufinit(void)
160 {
161 	struct bufarea *bp;
162 	long bufcnt, i;
163 	char *bufp;
164 
165 	pbp = pdirbp = (struct bufarea *)0;
166 	bufp = malloc((unsigned int)sblock.fs_bsize);
167 	if (bufp == 0)
168 		errx(EEXIT, "cannot allocate buffer pool");
169 	cgblk.b_un.b_buf = bufp;
170 	initbarea(&cgblk, BT_CYLGRP);
171 	TAILQ_INIT(&bufhead);
172 	bufcnt = MAXBUFS;
173 	if (bufcnt < MINBUFS)
174 		bufcnt = MINBUFS;
175 	for (i = 0; i < bufcnt; i++) {
176 		bp = (struct bufarea *)malloc(sizeof(struct bufarea));
177 		bufp = malloc((unsigned int)sblock.fs_bsize);
178 		if (bp == NULL || bufp == NULL) {
179 			if (i >= MINBUFS)
180 				break;
181 			errx(EEXIT, "cannot allocate buffer pool");
182 		}
183 		bp->b_un.b_buf = bufp;
184 		TAILQ_INSERT_HEAD(&bufhead, bp, b_list);
185 		initbarea(bp, BT_UNKNOWN);
186 	}
187 	numbufs = i;	/* save number of buffers */
188 	for (i = 0; i < BT_NUMBUFTYPES; i++) {
189 		readtime[i].tv_sec = totalreadtime[i].tv_sec = 0;
190 		readtime[i].tv_nsec = totalreadtime[i].tv_nsec = 0;
191 		readcnt[i] = totalreadcnt[i] = 0;
192 	}
193 }
194 
195 /*
196  * Manage a cache of directory blocks.
197  */
198 struct bufarea *
199 getdatablk(ufs2_daddr_t blkno, long size, int type)
200 {
201 	struct bufarea *bp;
202 
203 	TAILQ_FOREACH(bp, &bufhead, b_list)
204 		if (bp->b_bno == fsbtodb(&sblock, blkno))
205 			goto foundit;
206 	TAILQ_FOREACH_REVERSE(bp, &bufhead, buflist, b_list)
207 		if ((bp->b_flags & B_INUSE) == 0)
208 			break;
209 	if (bp == NULL)
210 		errx(EEXIT, "deadlocked buffer pool");
211 	bp->b_type = type;
212 	getblk(bp, blkno, size);
213 	/* fall through */
214 foundit:
215 	if (debug && bp->b_type != type)
216 		printf("Buffer type changed from %s to %s\n",
217 		    buftype[bp->b_type], buftype[type]);
218 	TAILQ_REMOVE(&bufhead, bp, b_list);
219 	TAILQ_INSERT_HEAD(&bufhead, bp, b_list);
220 	bp->b_flags |= B_INUSE;
221 	return (bp);
222 }
223 
224 /*
225  * Timespec operations (from <sys/time.h>).
226  */
227 #define	timespecsub(vvp, uvp)						\
228 	do {								\
229 		(vvp)->tv_sec -= (uvp)->tv_sec;				\
230 		(vvp)->tv_nsec -= (uvp)->tv_nsec;			\
231 		if ((vvp)->tv_nsec < 0) {				\
232 			(vvp)->tv_sec--;				\
233 			(vvp)->tv_nsec += 1000000000;			\
234 		}							\
235 	} while (0)
236 #define	timespecadd(vvp, uvp)						\
237 	do {								\
238 		(vvp)->tv_sec += (uvp)->tv_sec;				\
239 		(vvp)->tv_nsec += (uvp)->tv_nsec;			\
240 		if ((vvp)->tv_nsec >= 1000000000) {			\
241 			(vvp)->tv_sec++;				\
242 			(vvp)->tv_nsec -= 1000000000;			\
243 		}							\
244 	} while (0)
245 
246 void
247 getblk(struct bufarea *bp, ufs2_daddr_t blk, long size)
248 {
249 	ufs2_daddr_t dblk;
250 	struct timespec start, finish;
251 
252 	dblk = fsbtodb(&sblock, blk);
253 	if (bp->b_bno == dblk) {
254 		totalreads++;
255 	} else {
256 		flush(fswritefd, bp);
257 		if (debug) {
258 			readcnt[bp->b_type]++;
259 			clock_gettime(CLOCK_REALTIME_PRECISE, &start);
260 		}
261 		bp->b_errs = blread(fsreadfd, bp->b_un.b_buf, dblk, size);
262 		if (debug) {
263 			clock_gettime(CLOCK_REALTIME_PRECISE, &finish);
264 			timespecsub(&finish, &start);
265 			timespecadd(&readtime[bp->b_type], &finish);
266 		}
267 		bp->b_bno = dblk;
268 		bp->b_size = size;
269 	}
270 }
271 
272 void
273 flush(int fd, struct bufarea *bp)
274 {
275 	int i, j;
276 
277 	if (!bp->b_dirty)
278 		return;
279 	bp->b_dirty = 0;
280 	if (fswritefd < 0) {
281 		pfatal("WRITING IN READ_ONLY MODE.\n");
282 		return;
283 	}
284 	if (bp->b_errs != 0)
285 		pfatal("WRITING %sZERO'ED BLOCK %lld TO DISK\n",
286 		    (bp->b_errs == bp->b_size / dev_bsize) ? "" : "PARTIALLY ",
287 		    (long long)bp->b_bno);
288 	bp->b_errs = 0;
289 	blwrite(fd, bp->b_un.b_buf, bp->b_bno, bp->b_size);
290 	if (bp != &sblk)
291 		return;
292 	for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) {
293 		blwrite(fswritefd, (char *)sblock.fs_csp + i,
294 		    fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag),
295 		    sblock.fs_cssize - i < sblock.fs_bsize ?
296 		    sblock.fs_cssize - i : sblock.fs_bsize);
297 	}
298 }
299 
300 void
301 rwerror(const char *mesg, ufs2_daddr_t blk)
302 {
303 
304 	if (bkgrdcheck)
305 		exit(EEXIT);
306 	if (preen == 0)
307 		printf("\n");
308 	pfatal("CANNOT %s: %ld", mesg, (long)blk);
309 	if (reply("CONTINUE") == 0)
310 		exit(EEXIT);
311 }
312 
313 void
314 ckfini(int markclean)
315 {
316 	struct bufarea *bp, *nbp;
317 	int ofsmodified, cnt;
318 
319 	if (bkgrdflag) {
320 		unlink(snapname);
321 		if ((!(sblock.fs_flags & FS_UNCLEAN)) != markclean) {
322 			cmd.value = FS_UNCLEAN;
323 			cmd.size = markclean ? -1 : 1;
324 			if (sysctlbyname("vfs.ffs.setflags", 0, 0,
325 			    &cmd, sizeof cmd) == -1)
326 				rwerror("SET FILE SYSTEM FLAGS", FS_UNCLEAN);
327 			if (!preen) {
328 				printf("\n***** FILE SYSTEM MARKED %s *****\n",
329 				    markclean ? "CLEAN" : "DIRTY");
330 				if (!markclean)
331 					rerun = 1;
332 			}
333 		} else if (!preen && !markclean) {
334 			printf("\n***** FILE SYSTEM STILL DIRTY *****\n");
335 			rerun = 1;
336 		}
337 	}
338 	if (debug && totalreads > 0)
339 		printf("cache with %d buffers missed %ld of %ld (%d%%)\n",
340 		    numbufs, totaldiskreads, totalreads,
341 		    (int)(totaldiskreads * 100 / totalreads));
342 	if (fswritefd < 0) {
343 		(void)close(fsreadfd);
344 		return;
345 	}
346 	flush(fswritefd, &sblk);
347 	if (havesb && cursnapshot == 0 && sblock.fs_magic == FS_UFS2_MAGIC &&
348 	    sblk.b_bno != sblock.fs_sblockloc / dev_bsize &&
349 	    !preen && reply("UPDATE STANDARD SUPERBLOCK")) {
350 		sblk.b_bno = sblock.fs_sblockloc / dev_bsize;
351 		sbdirty();
352 		flush(fswritefd, &sblk);
353 	}
354 	flush(fswritefd, &cgblk);
355 	free(cgblk.b_un.b_buf);
356 	cnt = 0;
357 	TAILQ_FOREACH_REVERSE_SAFE(bp, &bufhead, buflist, b_list, nbp) {
358 		TAILQ_REMOVE(&bufhead, bp, b_list);
359 		cnt++;
360 		flush(fswritefd, bp);
361 		free(bp->b_un.b_buf);
362 		free((char *)bp);
363 	}
364 	if (numbufs != cnt)
365 		errx(EEXIT, "panic: lost %d buffers", numbufs - cnt);
366 	pbp = pdirbp = (struct bufarea *)0;
367 	if (cursnapshot == 0 && sblock.fs_clean != markclean) {
368 		if ((sblock.fs_clean = markclean) != 0) {
369 			sblock.fs_flags &= ~(FS_UNCLEAN | FS_NEEDSFSCK);
370 			sblock.fs_pendingblocks = 0;
371 			sblock.fs_pendinginodes = 0;
372 		}
373 		sbdirty();
374 		ofsmodified = fsmodified;
375 		flush(fswritefd, &sblk);
376 		fsmodified = ofsmodified;
377 		if (!preen) {
378 			printf("\n***** FILE SYSTEM MARKED %s *****\n",
379 			    markclean ? "CLEAN" : "DIRTY");
380 			if (!markclean)
381 				rerun = 1;
382 		}
383 	} else if (!preen) {
384 		if (markclean) {
385 			printf("\n***** FILE SYSTEM IS CLEAN *****\n");
386 		} else {
387 			printf("\n***** FILE SYSTEM STILL DIRTY *****\n");
388 			rerun = 1;
389 		}
390 	}
391 	(void)close(fsreadfd);
392 	(void)close(fswritefd);
393 }
394 
395 /*
396  * Print out I/O statistics.
397  */
398 void
399 IOstats(char *what)
400 {
401 	int i;
402 
403 	if (debug == 0)
404 		return;
405 	if (diskreads == 0) {
406 		printf("%s: no I/O\n\n", what);
407 		return;
408 	}
409 	if (startpass.tv_sec == 0)
410 		startpass = startprog;
411 	printf("%s: I/O statistics\n", what);
412 	printIOstats();
413 	totaldiskreads += diskreads;
414 	diskreads = 0;
415 	for (i = 0; i < BT_NUMBUFTYPES; i++) {
416 		timespecadd(&totalreadtime[i], &readtime[i]);
417 		totalreadcnt[i] += readcnt[i];
418 		readtime[i].tv_sec = readtime[i].tv_nsec = 0;
419 		readcnt[i] = 0;
420 	}
421 	clock_gettime(CLOCK_REALTIME_PRECISE, &startpass);
422 }
423 
424 void
425 finalIOstats(void)
426 {
427 	int i;
428 
429 	if (debug == 0)
430 		return;
431 	printf("Final I/O statistics\n");
432 	totaldiskreads += diskreads;
433 	diskreads = totaldiskreads;
434 	startpass = startprog;
435 	for (i = 0; i < BT_NUMBUFTYPES; i++) {
436 		timespecadd(&totalreadtime[i], &readtime[i]);
437 		totalreadcnt[i] += readcnt[i];
438 		readtime[i] = totalreadtime[i];
439 		readcnt[i] = totalreadcnt[i];
440 	}
441 	printIOstats();
442 }
443 
444 static void printIOstats(void)
445 {
446 	long long msec, totalmsec;
447 	int i;
448 
449 	clock_gettime(CLOCK_REALTIME_PRECISE, &finishpass);
450 	timespecsub(&finishpass, &startpass);
451 	msec = finishpass.tv_sec * 1000 + finishpass.tv_nsec / 1000000;
452 	printf("Running time: %lld msec\n", msec);
453 	printf("buffer reads by type:\n");
454 	for (totalmsec = 0, i = 0; i < BT_NUMBUFTYPES; i++)
455 		totalmsec += readtime[i].tv_sec * 1000 +
456 		    readtime[i].tv_nsec / 1000000;
457 	if (totalmsec == 0)
458 		totalmsec = 1;
459 	for (i = 0; i < BT_NUMBUFTYPES; i++) {
460 		if (readcnt[i] == 0)
461 			continue;
462 		msec = readtime[i].tv_sec * 1000 + readtime[i].tv_nsec / 1000000;
463 		printf("%21s:%8ld %2ld.%ld%% %8lld msec %2lld.%lld%%\n",
464 		    buftype[i], readcnt[i], readcnt[i] * 100 / diskreads,
465 		    (readcnt[i] * 1000 / diskreads) % 10, msec,
466 		    msec * 100 / totalmsec, (msec * 1000 / totalmsec) % 10);
467 	}
468 	printf("\n");
469 }
470 
471 int
472 blread(int fd, char *buf, ufs2_daddr_t blk, long size)
473 {
474 	char *cp;
475 	int i, errs;
476 	off_t offset;
477 
478 	offset = blk;
479 	offset *= dev_bsize;
480 	if (bkgrdflag)
481 		slowio_start();
482 	totalreads++;
483 	diskreads++;
484 	if (lseek(fd, offset, 0) < 0)
485 		rwerror("SEEK BLK", blk);
486 	else if (read(fd, buf, (int)size) == size) {
487 		if (bkgrdflag)
488 			slowio_end();
489 		return (0);
490 	}
491 	rwerror("READ BLK", blk);
492 	if (lseek(fd, offset, 0) < 0)
493 		rwerror("SEEK BLK", blk);
494 	errs = 0;
495 	memset(buf, 0, (size_t)size);
496 	printf("THE FOLLOWING DISK SECTORS COULD NOT BE READ:");
497 	for (cp = buf, i = 0; i < size; i += secsize, cp += secsize) {
498 		if (read(fd, cp, (int)secsize) != secsize) {
499 			(void)lseek(fd, offset + i + secsize, 0);
500 			if (secsize != dev_bsize && dev_bsize != 1)
501 				printf(" %jd (%jd),",
502 				    (intmax_t)(blk * dev_bsize + i) / secsize,
503 				    (intmax_t)blk + i / dev_bsize);
504 			else
505 				printf(" %jd,", (intmax_t)blk + i / dev_bsize);
506 			errs++;
507 		}
508 	}
509 	printf("\n");
510 	if (errs)
511 		resolved = 0;
512 	return (errs);
513 }
514 
515 void
516 blwrite(int fd, char *buf, ufs2_daddr_t blk, ssize_t size)
517 {
518 	int i;
519 	char *cp;
520 	off_t offset;
521 
522 	if (fd < 0)
523 		return;
524 	offset = blk;
525 	offset *= dev_bsize;
526 	if (lseek(fd, offset, 0) < 0)
527 		rwerror("SEEK BLK", blk);
528 	else if (write(fd, buf, size) == size) {
529 		fsmodified = 1;
530 		return;
531 	}
532 	resolved = 0;
533 	rwerror("WRITE BLK", blk);
534 	if (lseek(fd, offset, 0) < 0)
535 		rwerror("SEEK BLK", blk);
536 	printf("THE FOLLOWING SECTORS COULD NOT BE WRITTEN:");
537 	for (cp = buf, i = 0; i < size; i += dev_bsize, cp += dev_bsize)
538 		if (write(fd, cp, dev_bsize) != dev_bsize) {
539 			(void)lseek(fd, offset + i + dev_bsize, 0);
540 			printf(" %jd,", (intmax_t)blk + i / dev_bsize);
541 		}
542 	printf("\n");
543 	return;
544 }
545 
546 void
547 blerase(int fd, ufs2_daddr_t blk, long size)
548 {
549 	off_t ioarg[2];
550 
551 	if (fd < 0)
552 		return;
553 	ioarg[0] = blk * dev_bsize;
554 	ioarg[1] = size;
555 	ioctl(fd, DIOCGDELETE, ioarg);
556 	/* we don't really care if we succeed or not */
557 	return;
558 }
559 
560 /*
561  * Verify cylinder group's magic number and other parameters.  If the
562  * test fails, offer an option to rebuild the whole cylinder group.
563  */
564 int
565 check_cgmagic(int cg, struct cg *cgp)
566 {
567 
568 	/*
569 	 * Extended cylinder group checks.
570 	 */
571 	if (cg_chkmagic(cgp) &&
572 	    ((sblock.fs_magic == FS_UFS1_MAGIC &&
573 	      cgp->cg_old_niblk == sblock.fs_ipg &&
574 	      cgp->cg_ndblk <= sblock.fs_fpg &&
575 	      cgp->cg_old_ncyl <= sblock.fs_old_cpg) ||
576 	     (sblock.fs_magic == FS_UFS2_MAGIC &&
577 	      cgp->cg_niblk == sblock.fs_ipg &&
578 	      cgp->cg_ndblk <= sblock.fs_fpg &&
579 	      cgp->cg_initediblk <= sblock.fs_ipg))) {
580 		return (1);
581 	}
582 	pfatal("CYLINDER GROUP %d: BAD MAGIC NUMBER", cg);
583 	if (!reply("REBUILD CYLINDER GROUP")) {
584 		printf("YOU WILL NEED TO RERUN FSCK.\n");
585 		rerun = 1;
586 		return (1);
587 	}
588 	/*
589 	 * Zero out the cylinder group and then initialize critical fields.
590 	 * Bit maps and summaries will be recalculated by later passes.
591 	 */
592 	memset(cgp, 0, (size_t)sblock.fs_cgsize);
593 	cgp->cg_magic = CG_MAGIC;
594 	cgp->cg_cgx = cg;
595 	cgp->cg_niblk = sblock.fs_ipg;
596 	cgp->cg_initediblk = sblock.fs_ipg < 2 * INOPB(&sblock) ?
597 	    sblock.fs_ipg : 2 * INOPB(&sblock);
598 	if (cgbase(&sblock, cg) + sblock.fs_fpg < sblock.fs_size)
599 		cgp->cg_ndblk = sblock.fs_fpg;
600 	else
601 		cgp->cg_ndblk = sblock.fs_size - cgbase(&sblock, cg);
602 	cgp->cg_iusedoff = &cgp->cg_space[0] - (u_char *)(&cgp->cg_firstfield);
603 	if (sblock.fs_magic == FS_UFS1_MAGIC) {
604 		cgp->cg_niblk = 0;
605 		cgp->cg_initediblk = 0;
606 		cgp->cg_old_ncyl = sblock.fs_old_cpg;
607 		cgp->cg_old_niblk = sblock.fs_ipg;
608 		cgp->cg_old_btotoff = cgp->cg_iusedoff;
609 		cgp->cg_old_boff = cgp->cg_old_btotoff +
610 		    sblock.fs_old_cpg * sizeof(int32_t);
611 		cgp->cg_iusedoff = cgp->cg_old_boff +
612 		    sblock.fs_old_cpg * sizeof(u_int16_t);
613 	}
614 	cgp->cg_freeoff = cgp->cg_iusedoff + howmany(sblock.fs_ipg, CHAR_BIT);
615 	cgp->cg_nextfreeoff = cgp->cg_freeoff + howmany(sblock.fs_fpg,CHAR_BIT);
616 	if (sblock.fs_contigsumsize > 0) {
617 		cgp->cg_nclusterblks = cgp->cg_ndblk / sblock.fs_frag;
618 		cgp->cg_clustersumoff =
619 		    roundup(cgp->cg_nextfreeoff, sizeof(u_int32_t));
620 		cgp->cg_clustersumoff -= sizeof(u_int32_t);
621 		cgp->cg_clusteroff = cgp->cg_clustersumoff +
622 		    (sblock.fs_contigsumsize + 1) * sizeof(u_int32_t);
623 		cgp->cg_nextfreeoff = cgp->cg_clusteroff +
624 		    howmany(fragstoblks(&sblock, sblock.fs_fpg), CHAR_BIT);
625 	}
626 	cgdirty();
627 	return (0);
628 }
629 
630 /*
631  * allocate a data block with the specified number of fragments
632  */
633 ufs2_daddr_t
634 allocblk(long frags)
635 {
636 	int i, j, k, cg, baseblk;
637 	struct cg *cgp = &cgrp;
638 
639 	if (frags <= 0 || frags > sblock.fs_frag)
640 		return (0);
641 	for (i = 0; i < maxfsblock - sblock.fs_frag; i += sblock.fs_frag) {
642 		for (j = 0; j <= sblock.fs_frag - frags; j++) {
643 			if (testbmap(i + j))
644 				continue;
645 			for (k = 1; k < frags; k++)
646 				if (testbmap(i + j + k))
647 					break;
648 			if (k < frags) {
649 				j += k;
650 				continue;
651 			}
652 			cg = dtog(&sblock, i + j);
653 			getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize);
654 			if (!check_cgmagic(cg, cgp))
655 				return (0);
656 			baseblk = dtogd(&sblock, i + j);
657 			for (k = 0; k < frags; k++) {
658 				setbmap(i + j + k);
659 				clrbit(cg_blksfree(cgp), baseblk + k);
660 			}
661 			n_blks += frags;
662 			if (frags == sblock.fs_frag)
663 				cgp->cg_cs.cs_nbfree--;
664 			else
665 				cgp->cg_cs.cs_nffree -= frags;
666 			cgdirty();
667 			return (i + j);
668 		}
669 	}
670 	return (0);
671 }
672 
673 /*
674  * Free a previously allocated block
675  */
676 void
677 freeblk(ufs2_daddr_t blkno, long frags)
678 {
679 	struct inodesc idesc;
680 
681 	idesc.id_blkno = blkno;
682 	idesc.id_numfrags = frags;
683 	(void)pass4check(&idesc);
684 }
685 
686 /* Slow down IO so as to leave some disk bandwidth for other processes */
687 void
688 slowio_start()
689 {
690 
691 	/* Delay one in every 8 operations */
692 	slowio_pollcnt = (slowio_pollcnt + 1) & 7;
693 	if (slowio_pollcnt == 0) {
694 		gettimeofday(&slowio_starttime, NULL);
695 	}
696 }
697 
698 void
699 slowio_end()
700 {
701 	struct timeval tv;
702 	int delay_usec;
703 
704 	if (slowio_pollcnt != 0)
705 		return;
706 
707 	/* Update the slowdown interval. */
708 	gettimeofday(&tv, NULL);
709 	delay_usec = (tv.tv_sec - slowio_starttime.tv_sec) * 1000000 +
710 	    (tv.tv_usec - slowio_starttime.tv_usec);
711 	if (delay_usec < 64)
712 		delay_usec = 64;
713 	if (delay_usec > 2500000)
714 		delay_usec = 2500000;
715 	slowio_delay_usec = (slowio_delay_usec * 63 + delay_usec) >> 6;
716 	/* delay by 8 times the average IO delay */
717 	if (slowio_delay_usec > 64)
718 		usleep(slowio_delay_usec * 8);
719 }
720 
721 /*
722  * Find a pathname
723  */
724 void
725 getpathname(char *namebuf, ino_t curdir, ino_t ino)
726 {
727 	int len;
728 	char *cp;
729 	struct inodesc idesc;
730 	static int busy = 0;
731 
732 	if (curdir == ino && ino == ROOTINO) {
733 		(void)strcpy(namebuf, "/");
734 		return;
735 	}
736 	if (busy || !INO_IS_DVALID(curdir)) {
737 		(void)strcpy(namebuf, "?");
738 		return;
739 	}
740 	busy = 1;
741 	memset(&idesc, 0, sizeof(struct inodesc));
742 	idesc.id_type = DATA;
743 	idesc.id_fix = IGNORE;
744 	cp = &namebuf[MAXPATHLEN - 1];
745 	*cp = '\0';
746 	if (curdir != ino) {
747 		idesc.id_parent = curdir;
748 		goto namelookup;
749 	}
750 	while (ino != ROOTINO) {
751 		idesc.id_number = ino;
752 		idesc.id_func = findino;
753 		idesc.id_name = strdup("..");
754 		if ((ckinode(ginode(ino), &idesc) & FOUND) == 0)
755 			break;
756 	namelookup:
757 		idesc.id_number = idesc.id_parent;
758 		idesc.id_parent = ino;
759 		idesc.id_func = findname;
760 		idesc.id_name = namebuf;
761 		if ((ckinode(ginode(idesc.id_number), &idesc)&FOUND) == 0)
762 			break;
763 		len = strlen(namebuf);
764 		cp -= len;
765 		memmove(cp, namebuf, (size_t)len);
766 		*--cp = '/';
767 		if (cp < &namebuf[MAXNAMLEN])
768 			break;
769 		ino = idesc.id_number;
770 	}
771 	busy = 0;
772 	if (ino != ROOTINO)
773 		*--cp = '?';
774 	memmove(namebuf, cp, (size_t)(&namebuf[MAXPATHLEN] - cp));
775 }
776 
777 void
778 catch(int sig __unused)
779 {
780 
781 	ckfini(0);
782 	exit(12);
783 }
784 
785 /*
786  * When preening, allow a single quit to signal
787  * a special exit after file system checks complete
788  * so that reboot sequence may be interrupted.
789  */
790 void
791 catchquit(int sig __unused)
792 {
793 	printf("returning to single-user after file system check\n");
794 	returntosingle = 1;
795 	(void)signal(SIGQUIT, SIG_DFL);
796 }
797 
798 /*
799  * determine whether an inode should be fixed.
800  */
801 int
802 dofix(struct inodesc *idesc, const char *msg)
803 {
804 
805 	switch (idesc->id_fix) {
806 
807 	case DONTKNOW:
808 		if (idesc->id_type == DATA)
809 			direrror(idesc->id_number, msg);
810 		else
811 			pwarn("%s", msg);
812 		if (preen) {
813 			printf(" (SALVAGED)\n");
814 			idesc->id_fix = FIX;
815 			return (ALTERED);
816 		}
817 		if (reply("SALVAGE") == 0) {
818 			idesc->id_fix = NOFIX;
819 			return (0);
820 		}
821 		idesc->id_fix = FIX;
822 		return (ALTERED);
823 
824 	case FIX:
825 		return (ALTERED);
826 
827 	case NOFIX:
828 	case IGNORE:
829 		return (0);
830 
831 	default:
832 		errx(EEXIT, "UNKNOWN INODESC FIX MODE %d", idesc->id_fix);
833 	}
834 	/* NOTREACHED */
835 	return (0);
836 }
837 
838 #include <stdarg.h>
839 
840 /*
841  * An unexpected inconsistency occurred.
842  * Die if preening or file system is running with soft dependency protocol,
843  * otherwise just print message and continue.
844  */
845 void
846 pfatal(const char *fmt, ...)
847 {
848 	va_list ap;
849 	va_start(ap, fmt);
850 	if (!preen) {
851 		(void)vfprintf(stdout, fmt, ap);
852 		va_end(ap);
853 		if (usedsoftdep)
854 			(void)fprintf(stdout,
855 			    "\nUNEXPECTED SOFT UPDATE INCONSISTENCY\n");
856 		/*
857 		 * Force foreground fsck to clean up inconsistency.
858 		 */
859 		if (bkgrdflag) {
860 			cmd.value = FS_NEEDSFSCK;
861 			cmd.size = 1;
862 			if (sysctlbyname("vfs.ffs.setflags", 0, 0,
863 			    &cmd, sizeof cmd) == -1)
864 				pwarn("CANNOT SET FS_NEEDSFSCK FLAG\n");
865 			fprintf(stdout, "CANNOT RUN IN BACKGROUND\n");
866 			ckfini(0);
867 			exit(EEXIT);
868 		}
869 		return;
870 	}
871 	if (cdevname == NULL)
872 		cdevname = strdup("fsck");
873 	(void)fprintf(stdout, "%s: ", cdevname);
874 	(void)vfprintf(stdout, fmt, ap);
875 	(void)fprintf(stdout,
876 	    "\n%s: UNEXPECTED%sINCONSISTENCY; RUN fsck MANUALLY.\n",
877 	    cdevname, usedsoftdep ? " SOFT UPDATE " : " ");
878 	/*
879 	 * Force foreground fsck to clean up inconsistency.
880 	 */
881 	if (bkgrdflag) {
882 		cmd.value = FS_NEEDSFSCK;
883 		cmd.size = 1;
884 		if (sysctlbyname("vfs.ffs.setflags", 0, 0,
885 		    &cmd, sizeof cmd) == -1)
886 			pwarn("CANNOT SET FS_NEEDSFSCK FLAG\n");
887 	}
888 	ckfini(0);
889 	exit(EEXIT);
890 }
891 
892 /*
893  * Pwarn just prints a message when not preening or running soft dependency
894  * protocol, or a warning (preceded by filename) when preening.
895  */
896 void
897 pwarn(const char *fmt, ...)
898 {
899 	va_list ap;
900 	va_start(ap, fmt);
901 	if (preen)
902 		(void)fprintf(stdout, "%s: ", cdevname);
903 	(void)vfprintf(stdout, fmt, ap);
904 	va_end(ap);
905 }
906 
907 /*
908  * Stub for routines from kernel.
909  */
910 void
911 panic(const char *fmt, ...)
912 {
913 	va_list ap;
914 	va_start(ap, fmt);
915 	pfatal("INTERNAL INCONSISTENCY:");
916 	(void)vfprintf(stdout, fmt, ap);
917 	va_end(ap);
918 	exit(EEXIT);
919 }
920