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
ncheck_proc(struct ext2_dir_entry * dirent,int offset EXT2FS_ATTR ((unused)),int blocksize EXT2FS_ATTR ((unused)),char * buf EXT2FS_ATTR ((unused)),void * private)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
do_ncheck(int argc,char ** argv)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