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
21extern int optind;
22extern char *optarg;
23#endif
24
25#include "debugfs.h"
26
27struct 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
38static 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
89void 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
197error_out:
198	free(iw.iarray);
199	if (scan)
200		ext2fs_close_inode_scan(scan);
201	return;
202}
203
204
205
206