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 	blk64_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 		       blk64_t	*block_nr,
     35 		       e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)),
     36 		       blk64_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 		blk64_t blk;
    110 
    111 		if (!inode.i_links_count)
    112 			goto next;
    113 
    114 		bw.inode = ino;
    115 
    116 		blk = ext2fs_file_acl_block(current_fs, &inode);
    117 		if (blk) {
    118 			icheck_proc(current_fs, &blk, 0,
    119 				    0, 0, &bw);
    120 			if (bw.blocks_left == 0)
    121 				break;
    122 			ext2fs_file_acl_block_set(current_fs, &inode, blk);
    123 		}
    124 
    125 		if (!ext2fs_inode_has_valid_blocks2(current_fs, &inode))
    126 			goto next;
    127 		/*
    128 		 * To handle filesystems touched by 0.3c extfs; can be
    129 		 * removed later.
    130 		 */
    131 		if (inode.i_dtime)
    132 			goto next;
    133 
    134 		retval = ext2fs_block_iterate3(current_fs, ino,
    135 					       BLOCK_FLAG_READ_ONLY, block_buf,
    136 					       icheck_proc, &bw);
    137 		if (retval) {
    138 			com_err("icheck", retval,
    139 				"while calling ext2fs_block_iterate");
    140 			goto next;
    141 		}
    142 
    143 		if (bw.blocks_left == 0)
    144 			break;
    145 
    146 	next:
    147 		do {
    148 			retval = ext2fs_get_next_inode(scan, &ino, &inode);
    149 		} while (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE);
    150 		if (retval) {
    151 			com_err("icheck", retval,
    152 				"while doing inode scan");
    153 			goto error_out;
    154 		}
    155 	}
    156 
    157 	printf("Block\tInode number\n");
    158 	for (i=0, binfo = bw.barray; i < bw.num_blocks; i++, binfo++) {
    159 		if (binfo->ino == 0) {
    160 			printf("%llu\t<block not found>\n", binfo->blk);
    161 			continue;
    162 		}
    163 		printf("%llu\t%u\n", binfo->blk, binfo->ino);
    164 	}
    165 
    166 error_out:
    167 	free(bw.barray);
    168 	free(block_buf);
    169 	if (scan)
    170 		ext2fs_close_inode_scan(scan);
    171 	return;
    172 }
    173