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