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