]>
Commit | Line | Data |
---|---|---|
258b00ea | 1 | /* |
74043ab2 | 2 | * Copyright (c) 2005-2006 Silicon Graphics, Inc. |
258b00ea TS |
3 | * All Rights Reserved. |
4 | * | |
5 | * This program is free software; you can redistribute it and/or | |
6 | * modify it under the terms of the GNU General Public License as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * This program is distributed in the hope that it would be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public License | |
15 | * along with this program; if not, write the Free Software Foundation, | |
16 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
17 | */ | |
18 | ||
19 | #include <xfs/xfs.h> | |
20 | #include <xfs/command.h> | |
21 | #include <xfs/input.h> | |
22 | #include <xfs/path.h> | |
23 | #include <xfs/parent.h> | |
24 | #include <xfs/handle.h> | |
25 | #include <xfs/jdm.h> | |
26 | #include "init.h" | |
27 | #include "io.h" | |
28 | ||
29 | #define PARENTBUF_SZ 16384 | |
74043ab2 | 30 | #define BSTATBUF_SZ 16384 |
258b00ea TS |
31 | |
32 | static cmdinfo_t parent_cmd; | |
33 | static int verbose_flag; | |
34 | static int err_status; | |
74043ab2 TS |
35 | static __u64 inodes_checked; |
36 | static char *mntpt; | |
258b00ea TS |
37 | |
38 | /* | |
39 | * check out a parent entry to see if the values seem valid | |
40 | */ | |
41 | static void | |
74043ab2 | 42 | check_parent_entry(xfs_bstat_t *bstatp, parent_t *parent) |
258b00ea TS |
43 | { |
44 | int sts; | |
45 | char fullpath[PATH_MAX]; | |
46 | struct stat statbuf; | |
47 | char *str; | |
48 | ||
49 | sprintf(fullpath, _("%s%s"), mntpt, parent->p_name); | |
50 | ||
51 | sts = lstat(fullpath, &statbuf); | |
52 | if (sts != 0) { | |
53 | fprintf(stderr, | |
74043ab2 | 54 | _("inode-path for inode: %llu is incorrect - path \"%s\" non-existent\n"), |
f934f4a5 | 55 | (unsigned long long) bstatp->bs_ino, fullpath); |
258b00ea TS |
56 | if (verbose_flag) { |
57 | fprintf(stderr, | |
58 | _("path \"%s\" does not stat for inode: %llu; err = %s\n"), | |
59 | fullpath, | |
f934f4a5 | 60 | (unsigned long long) bstatp->bs_ino, |
258b00ea TS |
61 | strerror(errno)); |
62 | } | |
63 | err_status++; | |
64 | return; | |
65 | } else { | |
66 | if (verbose_flag > 1) { | |
67 | printf(_("path \"%s\" found\n"), fullpath); | |
68 | } | |
69 | } | |
70 | ||
71 | if (statbuf.st_ino != bstatp->bs_ino) { | |
72 | fprintf(stderr, | |
73 | _("inode-path for inode: %llu is incorrect - wrong inode#\n"), | |
f934f4a5 | 74 | (unsigned long long) bstatp->bs_ino); |
258b00ea TS |
75 | if (verbose_flag) { |
76 | fprintf(stderr, | |
77 | _("ino mismatch for path \"%s\" %llu vs %llu\n"), | |
78 | fullpath, | |
5acc4dfe NS |
79 | (unsigned long long)statbuf.st_ino, |
80 | (unsigned long long)bstatp->bs_ino); | |
258b00ea TS |
81 | } |
82 | err_status++; | |
83 | return; | |
84 | } else if (verbose_flag > 1) { | |
5acc4dfe NS |
85 | printf(_("inode number match: %llu\n"), |
86 | (unsigned long long)statbuf.st_ino); | |
258b00ea TS |
87 | } |
88 | ||
89 | /* get parent path */ | |
90 | str = strrchr(fullpath, '/'); | |
91 | *str = '\0'; | |
92 | sts = stat(fullpath, &statbuf); | |
93 | if (sts != 0) { | |
94 | fprintf(stderr, | |
95 | _("parent path \"%s\" does not stat: %s\n"), | |
96 | fullpath, | |
97 | strerror(errno)); | |
98 | err_status++; | |
99 | return; | |
100 | } else { | |
101 | if (parent->p_ino != statbuf.st_ino) { | |
102 | fprintf(stderr, | |
103 | _("inode-path for inode: %llu is incorrect - wrong parent inode#\n"), | |
f934f4a5 | 104 | (unsigned long long) bstatp->bs_ino); |
258b00ea TS |
105 | if (verbose_flag) { |
106 | fprintf(stderr, | |
107 | _("ino mismatch for path \"%s\" %llu vs %llu\n"), | |
108 | fullpath, | |
5acc4dfe NS |
109 | (unsigned long long)parent->p_ino, |
110 | (unsigned long long)statbuf.st_ino); | |
258b00ea TS |
111 | } |
112 | err_status++; | |
113 | return; | |
114 | } else { | |
115 | if (verbose_flag > 1) { | |
f934f4a5 AE |
116 | printf(_("parent ino match for %llu\n"), |
117 | (unsigned long long) parent->p_ino); | |
258b00ea TS |
118 | } |
119 | } | |
120 | } | |
121 | } | |
122 | ||
123 | static void | |
74043ab2 TS |
124 | check_parents(parent_t *parentbuf, size_t *parentbuf_size, |
125 | jdm_fshandle_t *fshandlep, xfs_bstat_t *statp) | |
258b00ea TS |
126 | { |
127 | int error, i; | |
74043ab2 | 128 | __u32 count; |
258b00ea | 129 | parent_t *entryp; |
258b00ea | 130 | |
258b00ea | 131 | do { |
74043ab2 TS |
132 | error = jdm_parentpaths(fshandlep, statp, parentbuf, *parentbuf_size, &count); |
133 | ||
134 | if (error == ERANGE) { | |
135 | *parentbuf_size *= 2; | |
136 | parentbuf = (parent_t *)realloc(parentbuf, *parentbuf_size); | |
137 | } else if (error) { | |
138 | fprintf(stderr, _("parentpaths failed for ino %llu: %s\n"), | |
f934f4a5 | 139 | (unsigned long long) statp->bs_ino, |
8577b2c9 | 140 | strerror(errno)); |
258b00ea TS |
141 | err_status++; |
142 | break; | |
143 | } | |
74043ab2 TS |
144 | } while (error == ERANGE); |
145 | ||
258b00ea | 146 | |
74043ab2 TS |
147 | if (count == 0) { |
148 | /* no links for inode - something wrong here */ | |
f934f4a5 AE |
149 | fprintf(stderr, _("inode-path for inode: %llu is missing\n"), |
150 | (unsigned long long) statp->bs_ino); | |
74043ab2 TS |
151 | err_status++; |
152 | } | |
258b00ea | 153 | |
74043ab2 TS |
154 | entryp = parentbuf; |
155 | for (i = 0; i < count; i++) { | |
156 | check_parent_entry(statp, entryp); | |
157 | entryp = (parent_t*) (((char*)entryp) + entryp->p_reclen); | |
158 | } | |
258b00ea TS |
159 | } |
160 | ||
161 | static int | |
74043ab2 TS |
162 | do_bulkstat(parent_t *parentbuf, size_t *parentbuf_size, xfs_bstat_t *bstatbuf, |
163 | int fsfd, jdm_fshandle_t *fshandlep) | |
258b00ea | 164 | { |
d026b19e NS |
165 | __s32 buflenout; |
166 | __u64 lastino = 0; | |
258b00ea TS |
167 | xfs_bstat_t *p; |
168 | xfs_bstat_t *endp; | |
169 | xfs_fsop_bulkreq_t bulkreq; | |
170 | struct stat mntstat; | |
171 | ||
a504bf72 | 172 | if (stat(mntpt, &mntstat)) { |
258b00ea | 173 | fprintf(stderr, _("can't stat mount point \"%s\": %s\n"), |
8577b2c9 | 174 | mntpt, strerror(errno)); |
258b00ea TS |
175 | return 1; |
176 | } | |
177 | ||
178 | bulkreq.lastip = &lastino; | |
179 | bulkreq.icount = BSTATBUF_SZ; | |
180 | bulkreq.ubuffer = (void *)bstatbuf; | |
181 | bulkreq.ocount = &buflenout; | |
182 | ||
183 | while (xfsctl(mntpt, fsfd, XFS_IOC_FSBULKSTAT, &bulkreq) == 0) { | |
184 | if (*(bulkreq.ocount) == 0) { | |
185 | return 0; | |
186 | } | |
187 | for (p = bstatbuf, endp = bstatbuf + *bulkreq.ocount; p < endp; p++) { | |
188 | ||
189 | /* inode being modified, get synced data with iget */ | |
190 | if ( (!p->bs_nlink || !p->bs_mode) && p->bs_ino != 0 ) { | |
191 | ||
192 | if (xfsctl(mntpt, fsfd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq) < 0) { | |
193 | fprintf(stderr, | |
194 | _("failed to get bulkstat information for inode %llu\n"), | |
f934f4a5 | 195 | (unsigned long long) p->bs_ino); |
258b00ea TS |
196 | continue; |
197 | } | |
198 | if (!p->bs_nlink || !p->bs_mode || !p->bs_ino) { | |
199 | fprintf(stderr, | |
200 | _("failed to get valid bulkstat information for inode %llu\n"), | |
f934f4a5 | 201 | (unsigned long long) p->bs_ino); |
258b00ea TS |
202 | continue; |
203 | } | |
204 | } | |
205 | ||
206 | /* skip root */ | |
207 | if (p->bs_ino == mntstat.st_ino) { | |
208 | continue; | |
209 | } | |
210 | ||
211 | if (verbose_flag > 1) { | |
f934f4a5 AE |
212 | printf(_("checking inode %llu\n"), |
213 | (unsigned long long) p->bs_ino); | |
258b00ea TS |
214 | } |
215 | ||
216 | /* print dotted progress */ | |
217 | if ((inodes_checked % 100) == 0 && verbose_flag == 1) { | |
218 | printf("."); fflush(stdout); | |
219 | } | |
220 | inodes_checked++; | |
221 | ||
74043ab2 | 222 | check_parents(parentbuf, parentbuf_size, fshandlep, p); |
258b00ea TS |
223 | } |
224 | ||
225 | }/*while*/ | |
226 | ||
227 | fprintf(stderr, _("syssgi bulkstat failed: %s\n"), strerror(errno)); | |
228 | return 1; | |
229 | } | |
230 | ||
231 | static int | |
232 | parent_check(void) | |
233 | { | |
258b00ea TS |
234 | int fsfd; |
235 | jdm_fshandle_t *fshandlep; | |
236 | parent_t *parentbuf; | |
74043ab2 | 237 | size_t parentbuf_size = PARENTBUF_SZ; |
258b00ea TS |
238 | xfs_bstat_t *bstatbuf; |
239 | ||
240 | err_status = 0; | |
241 | inodes_checked = 0; | |
242 | ||
243 | sync(); | |
244 | ||
258b00ea TS |
245 | fsfd = file->fd; |
246 | ||
247 | fshandlep = jdm_getfshandle(mntpt); | |
5e656dbb | 248 | if (fshandlep == NULL) { |
258b00ea TS |
249 | fprintf(stderr, _("unable to open \"%s\" for jdm: %s\n"), |
250 | mntpt, | |
251 | strerror(errno)); | |
252 | return 1; | |
253 | } | |
254 | ||
255 | /* allocate buffers */ | |
256 | bstatbuf = (xfs_bstat_t *)calloc(BSTATBUF_SZ, sizeof(xfs_bstat_t)); | |
74043ab2 | 257 | parentbuf = (parent_t *)malloc(parentbuf_size); |
258b00ea TS |
258 | if (!bstatbuf || !parentbuf) { |
259 | fprintf(stderr, _("unable to allocate buffers: %s\n"), | |
260 | strerror(errno)); | |
355ac015 ES |
261 | free(bstatbuf); |
262 | free(parentbuf); | |
258b00ea TS |
263 | return 1; |
264 | } | |
265 | ||
74043ab2 | 266 | if (do_bulkstat(parentbuf, &parentbuf_size, bstatbuf, fsfd, fshandlep) != 0) |
258b00ea TS |
267 | err_status++; |
268 | ||
269 | if (err_status > 0) | |
270 | fprintf(stderr, _("num errors: %d\n"), err_status); | |
271 | else | |
f934f4a5 AE |
272 | printf(_("succeeded checking %llu inodes\n"), |
273 | (unsigned long long) inodes_checked); | |
258b00ea TS |
274 | |
275 | free(bstatbuf); | |
276 | free(parentbuf); | |
277 | return err_status; | |
278 | } | |
279 | ||
280 | static void | |
74043ab2 | 281 | print_parent_entry(parent_t *parent, int fullpath) |
258b00ea | 282 | { |
f934f4a5 | 283 | printf(_("p_ino = %llu\n"), (unsigned long long) parent->p_ino); |
258b00ea TS |
284 | printf(_("p_gen = %u\n"), parent->p_gen); |
285 | printf(_("p_reclen = %u\n"), parent->p_reclen); | |
74043ab2 TS |
286 | if (fullpath) |
287 | printf(_("p_name = \"%s%s\"\n"), mntpt, parent->p_name); | |
288 | else | |
289 | printf(_("p_name = \"%s\"\n"), parent->p_name); | |
258b00ea TS |
290 | } |
291 | ||
292 | static int | |
293 | parent_list(int fullpath) | |
294 | { | |
295 | void *handlep; | |
296 | size_t handlen; | |
297 | int error, i; | |
298 | int retval = 1; | |
74043ab2 | 299 | __u32 count; |
258b00ea | 300 | parent_t *entryp; |
74043ab2 | 301 | parent_t *parentbuf = NULL; |
258b00ea | 302 | char *path = file->name; |
74043ab2 | 303 | int pb_size = PARENTBUF_SZ; |
258b00ea TS |
304 | |
305 | /* XXXX for linux libhandle version - to set libhandle fsfd cache */ | |
306 | { | |
307 | void *fshandle; | |
308 | size_t fshlen; | |
309 | ||
74043ab2 | 310 | if (path_to_fshandle(mntpt, &fshandle, &fshlen) != 0) { |
258b00ea TS |
311 | fprintf(stderr, _("%s: failed path_to_fshandle \"%s\": %s\n"), |
312 | progname, path, strerror(errno)); | |
313 | goto error; | |
314 | } | |
315 | } | |
316 | ||
317 | if (path_to_handle(path, &handlep, &handlen) != 0) { | |
318 | fprintf(stderr, _("%s: path_to_handle failed for \"%s\"\n"), progname, path); | |
319 | goto error; | |
320 | } | |
321 | ||
258b00ea | 322 | do { |
74043ab2 TS |
323 | parentbuf = (parent_t *)realloc(parentbuf, pb_size); |
324 | if (!parentbuf) { | |
325 | fprintf(stderr, _("%s: unable to allocate parent buffer: %s\n"), | |
326 | progname, strerror(errno)); | |
327 | return 1; | |
328 | } | |
329 | ||
258b00ea | 330 | if (fullpath) { |
74043ab2 | 331 | error = parentpaths_by_handle(handlep, |
258b00ea TS |
332 | handlen, |
333 | parentbuf, | |
74043ab2 TS |
334 | pb_size, |
335 | &count); | |
258b00ea | 336 | } else { |
74043ab2 | 337 | error = parents_by_handle(handlep, |
258b00ea TS |
338 | handlen, |
339 | parentbuf, | |
74043ab2 TS |
340 | pb_size, |
341 | &count); | |
258b00ea | 342 | } |
74043ab2 TS |
343 | if (error == ERANGE) { |
344 | pb_size *= 2; | |
345 | } else if (error) { | |
346 | fprintf(stderr, _("%s: %s call failed for \"%s\": %s\n"), | |
347 | progname, fullpath ? "parentpaths" : "parents", | |
348 | path, strerror(errno)); | |
258b00ea TS |
349 | goto error; |
350 | } | |
74043ab2 | 351 | } while (error == ERANGE); |
258b00ea | 352 | |
74043ab2 TS |
353 | if (count == 0) { |
354 | /* no links for inode - something wrong here */ | |
355 | fprintf(stderr, _("%s: inode-path is missing\n"), progname); | |
356 | goto error; | |
357 | } | |
258b00ea | 358 | |
74043ab2 TS |
359 | entryp = parentbuf; |
360 | for (i = 0; i < count; i++) { | |
361 | print_parent_entry(entryp, fullpath); | |
362 | entryp = (parent_t*) (((char*)entryp) + entryp->p_reclen); | |
363 | } | |
258b00ea TS |
364 | |
365 | retval = 0; | |
366 | error: | |
367 | free(parentbuf); | |
368 | return retval; | |
369 | } | |
370 | ||
371 | int | |
372 | parent_f(int argc, char **argv) | |
373 | { | |
374 | int c; | |
375 | int listpath_flag = 0; | |
376 | int check_flag = 0; | |
74043ab2 TS |
377 | fs_path_t *fs; |
378 | static int tab_init; | |
379 | ||
380 | if (!tab_init) { | |
381 | tab_init = 1; | |
0900efe4 | 382 | fs_table_initialise(0, NULL, 0, NULL); |
74043ab2 TS |
383 | } |
384 | fs = fs_table_lookup(file->name, FS_MOUNT_POINT); | |
385 | if (!fs) { | |
386 | fprintf(stderr, _("file argument, \"%s\", is not in a mounted XFS filesystem\n"), | |
387 | file->name); | |
388 | return 1; | |
389 | } | |
390 | mntpt = fs->fs_dir; | |
258b00ea TS |
391 | |
392 | verbose_flag = 0; | |
393 | ||
394 | while ((c = getopt(argc, argv, "cpv")) != EOF) { | |
395 | switch (c) { | |
396 | case 'c': | |
397 | check_flag = 1; | |
398 | break; | |
399 | case 'p': | |
400 | listpath_flag = 1; | |
401 | break; | |
402 | case 'v': | |
403 | verbose_flag++; | |
404 | break; | |
405 | default: | |
406 | return command_usage(&parent_cmd); | |
407 | } | |
408 | } | |
409 | ||
410 | if (!check_flag && !listpath_flag) /* default case */ | |
411 | exitcode = parent_list(listpath_flag); | |
412 | else { | |
413 | if (listpath_flag) | |
414 | exitcode = parent_list(listpath_flag); | |
415 | if (check_flag) | |
416 | exitcode = parent_check(); | |
417 | } | |
418 | ||
419 | return 0; | |
420 | } | |
421 | ||
422 | static void | |
423 | parent_help(void) | |
424 | { | |
425 | printf(_( | |
426 | "\n" | |
427 | " list the current file's parents and their filenames\n" | |
428 | "\n" | |
429 | " -c -- check the current file's file system for parent consistency\n" | |
430 | " -p -- list the current file's parents and their full paths\n" | |
431 | " -v -- verbose mode\n" | |
432 | "\n")); | |
433 | } | |
434 | ||
435 | void | |
436 | parent_init(void) | |
437 | { | |
ad765595 | 438 | parent_cmd.name = "parent"; |
258b00ea TS |
439 | parent_cmd.cfunc = parent_f; |
440 | parent_cmd.argmin = 0; | |
441 | parent_cmd.argmax = -1; | |
442 | parent_cmd.args = _("[-cpv]"); | |
443 | parent_cmd.flags = CMD_NOMAP_OK; | |
444 | parent_cmd.oneline = _("print or check parent inodes"); | |
445 | parent_cmd.help = parent_help; | |
446 | ||
447 | if (expert) | |
448 | add_command(&parent_cmd); | |
449 | } |