xref: /openbsd-src/sbin/fsck_ext2fs/pass5.c (revision b9fc9a728fce9c4289b7e9a992665e28d5629a54)
1*b9fc9a72Sderaadt /*	$OpenBSD: pass5.c,v 1.18 2015/01/16 06:39:57 deraadt Exp $	*/
20190393fSart /*	$NetBSD: pass5.c,v 1.7 2000/01/28 16:01:46 bouyer Exp $ */
38c424e8eSdownsj 
48c424e8eSdownsj /*
55ff4e0c8Sdownsj  * Copyright (c) 1997 Manuel Bouyer.
68c424e8eSdownsj  * Copyright (c) 1980, 1986, 1993
78c424e8eSdownsj  *	The Regents of the University of California.  All rights reserved.
88c424e8eSdownsj  *
98c424e8eSdownsj  * Redistribution and use in source and binary forms, with or without
108c424e8eSdownsj  * modification, are permitted provided that the following conditions
118c424e8eSdownsj  * are met:
128c424e8eSdownsj  * 1. Redistributions of source code must retain the above copyright
138c424e8eSdownsj  *    notice, this list of conditions and the following disclaimer.
148c424e8eSdownsj  * 2. Redistributions in binary form must reproduce the above copyright
158c424e8eSdownsj  *    notice, this list of conditions and the following disclaimer in the
168c424e8eSdownsj  *    documentation and/or other materials provided with the distribution.
171ef0d710Smillert  * 3. Neither the name of the University nor the names of its contributors
188c424e8eSdownsj  *    may be used to endorse or promote products derived from this software
198c424e8eSdownsj  *    without specific prior written permission.
208c424e8eSdownsj  *
218c424e8eSdownsj  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
228c424e8eSdownsj  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
238c424e8eSdownsj  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
248c424e8eSdownsj  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
258c424e8eSdownsj  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
268c424e8eSdownsj  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
278c424e8eSdownsj  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
288c424e8eSdownsj  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
298c424e8eSdownsj  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
308c424e8eSdownsj  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
318c424e8eSdownsj  * SUCH DAMAGE.
328c424e8eSdownsj  */
338c424e8eSdownsj 
34*b9fc9a72Sderaadt #include <sys/param.h>	/* setbit isset */
358c424e8eSdownsj #include <sys/time.h>
368a68c314Sderaadt #include <ufs/ufs/dinode.h>
378c424e8eSdownsj #include <ufs/ext2fs/ext2fs_dinode.h>
388c424e8eSdownsj #include <ufs/ext2fs/ext2fs.h>
398c424e8eSdownsj #include <string.h>
408c424e8eSdownsj #include <stdio.h>
41ce18c919Sdownsj #include <stdlib.h>
428c424e8eSdownsj 
438c424e8eSdownsj #include "fsutil.h"
448c424e8eSdownsj #include "fsck.h"
458c424e8eSdownsj #include "extern.h"
468c424e8eSdownsj 
478c424e8eSdownsj 
48c72b5b24Smillert void print_bmap(u_char *,u_int32_t);
498c424e8eSdownsj 
508c424e8eSdownsj void
pass5(void)518809fabbSderaadt pass5(void)
528c424e8eSdownsj {
5365348f21Sjasoni 	int c;
540190393fSart 	struct m_ext2fs *fs = &sblock;
55b6d2e2d5Sderaadt 	daddr32_t dbase, dmax;
56b6d2e2d5Sderaadt 	daddr32_t d;
570190393fSart 	long i, j;
588c424e8eSdownsj 	struct inodesc idesc[3];
598c424e8eSdownsj 	struct bufarea *ino_bitmap = NULL, *blk_bitmap = NULL;
608c424e8eSdownsj 	char *ibmap, *bbmap;
618c424e8eSdownsj 	u_int32_t cs_ndir, cs_nbfree, cs_nifree;
628c424e8eSdownsj 	char msg[255];
638c424e8eSdownsj 
648c424e8eSdownsj 	cs_ndir = 0;
658c424e8eSdownsj 	cs_nbfree = 0;
668c424e8eSdownsj 	cs_nifree = 0;
678c424e8eSdownsj 
688c424e8eSdownsj 	ibmap = malloc(fs->e2fs_bsize);
698c424e8eSdownsj 	bbmap = malloc(fs->e2fs_bsize);
708c424e8eSdownsj 	if (ibmap == NULL || bbmap == NULL) {
718c424e8eSdownsj 		errexit("out of memory\n");
728c424e8eSdownsj 	}
738c424e8eSdownsj 
748c424e8eSdownsj 	for (c = 0; c < fs->e2fs_ncg; c++) {
758c424e8eSdownsj 		u_int32_t nbfree = 0;
768c424e8eSdownsj 		u_int32_t nifree = 0;
778c424e8eSdownsj 		u_int32_t ndirs = 0;
788c424e8eSdownsj 
798c424e8eSdownsj 		nbfree = 0;
808c424e8eSdownsj 		nifree = fs->e2fs.e2fs_ipg;
818c424e8eSdownsj 		ndirs = 0;
828c424e8eSdownsj 
838c424e8eSdownsj 		if (blk_bitmap == NULL) {
8460a51e06Spelikan 			blk_bitmap = getdatablk(letoh32(fs->e2fs_gd[c].ext2bgd_b_bitmap),
858c424e8eSdownsj 				fs->e2fs_bsize);
868c424e8eSdownsj 		} else {
8760a51e06Spelikan 			getblk(blk_bitmap, letoh32(fs->e2fs_gd[c].ext2bgd_b_bitmap),
888c424e8eSdownsj 				fs->e2fs_bsize);
898c424e8eSdownsj 		}
908c424e8eSdownsj 		if (ino_bitmap == NULL) {
9160a51e06Spelikan 			ino_bitmap = getdatablk(letoh32(fs->e2fs_gd[c].ext2bgd_i_bitmap),
928c424e8eSdownsj 				fs->e2fs_bsize);
938c424e8eSdownsj 		} else {
9460a51e06Spelikan 			getblk(ino_bitmap, letoh32(fs->e2fs_gd[c].ext2bgd_i_bitmap),
958c424e8eSdownsj 				fs->e2fs_bsize);
968c424e8eSdownsj 		}
978c424e8eSdownsj 		memset(bbmap, 0, fs->e2fs_bsize);
988c424e8eSdownsj 		memset(ibmap, 0, fs->e2fs_bsize);
998c424e8eSdownsj 		memset(&idesc[0], 0, sizeof idesc);
1008c424e8eSdownsj 		for (i = 0; i < 3; i++) {
1018c424e8eSdownsj 			idesc[i].id_type = ADDR;
1028c424e8eSdownsj 		}
1038c424e8eSdownsj 
1048c424e8eSdownsj 		j = fs->e2fs.e2fs_ipg * c + 1;
1058c424e8eSdownsj 
1068c424e8eSdownsj 		for (i = 0; i < fs->e2fs.e2fs_ipg; j++, i++) {
1078c424e8eSdownsj 			if ((j < EXT2_FIRSTINO) && (j != EXT2_ROOTINO)) {
1088c424e8eSdownsj 				setbit(ibmap, i);
1098c424e8eSdownsj 				nifree--;
1108c424e8eSdownsj 				continue;
1118c424e8eSdownsj 			}
1128c424e8eSdownsj 			if (j > fs->e2fs.e2fs_icount) {
1138c424e8eSdownsj 				setbit(ibmap, i);
1148c424e8eSdownsj 				continue;
1158c424e8eSdownsj 			}
1168c424e8eSdownsj 			switch (statemap[j]) {
1178c424e8eSdownsj 
1188c424e8eSdownsj 			case USTATE:
1198c424e8eSdownsj 				break;
1208c424e8eSdownsj 
1218c424e8eSdownsj 			case DSTATE:
1228c424e8eSdownsj 			case DCLEAR:
1238c424e8eSdownsj 			case DFOUND:
1248c424e8eSdownsj 				ndirs++;
1258c424e8eSdownsj 				/* fall through */
1268c424e8eSdownsj 
1278c424e8eSdownsj 			case FSTATE:
1288c424e8eSdownsj 			case FCLEAR:
1298c424e8eSdownsj 				nifree--;
1308c424e8eSdownsj 				setbit(ibmap, i);
1318c424e8eSdownsj 				break;
1328c424e8eSdownsj 
1338c424e8eSdownsj 			default:
1343b92bd08Sderaadt 				errexit("BAD STATE %d FOR INODE I=%llu\n",
1353b92bd08Sderaadt 				    statemap[j], (unsigned long long)j);
1368c424e8eSdownsj 			}
1378c424e8eSdownsj 		}
1388c424e8eSdownsj 
1398c424e8eSdownsj 		/* fill in unused par of the inode map */
1408c424e8eSdownsj 		for (i = fs->e2fs.e2fs_ipg / NBBY; i < fs->e2fs_bsize; i++)
1418c424e8eSdownsj 			ibmap[i] = 0xff;
1428c424e8eSdownsj 
14365348f21Sjasoni 		dbase = c * sblock.e2fs.e2fs_bpg +
14465348f21Sjasoni 		    sblock.e2fs.e2fs_first_dblock;
14565348f21Sjasoni 		dmax = (c+1) * sblock.e2fs.e2fs_bpg +
14665348f21Sjasoni 		    sblock.e2fs.e2fs_first_dblock;
1478c424e8eSdownsj 
14865348f21Sjasoni 		for (i = 0, d = dbase;
1498c424e8eSdownsj 		     d < dmax;
1508c424e8eSdownsj 		     d ++, i ++) {
1518c424e8eSdownsj 			if (testbmap(d) || d >= sblock.e2fs.e2fs_bcount) {
1528c424e8eSdownsj 				setbit(bbmap, i);
1538c424e8eSdownsj 				continue;
1548c424e8eSdownsj 			} else {
1558c424e8eSdownsj 				nbfree++;
1568c424e8eSdownsj 			}
1578c424e8eSdownsj 
1588c424e8eSdownsj 		}
1598c424e8eSdownsj 		cs_nbfree += nbfree;
1608c424e8eSdownsj 		cs_nifree += nifree;
1618c424e8eSdownsj 		cs_ndir += ndirs;
1628c424e8eSdownsj 
16360a51e06Spelikan 		if (debug && (letoh16(fs->e2fs_gd[c].ext2bgd_nbfree) != nbfree ||
16460a51e06Spelikan 		    letoh16(fs->e2fs_gd[c].ext2bgd_nifree) != nifree ||
16560a51e06Spelikan 		    letoh16(fs->e2fs_gd[c].ext2bgd_ndirs) != ndirs)) {
1668c424e8eSdownsj 			printf("summary info for cg %d is %d, %d, %d,"
1678c424e8eSdownsj 					"should be %d, %d, %d\n", c,
16860a51e06Spelikan 					letoh16(fs->e2fs_gd[c].ext2bgd_nbfree),
16960a51e06Spelikan 					letoh16(fs->e2fs_gd[c].ext2bgd_nifree),
17060a51e06Spelikan 					letoh16(fs->e2fs_gd[c].ext2bgd_ndirs),
1718c424e8eSdownsj 					nbfree,
1728c424e8eSdownsj 					nifree,
1738c424e8eSdownsj 					ndirs);
1748c424e8eSdownsj 		}
17565348f21Sjasoni 		(void)snprintf(msg, sizeof(msg),
17665348f21Sjasoni 		    "SUMMARY INFORMATIONS WRONG FOR CG #%d", c);
17760a51e06Spelikan 		if ((letoh16(fs->e2fs_gd[c].ext2bgd_nbfree) != nbfree ||
17860a51e06Spelikan 			letoh16(fs->e2fs_gd[c].ext2bgd_nifree) != nifree ||
17960a51e06Spelikan 			letoh16(fs->e2fs_gd[c].ext2bgd_ndirs) != ndirs) &&
1808c424e8eSdownsj 			dofix(&idesc[0], msg)) {
18160a51e06Spelikan 			fs->e2fs_gd[c].ext2bgd_nbfree = htole16(nbfree);
18260a51e06Spelikan 			fs->e2fs_gd[c].ext2bgd_nifree = htole16(nifree);
18360a51e06Spelikan 			fs->e2fs_gd[c].ext2bgd_ndirs = htole16(ndirs);
1848c424e8eSdownsj 			sbdirty();
1858c424e8eSdownsj 		}
1868c424e8eSdownsj 
1878c424e8eSdownsj 		if (debug && memcmp(blk_bitmap->b_un.b_buf, bbmap, fs->e2fs_bsize)) {
1888c424e8eSdownsj 			printf("blk_bitmap:\n");
1898c424e8eSdownsj 			print_bmap(blk_bitmap->b_un.b_buf, fs->e2fs_bsize);
1908c424e8eSdownsj 			printf("bbmap:\n");
1918c424e8eSdownsj 			print_bmap(bbmap, fs->e2fs_bsize);
1928c424e8eSdownsj 		}
1938c424e8eSdownsj 
19465348f21Sjasoni 		(void)snprintf(msg, sizeof(msg),
19565348f21Sjasoni 		    "BLK(S) MISSING IN BIT MAPS #%d", c);
1968c424e8eSdownsj 		if (memcmp(blk_bitmap->b_un.b_buf, bbmap, fs->e2fs_bsize) &&
1978c424e8eSdownsj 			dofix(&idesc[1], msg)) {
1988c424e8eSdownsj 			memcpy(blk_bitmap->b_un.b_buf, bbmap, fs->e2fs_bsize);
1998c424e8eSdownsj 			dirty(blk_bitmap);
2008c424e8eSdownsj 		}
2018c424e8eSdownsj 		if (debug && memcmp(ino_bitmap->b_un.b_buf, ibmap, fs->e2fs_bsize)) {
2028c424e8eSdownsj 			printf("ino_bitmap:\n");
2038c424e8eSdownsj 			print_bmap(ino_bitmap->b_un.b_buf, fs->e2fs_bsize);
2048c424e8eSdownsj 			printf("ibmap:\n");
2058c424e8eSdownsj 			print_bmap(ibmap, fs->e2fs_bsize);
2068c424e8eSdownsj 		}
20765348f21Sjasoni 		(void)snprintf(msg, sizeof(msg),
20865348f21Sjasoni 		    "INODE(S) MISSING IN BIT MAPS #%d", c);
2098c424e8eSdownsj 		if (memcmp(ino_bitmap->b_un.b_buf, ibmap, fs->e2fs_bsize) &&
2108c424e8eSdownsj 			dofix(&idesc[1], msg)) {
2118c424e8eSdownsj 			memcpy(ino_bitmap->b_un.b_buf, ibmap, fs->e2fs_bsize);
2128c424e8eSdownsj 			dirty(ino_bitmap);
2138c424e8eSdownsj 		}
2148c424e8eSdownsj 
2158c424e8eSdownsj 	}
2168c424e8eSdownsj 	if (debug && (fs->e2fs.e2fs_fbcount != cs_nbfree ||
2178c424e8eSdownsj 		fs->e2fs.e2fs_ficount != cs_nifree)) {
2188c424e8eSdownsj 		printf("summary info bad in superblock: %d, %d should be %d, %d\n",
2198c424e8eSdownsj 		fs->e2fs.e2fs_fbcount, fs->e2fs.e2fs_ficount,
2208c424e8eSdownsj 		cs_nbfree, cs_nifree);
2218c424e8eSdownsj 	}
2228c424e8eSdownsj 	if ((fs->e2fs.e2fs_fbcount != cs_nbfree ||
2238c424e8eSdownsj 		fs->e2fs.e2fs_ficount != cs_nifree)
2248c424e8eSdownsj 	    && dofix(&idesc[0], "SUPERBLK SUMMARY INFORMATION BAD")) {
2258c424e8eSdownsj 		fs->e2fs.e2fs_fbcount = cs_nbfree;
2268c424e8eSdownsj 		fs->e2fs.e2fs_ficount = cs_nifree;
2278c424e8eSdownsj 		sbdirty();
2288c424e8eSdownsj 	}
2295e12154eSdhill 	free(ibmap);
2305e12154eSdhill 	free(bbmap);
2318c424e8eSdownsj }
2328c424e8eSdownsj 
2338c424e8eSdownsj void
print_bmap(u_char * map,u_int32_t size)2348809fabbSderaadt print_bmap(u_char *map, u_int32_t size)
2358c424e8eSdownsj {
2368c424e8eSdownsj 	int i, j;
2378c424e8eSdownsj 
2388c424e8eSdownsj 	i = 0;
2398c424e8eSdownsj 	while (i < size) {
2408c424e8eSdownsj 		printf("%u: ",i);
2418c424e8eSdownsj 		for (j = 0; j < 16; j++, i++)
2422e7e8d8bSderaadt 			printf("%2x ", (u_int)map[i] & 0xff);
2438c424e8eSdownsj 		printf("\n");
2448c424e8eSdownsj 	}
2458c424e8eSdownsj }
246