Home | History | Annotate | Download | only in debugfs
      1 /*
      2  * ncheck.c --- given a list of inodes, generate a list of names
      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 #ifdef HAVE_GETOPT_H
     19 #include <getopt.h>
     20 #else
     21 extern int optind;
     22 extern char *optarg;
     23 #endif
     24 
     25 #include "debugfs.h"
     26 
     27 struct inode_walk_struct {
     28 	ext2_ino_t		dir;
     29 	ext2_ino_t		*iarray;
     30 	int			inodes_left;
     31 	int			num_inodes;
     32 	int			position;
     33 	char			*parent;
     34 	unsigned int		get_pathname_failed:1;
     35 	unsigned int		check_dirent:1;
     36 };
     37 
     38 static int ncheck_proc(struct ext2_dir_entry *dirent,
     39 		       int	offset EXT2FS_ATTR((unused)),
     40 		       int	blocksize EXT2FS_ATTR((unused)),
     41 		       char	*buf EXT2FS_ATTR((unused)),
     42 		       void	*private)
     43 {
     44 	struct inode_walk_struct *iw = (struct inode_walk_struct *) private;
     45 	struct ext2_inode inode;
     46 	errcode_t	retval;
     47 	int		filetype = dirent->name_len >> 8;
     48 	int		i;
     49 
     50 	iw->position++;
     51 	if (iw->position <= 2)
     52 		return 0;
     53 	for (i=0; i < iw->num_inodes; i++) {
     54 		if (iw->iarray[i] == dirent->inode) {
     55 			if (!iw->parent && !iw->get_pathname_failed) {
     56 				retval = ext2fs_get_pathname(current_fs,
     57 							     iw->dir,
     58 							     0, &iw->parent);
     59 				if (retval) {
     60 					com_err("ncheck", retval,
     61 		"while calling ext2fs_get_pathname for inode #%u", iw->dir);
     62 					iw->get_pathname_failed = 1;
     63 				}
     64 			}
     65 			if (iw->parent)
     66 				printf("%u\t%s/%.*s", iw->iarray[i],
     67 				       iw->parent,
     68 				       (dirent->name_len & 0xFF), dirent->name);
     69 			else
     70 				printf("%u\t<%u>/%.*s", iw->iarray[i],
     71 				       iw->dir,
     72 				       (dirent->name_len & 0xFF), dirent->name);
     73 			if (iw->check_dirent && filetype) {
     74 				if (!debugfs_read_inode(dirent->inode, &inode,
     75 							"ncheck") &&
     76 				    filetype != ext2_file_type(inode.i_mode)) {
     77 					printf("  <--- BAD FILETYPE");
     78 				}
     79 			}
     80 			putc('\n', stdout);
     81 		}
     82 	}
     83 	if (!iw->inodes_left)
     84 		return DIRENT_ABORT;
     85 
     86 	return 0;
     87 }
     88 
     89 void do_ncheck(int argc, char **argv)
     90 {
     91 	struct inode_walk_struct iw;
     92 	int			c, i;
     93 	ext2_inode_scan		scan = 0;
     94 	ext2_ino_t		ino;
     95 	struct ext2_inode	inode;
     96 	errcode_t		retval;
     97 	char			*tmp;
     98 
     99 	iw.check_dirent = 0;
    100 
    101 	reset_getopt();
    102 	while ((c = getopt (argc, argv, "c")) != EOF) {
    103 		switch (c) {
    104 		case 'c':
    105 			iw.check_dirent = 1;
    106 			break;
    107 		default:
    108 			goto print_usage;
    109 		}
    110 	}
    111 	argc -= optind;
    112 	argv += optind;
    113 
    114 	if (argc < 1) {
    115 	print_usage:
    116 		com_err(argv[0], 0, "Usage: ncheck [-c] <inode number> ...");
    117 		return;
    118 	}
    119 	if (check_fs_open(argv[0]))
    120 		return;
    121 
    122 	iw.iarray = malloc(sizeof(ext2_ino_t) * argc);
    123 	if (!iw.iarray) {
    124 		com_err("ncheck", ENOMEM,
    125 			"while allocating inode number array");
    126 		return;
    127 	}
    128 	memset(iw.iarray, 0, sizeof(ext2_ino_t) * argc);
    129 
    130 	for (i=0; i < argc; i++) {
    131 		iw.iarray[i] = strtol(argv[i], &tmp, 0);
    132 		if (*tmp) {
    133 			com_err(argv[0], 0, "Bad inode - %s", argv[i]);
    134 			goto error_out;
    135 		}
    136 	}
    137 
    138 	iw.num_inodes = iw.inodes_left = argc;
    139 
    140 	retval = ext2fs_open_inode_scan(current_fs, 0, &scan);
    141 	if (retval) {
    142 		com_err("ncheck", retval, "while opening inode scan");
    143 		goto error_out;
    144 	}
    145 
    146 	do {
    147 		retval = ext2fs_get_next_inode(scan, &ino, &inode);
    148 	} while (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE);
    149 	if (retval) {
    150 		com_err("ncheck", retval, "while starting inode scan");
    151 		goto error_out;
    152 	}
    153 
    154 	printf("Inode\tPathname\n");
    155 	while (ino) {
    156 		if (!inode.i_links_count)
    157 			goto next;
    158 		/*
    159 		 * To handle filesystems touched by 0.3c extfs; can be
    160 		 * removed later.
    161 		 */
    162 		if (inode.i_dtime)
    163 			goto next;
    164 		/* Ignore anything that isn't a directory */
    165 		if (!LINUX_S_ISDIR(inode.i_mode))
    166 			goto next;
    167 
    168 		iw.position = 0;
    169 		iw.parent = 0;
    170 		iw.dir = ino;
    171 		iw.get_pathname_failed = 0;
    172 
    173 		retval = ext2fs_dir_iterate(current_fs, ino, 0, 0,
    174 					    ncheck_proc, &iw);
    175 		ext2fs_free_mem(&iw.parent);
    176 		if (retval) {
    177 			com_err("ncheck", retval,
    178 				"while calling ext2_dir_iterate");
    179 			goto next;
    180 		}
    181 
    182 		if (iw.inodes_left == 0)
    183 			break;
    184 
    185 	next:
    186 		do {
    187 			retval = ext2fs_get_next_inode(scan, &ino, &inode);
    188 		} while (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE);
    189 
    190 		if (retval) {
    191 			com_err("ncheck", retval,
    192 				"while doing inode scan");
    193 			goto error_out;
    194 		}
    195 	}
    196 
    197 error_out:
    198 	free(iw.iarray);
    199 	if (scan)
    200 		ext2fs_close_inode_scan(scan);
    201 	return;
    202 }
    203 
    204 
    205 
    206