xref: /aosp_15_r20/external/e2fsprogs/debugfs/ncheck.c (revision 6a54128f25917bfc36a8a6e9d722c04a0b4641b6)
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 
ncheck_proc(struct ext2_dir_entry * dirent,int offset EXT2FS_ATTR ((unused)),int blocksize EXT2FS_ATTR ((unused)),char * buf EXT2FS_ATTR ((unused)),void * private)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 
do_ncheck(int argc,char ** argv,int sci_idx EXT2FS_ATTR ((unused)),void * infop EXT2FS_ATTR ((unused)))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 		char *str = argv[i];
138 		int len = strlen(str);
139 
140 		if ((len > 2) && (str[0] == '<') && (str[len - 1] == '>'))
141 			str++;
142 		iw.iarray[i] = strtol(str, &tmp, 0);
143 		if (*tmp && (str == argv[i] || *tmp != '>')) {
144 			com_err("ncheck", 0, "Invalid inode number - '%s'",
145 				argv[i]);
146 			goto error_out;
147 		}
148 		if (debugfs_read_inode(iw.iarray[i], &inode, *argv))
149 			goto error_out;
150 		if (LINUX_S_ISDIR(inode.i_mode))
151 			iw.names_left += 1;
152 		else
153 			iw.names_left += inode.i_links_count;
154 	}
155 
156 	iw.num_inodes = argc;
157 
158 	retval = ext2fs_open_inode_scan(current_fs, 0, &scan);
159 	if (retval) {
160 		com_err("ncheck", retval, "while opening inode scan");
161 		goto error_out;
162 	}
163 
164 	do {
165 		retval = ext2fs_get_next_inode(scan, &ino, &inode);
166 	} while (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE);
167 	if (retval) {
168 		com_err("ncheck", retval, "while starting inode scan");
169 		goto error_out;
170 	}
171 
172 	printf("Inode\tPathname\n");
173 	while (ino) {
174 		if (!inode.i_links_count)
175 			goto next;
176 		/*
177 		 * To handle filesystems touched by 0.3c extfs; can be
178 		 * removed later.
179 		 */
180 		if (inode.i_dtime)
181 			goto next;
182 		/* Ignore anything that isn't a directory */
183 		if (!LINUX_S_ISDIR(inode.i_mode))
184 			goto next;
185 
186 		iw.position = 0;
187 		iw.parent = 0;
188 		iw.dir = ino;
189 		iw.get_pathname_failed = 0;
190 
191 		retval = ext2fs_dir_iterate(current_fs, ino, 0, 0,
192 					    ncheck_proc, &iw);
193 		ext2fs_free_mem(&iw.parent);
194 		if (retval) {
195 			com_err("ncheck", retval,
196 				"while calling ext2_dir_iterate");
197 			goto next;
198 		}
199 
200 		if (iw.names_left == 0)
201 			break;
202 
203 	next:
204 		do {
205 			retval = ext2fs_get_next_inode(scan, &ino, &inode);
206 		} while (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE);
207 
208 		if (retval) {
209 			com_err("ncheck", retval,
210 				"while doing inode scan");
211 			goto error_out;
212 		}
213 	}
214 
215 error_out:
216 	free(iw.iarray);
217 	if (scan)
218 		ext2fs_close_inode_scan(scan);
219 	return;
220 }
221 
222 
223 
224