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
19#include "debugfs.h"
20
21struct inode_info {
22	ext2_ino_t	ino;
23	ext2_ino_t	parent;
24	char		*pathname;
25};
26
27struct inode_walk_struct {
28	struct inode_info	*iarray;
29	int			inodes_left;
30	int			num_inodes;
31	int			position;
32	ext2_ino_t		parent;
33};
34
35static int ncheck_proc(struct ext2_dir_entry *dirent,
36		       int	offset EXT2FS_ATTR((unused)),
37		       int	blocksize EXT2FS_ATTR((unused)),
38		       char	*buf EXT2FS_ATTR((unused)),
39		       void	*private)
40{
41	struct inode_walk_struct *iw = (struct inode_walk_struct *) private;
42	int	i;
43
44	iw->position++;
45	if (iw->position <= 2)
46		return 0;
47	for (i=0; i < iw->num_inodes; i++) {
48		if (iw->iarray[i].ino == dirent->inode) {
49			iw->iarray[i].parent = iw->parent;
50			iw->inodes_left--;
51		}
52	}
53	if (!iw->inodes_left)
54		return DIRENT_ABORT;
55
56	return 0;
57}
58
59void do_ncheck(int argc, char **argv)
60{
61	struct inode_walk_struct iw;
62	struct inode_info	*iinfo;
63	int			i;
64	ext2_inode_scan		scan = 0;
65	ext2_ino_t		ino;
66	struct ext2_inode	inode;
67	errcode_t		retval;
68	char			*tmp;
69
70	if (argc < 2) {
71		com_err(argv[0], 0, "Usage: ncheck <inode number> ...");
72		return;
73	}
74	if (check_fs_open(argv[0]))
75		return;
76
77	iw.iarray = malloc(sizeof(struct inode_info) * argc);
78	if (!iw.iarray) {
79		com_err("do_ncheck", ENOMEM,
80			"while allocating inode info array");
81		return;
82	}
83	memset(iw.iarray, 0, sizeof(struct inode_info) * argc);
84
85	for (i=1; i < argc; i++) {
86		iw.iarray[i-1].ino = strtol(argv[i], &tmp, 0);
87		if (*tmp) {
88			com_err(argv[0], 0, "Bad inode - %s", argv[i]);
89			return;
90		}
91	}
92
93	iw.num_inodes = iw.inodes_left = argc-1;
94
95	retval = ext2fs_open_inode_scan(current_fs, 0, &scan);
96	if (retval) {
97		com_err("ncheck", retval, "while opening inode scan");
98		goto error_out;
99	}
100
101	do {
102		retval = ext2fs_get_next_inode(scan, &ino, &inode);
103	} while (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE);
104	if (retval) {
105		com_err("ncheck", retval, "while starting inode scan");
106		goto error_out;
107	}
108
109	while (ino) {
110		if (!inode.i_links_count)
111			goto next;
112		/*
113		 * To handle filesystems touched by 0.3c extfs; can be
114		 * removed later.
115		 */
116		if (inode.i_dtime)
117			goto next;
118		/* Ignore anything that isn't a directory */
119		if (!LINUX_S_ISDIR(inode.i_mode))
120			goto next;
121
122		iw.position = 0;
123		iw.parent = ino;
124
125		retval = ext2fs_dir_iterate(current_fs, ino, 0, 0,
126					    ncheck_proc, &iw);
127		if (retval) {
128			com_err("ncheck", retval,
129				"while calling ext2_dir_iterate");
130			goto next;
131		}
132
133		if (iw.inodes_left == 0)
134			break;
135
136	next:
137		do {
138			retval = ext2fs_get_next_inode(scan, &ino, &inode);
139		} while (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE);
140
141		if (retval) {
142			com_err("ncheck", retval,
143				"while doing inode scan");
144			goto error_out;
145		}
146	}
147
148	for (i=0, iinfo = iw.iarray; i < iw.num_inodes; i++, iinfo++) {
149		if (iinfo->parent == 0)
150			continue;
151		retval = ext2fs_get_pathname(current_fs, iinfo->parent,
152					     iinfo->ino, &iinfo->pathname);
153		if (retval)
154			com_err("ncheck", retval,
155				"while resolving pathname for inode %d (%d)",
156				iinfo->parent, iinfo->ino);
157	}
158
159	printf("Inode\tPathname\n");
160	for (i=0, iinfo = iw.iarray; i < iw.num_inodes; i++, iinfo++) {
161		if (iinfo->parent == 0) {
162			printf("%u\t<inode not found>\n", iinfo->ino);
163			continue;
164		}
165		printf("%u\t%s\n", iinfo->ino, iinfo->pathname ?
166		       iinfo->pathname : "<unknown pathname>");
167		if (iinfo->pathname)
168			free(iinfo->pathname);
169	}
170
171error_out:
172	free(iw.iarray);
173	if (scan)
174		ext2fs_close_inode_scan(scan);
175	return;
176}
177
178
179
180