Home | History | Annotate | Download | only in debugfs
      1 /*
      2  * icheck.c --- given a list of blocks, generate a list of inodes
      3  *
      4  * Copyright (C) 1994 Theodore Ts'o.  This file may be redistributed
      5  * under the terms of the GNU Public License.
      6  */
      7 
      8 #include <stdio.h>
      9 #include <unistd.h>
     10 #include <stdlib.h>
     11 #include <ctype.h>
     12 #include <string.h>
     13 #include <time.h>
     14 #ifdef HAVE_ERRNO_H
     15 #include <errno.h>
     16 #endif
     17 #include <sys/types.h>
     18 
     19 #include "debugfs.h"
     20 
     21 struct block_info {
     22 	blk_t		blk;
     23 	ext2_ino_t	ino;
     24 };
     25 
     26 struct block_walk_struct {
     27 	struct block_info	*barray;
     28 	e2_blkcnt_t		blocks_left;
     29 	e2_blkcnt_t		num_blocks;
     30 	ext2_ino_t		inode;
     31 };
     32 
     33 static int icheck_proc(ext2_filsys fs EXT2FS_ATTR((unused)),
     34 		       blk_t	*block_nr,
     35 		       e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
     36 		       blk_t ref_block EXT2FS_ATTR((unused)),
     37 		       int ref_offset EXT2FS_ATTR((unused)),
     38 		       void *private)
     39 {
     40 	struct block_walk_struct *bw = (struct block_walk_struct *) private;
     41 	e2_blkcnt_t	i;
     42 
     43 	for (i=0; i < bw->num_blocks; i++) {
     44 		if (!bw->barray[i].ino && bw->barray[i].blk == *block_nr) {
     45 			bw->barray[i].ino = bw->inode;
     46 			bw->blocks_left--;
     47 		}
     48 	}
     49 	if (!bw->blocks_left)
     50 		return BLOCK_ABORT;
     51 
     52 	return 0;
     53 }
     54 
     55 void do_icheck(int argc, char **argv)
     56 {
     57 	struct block_walk_struct bw;
     58 	struct block_info	*binfo;
     59 	int			i;
     60 	ext2_inode_scan		scan = 0;
     61 	ext2_ino_t		ino;
     62 	struct ext2_inode	inode;
     63 	errcode_t		retval;
     64 	char			*block_buf;
     65 
     66 	if (argc < 2) {
     67 		com_err(argv[0], 0, "Usage: icheck <block number> ...");
     68 		return;
     69 	}
     70 	if (check_fs_open(argv[0]))
     71 		return;
     72 
     73 	bw.barray = malloc(sizeof(struct block_info) * argc);
     74 	if (!bw.barray) {
     75 		com_err("icheck", ENOMEM,
     76 			"while allocating inode info array");
     77 		return;
     78 	}
     79 	memset(bw.barray, 0, sizeof(struct block_info) * argc);
     80 
     81 	block_buf = malloc(current_fs->blocksize * 3);
     82 	if (!block_buf) {
     83 		com_err("icheck", ENOMEM, "while allocating block buffer");
     84 		goto error_out;
     85 	}
     86 
     87 	for (i=1; i < argc; i++) {
     88 		if (strtoblk(argv[0], argv[i], &bw.barray[i-1].blk))
     89 			goto error_out;
     90 	}
     91 
     92 	bw.num_blocks = bw.blocks_left = argc-1;
     93 
     94 	retval = ext2fs_open_inode_scan(current_fs, 0, &scan);
     95 	if (retval) {
     96 		com_err("icheck", retval, "while opening inode scan");
     97 		goto error_out;
     98 	}
     99 
    100 	do {
    101 		retval = ext2fs_get_next_inode(scan, &ino, &inode);
    102 	} while (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE);
    103 	if (retval) {
    104 		com_err("icheck", retval, "while starting inode scan");
    105 		goto error_out;
    106 	}
    107 
    108 	while (ino) {
    109 		if (!inode.i_links_count)
    110 			goto next;
    111 
    112 		bw.inode = ino;
    113 
    114 		if (inode.i_file_acl) {
    115 			icheck_proc(current_fs, &inode.i_file_acl, 0,
    116 				    0, 0, &bw);
    117 			if (bw.blocks_left == 0)
    118 				break;
    119 		}
    120 
    121 		if (!ext2fs_inode_has_valid_blocks(&inode))
    122 			goto next;
    123 		/*
    124 		 * To handle filesystems touched by 0.3c extfs; can be
    125 		 * removed later.
    126 		 */
    127 		if (inode.i_dtime)
    128 			goto next;
    129 
    130 		retval = ext2fs_block_iterate2(current_fs, ino,
    131 					       BLOCK_FLAG_READ_ONLY, block_buf,
    132 					       icheck_proc, &bw);
    133 		if (retval) {
    134 			com_err("icheck", retval,
    135 				"while calling ext2fs_block_iterate");
    136 			goto next;
    137 		}
    138 
    139 		if (bw.blocks_left == 0)
    140 			break;
    141 
    142 	next:
    143 		do {
    144 			retval = ext2fs_get_next_inode(scan, &ino, &inode);
    145 		} while (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE);
    146 		if (retval) {
    147 			com_err("icheck", retval,
    148 				"while doing inode scan");
    149 			goto error_out;
    150 		}
    151 	}
    152 
    153 	printf("Block\tInode number\n");
    154 	for (i=0, binfo = bw.barray; i < bw.num_blocks; i++, binfo++) {
    155 		if (binfo->ino == 0) {
    156 			printf("%u\t<block not found>\n", binfo->blk);
    157 			continue;
    158 		}
    159 		printf("%u\t%u\n", binfo->blk, binfo->ino);
    160 	}
    161 
    162 error_out:
    163 	free(bw.barray);
    164 	free(block_buf);
    165 	if (scan)
    166 		ext2fs_close_inode_scan(scan);
    167 	return;
    168 }
    169