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