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