]>
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 TS |
54 | _("inode-path for inode: %llu is incorrect - path \"%s\" non-existent\n"), |
55 | 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, | |
60 | bstatp->bs_ino, | |
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"), | |
74 | bstatp->bs_ino); | |
75 | if (verbose_flag) { | |
76 | fprintf(stderr, | |
77 | _("ino mismatch for path \"%s\" %llu vs %llu\n"), | |
78 | fullpath, | |
79 | statbuf.st_ino, | |
80 | bstatp->bs_ino); | |
81 | } | |
82 | err_status++; | |
83 | return; | |
84 | } else if (verbose_flag > 1) { | |
85 | printf(_("inode number match: %llu\n"), statbuf.st_ino); | |
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"), | |
103 | bstatp->bs_ino); | |
104 | if (verbose_flag) { | |
105 | fprintf(stderr, | |
106 | _("ino mismatch for path \"%s\" %llu vs %llu\n"), | |
107 | fullpath, | |
108 | parent->p_ino, | |
109 | statbuf.st_ino); | |
110 | } | |
111 | err_status++; | |
112 | return; | |
113 | } else { | |
114 | if (verbose_flag > 1) { | |
115 | printf(_("parent ino match for %llu\n"), parent->p_ino); | |
116 | } | |
117 | } | |
118 | } | |
119 | } | |
120 | ||
121 | static void | |
74043ab2 TS |
122 | check_parents(parent_t *parentbuf, size_t *parentbuf_size, |
123 | jdm_fshandle_t *fshandlep, xfs_bstat_t *statp) | |
258b00ea TS |
124 | { |
125 | int error, i; | |
74043ab2 | 126 | __u32 count; |
258b00ea | 127 | parent_t *entryp; |
258b00ea | 128 | |
258b00ea | 129 | do { |
74043ab2 TS |
130 | error = jdm_parentpaths(fshandlep, statp, parentbuf, *parentbuf_size, &count); |
131 | ||
132 | if (error == ERANGE) { | |
133 | *parentbuf_size *= 2; | |
134 | parentbuf = (parent_t *)realloc(parentbuf, *parentbuf_size); | |
135 | } else if (error) { | |
136 | fprintf(stderr, _("parentpaths failed for ino %llu: %s\n"), | |
258b00ea | 137 | statp->bs_ino, |
8577b2c9 | 138 | strerror(errno)); |
258b00ea TS |
139 | err_status++; |
140 | break; | |
141 | } | |
74043ab2 TS |
142 | } while (error == ERANGE); |
143 | ||
258b00ea | 144 | |
74043ab2 TS |
145 | if (count == 0) { |
146 | /* no links for inode - something wrong here */ | |
147 | fprintf(stderr, _("inode-path for inode: %llu is missing\n"), statp->bs_ino); | |
148 | err_status++; | |
149 | } | |
258b00ea | 150 | |
74043ab2 TS |
151 | entryp = parentbuf; |
152 | for (i = 0; i < count; i++) { | |
153 | check_parent_entry(statp, entryp); | |
154 | entryp = (parent_t*) (((char*)entryp) + entryp->p_reclen); | |
155 | } | |
258b00ea TS |
156 | } |
157 | ||
158 | static int | |
74043ab2 TS |
159 | do_bulkstat(parent_t *parentbuf, size_t *parentbuf_size, xfs_bstat_t *bstatbuf, |
160 | int fsfd, jdm_fshandle_t *fshandlep) | |
258b00ea | 161 | { |
d026b19e NS |
162 | __s32 buflenout; |
163 | __u64 lastino = 0; | |
258b00ea TS |
164 | xfs_bstat_t *p; |
165 | xfs_bstat_t *endp; | |
166 | xfs_fsop_bulkreq_t bulkreq; | |
167 | struct stat mntstat; | |
168 | ||
a504bf72 | 169 | if (stat(mntpt, &mntstat)) { |
258b00ea | 170 | fprintf(stderr, _("can't stat mount point \"%s\": %s\n"), |
8577b2c9 | 171 | mntpt, strerror(errno)); |
258b00ea TS |
172 | return 1; |
173 | } | |
174 | ||
175 | bulkreq.lastip = &lastino; | |
176 | bulkreq.icount = BSTATBUF_SZ; | |
177 | bulkreq.ubuffer = (void *)bstatbuf; | |
178 | bulkreq.ocount = &buflenout; | |
179 | ||
180 | while (xfsctl(mntpt, fsfd, XFS_IOC_FSBULKSTAT, &bulkreq) == 0) { | |
181 | if (*(bulkreq.ocount) == 0) { | |
182 | return 0; | |
183 | } | |
184 | for (p = bstatbuf, endp = bstatbuf + *bulkreq.ocount; p < endp; p++) { | |
185 | ||
186 | /* inode being modified, get synced data with iget */ | |
187 | if ( (!p->bs_nlink || !p->bs_mode) && p->bs_ino != 0 ) { | |
188 | ||
189 | if (xfsctl(mntpt, fsfd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq) < 0) { | |
190 | fprintf(stderr, | |
191 | _("failed to get bulkstat information for inode %llu\n"), | |
192 | p->bs_ino ); | |
193 | continue; | |
194 | } | |
195 | if (!p->bs_nlink || !p->bs_mode || !p->bs_ino) { | |
196 | fprintf(stderr, | |
197 | _("failed to get valid bulkstat information for inode %llu\n"), | |
198 | p->bs_ino ); | |
199 | continue; | |
200 | } | |
201 | } | |
202 | ||
203 | /* skip root */ | |
204 | if (p->bs_ino == mntstat.st_ino) { | |
205 | continue; | |
206 | } | |
207 | ||
208 | if (verbose_flag > 1) { | |
209 | printf(_("checking inode %llu\n"), p->bs_ino); | |
210 | } | |
211 | ||
212 | /* print dotted progress */ | |
213 | if ((inodes_checked % 100) == 0 && verbose_flag == 1) { | |
214 | printf("."); fflush(stdout); | |
215 | } | |
216 | inodes_checked++; | |
217 | ||
74043ab2 | 218 | check_parents(parentbuf, parentbuf_size, fshandlep, p); |
258b00ea TS |
219 | } |
220 | ||
221 | }/*while*/ | |
222 | ||
223 | fprintf(stderr, _("syssgi bulkstat failed: %s\n"), strerror(errno)); | |
224 | return 1; | |
225 | } | |
226 | ||
227 | static int | |
228 | parent_check(void) | |
229 | { | |
258b00ea TS |
230 | int fsfd; |
231 | jdm_fshandle_t *fshandlep; | |
232 | parent_t *parentbuf; | |
74043ab2 | 233 | size_t parentbuf_size = PARENTBUF_SZ; |
258b00ea TS |
234 | xfs_bstat_t *bstatbuf; |
235 | ||
236 | err_status = 0; | |
237 | inodes_checked = 0; | |
238 | ||
239 | sync(); | |
240 | ||
258b00ea TS |
241 | fsfd = file->fd; |
242 | ||
243 | fshandlep = jdm_getfshandle(mntpt); | |
244 | if (fshandlep == 0) { | |
245 | fprintf(stderr, _("unable to open \"%s\" for jdm: %s\n"), | |
246 | mntpt, | |
247 | strerror(errno)); | |
248 | return 1; | |
249 | } | |
250 | ||
251 | /* allocate buffers */ | |
252 | bstatbuf = (xfs_bstat_t *)calloc(BSTATBUF_SZ, sizeof(xfs_bstat_t)); | |
74043ab2 | 253 | parentbuf = (parent_t *)malloc(parentbuf_size); |
258b00ea TS |
254 | if (!bstatbuf || !parentbuf) { |
255 | fprintf(stderr, _("unable to allocate buffers: %s\n"), | |
256 | strerror(errno)); | |
257 | return 1; | |
258 | } | |
259 | ||
74043ab2 | 260 | if (do_bulkstat(parentbuf, &parentbuf_size, bstatbuf, fsfd, fshandlep) != 0) |
258b00ea TS |
261 | err_status++; |
262 | ||
263 | if (err_status > 0) | |
264 | fprintf(stderr, _("num errors: %d\n"), err_status); | |
265 | else | |
266 | printf(_("succeeded checking %llu inodes\n"), inodes_checked); | |
267 | ||
268 | free(bstatbuf); | |
269 | free(parentbuf); | |
270 | return err_status; | |
271 | } | |
272 | ||
273 | static void | |
74043ab2 | 274 | print_parent_entry(parent_t *parent, int fullpath) |
258b00ea TS |
275 | { |
276 | printf(_("p_ino = %llu\n"), parent->p_ino); | |
277 | printf(_("p_gen = %u\n"), parent->p_gen); | |
278 | printf(_("p_reclen = %u\n"), parent->p_reclen); | |
74043ab2 TS |
279 | if (fullpath) |
280 | printf(_("p_name = \"%s%s\"\n"), mntpt, parent->p_name); | |
281 | else | |
282 | printf(_("p_name = \"%s\"\n"), parent->p_name); | |
258b00ea TS |
283 | } |
284 | ||
285 | static int | |
286 | parent_list(int fullpath) | |
287 | { | |
288 | void *handlep; | |
289 | size_t handlen; | |
290 | int error, i; | |
291 | int retval = 1; | |
74043ab2 | 292 | __u32 count; |
258b00ea | 293 | parent_t *entryp; |
74043ab2 | 294 | parent_t *parentbuf = NULL; |
258b00ea | 295 | char *path = file->name; |
74043ab2 | 296 | int pb_size = PARENTBUF_SZ; |
258b00ea TS |
297 | |
298 | /* XXXX for linux libhandle version - to set libhandle fsfd cache */ | |
299 | { | |
300 | void *fshandle; | |
301 | size_t fshlen; | |
302 | ||
74043ab2 | 303 | if (path_to_fshandle(mntpt, &fshandle, &fshlen) != 0) { |
258b00ea TS |
304 | fprintf(stderr, _("%s: failed path_to_fshandle \"%s\": %s\n"), |
305 | progname, path, strerror(errno)); | |
306 | goto error; | |
307 | } | |
308 | } | |
309 | ||
310 | if (path_to_handle(path, &handlep, &handlen) != 0) { | |
311 | fprintf(stderr, _("%s: path_to_handle failed for \"%s\"\n"), progname, path); | |
312 | goto error; | |
313 | } | |
314 | ||
258b00ea | 315 | do { |
74043ab2 TS |
316 | parentbuf = (parent_t *)realloc(parentbuf, pb_size); |
317 | if (!parentbuf) { | |
318 | fprintf(stderr, _("%s: unable to allocate parent buffer: %s\n"), | |
319 | progname, strerror(errno)); | |
320 | return 1; | |
321 | } | |
322 | ||
258b00ea | 323 | if (fullpath) { |
74043ab2 | 324 | error = parentpaths_by_handle(handlep, |
258b00ea TS |
325 | handlen, |
326 | parentbuf, | |
74043ab2 TS |
327 | pb_size, |
328 | &count); | |
258b00ea | 329 | } else { |
74043ab2 | 330 | error = parents_by_handle(handlep, |
258b00ea TS |
331 | handlen, |
332 | parentbuf, | |
74043ab2 TS |
333 | pb_size, |
334 | &count); | |
258b00ea | 335 | } |
74043ab2 TS |
336 | if (error == ERANGE) { |
337 | pb_size *= 2; | |
338 | } else if (error) { | |
339 | fprintf(stderr, _("%s: %s call failed for \"%s\": %s\n"), | |
340 | progname, fullpath ? "parentpaths" : "parents", | |
341 | path, strerror(errno)); | |
258b00ea TS |
342 | goto error; |
343 | } | |
74043ab2 | 344 | } while (error == ERANGE); |
258b00ea | 345 | |
74043ab2 TS |
346 | if (count == 0) { |
347 | /* no links for inode - something wrong here */ | |
348 | fprintf(stderr, _("%s: inode-path is missing\n"), progname); | |
349 | goto error; | |
350 | } | |
258b00ea | 351 | |
74043ab2 TS |
352 | entryp = parentbuf; |
353 | for (i = 0; i < count; i++) { | |
354 | print_parent_entry(entryp, fullpath); | |
355 | entryp = (parent_t*) (((char*)entryp) + entryp->p_reclen); | |
356 | } | |
258b00ea TS |
357 | |
358 | retval = 0; | |
359 | error: | |
360 | free(parentbuf); | |
361 | return retval; | |
362 | } | |
363 | ||
364 | int | |
365 | parent_f(int argc, char **argv) | |
366 | { | |
367 | int c; | |
368 | int listpath_flag = 0; | |
369 | int check_flag = 0; | |
74043ab2 TS |
370 | fs_path_t *fs; |
371 | static int tab_init; | |
372 | ||
373 | if (!tab_init) { | |
374 | tab_init = 1; | |
375 | fs_table_initialise(); | |
376 | } | |
377 | fs = fs_table_lookup(file->name, FS_MOUNT_POINT); | |
378 | if (!fs) { | |
379 | fprintf(stderr, _("file argument, \"%s\", is not in a mounted XFS filesystem\n"), | |
380 | file->name); | |
381 | return 1; | |
382 | } | |
383 | mntpt = fs->fs_dir; | |
258b00ea TS |
384 | |
385 | verbose_flag = 0; | |
386 | ||
387 | while ((c = getopt(argc, argv, "cpv")) != EOF) { | |
388 | switch (c) { | |
389 | case 'c': | |
390 | check_flag = 1; | |
391 | break; | |
392 | case 'p': | |
393 | listpath_flag = 1; | |
394 | break; | |
395 | case 'v': | |
396 | verbose_flag++; | |
397 | break; | |
398 | default: | |
399 | return command_usage(&parent_cmd); | |
400 | } | |
401 | } | |
402 | ||
403 | if (!check_flag && !listpath_flag) /* default case */ | |
404 | exitcode = parent_list(listpath_flag); | |
405 | else { | |
406 | if (listpath_flag) | |
407 | exitcode = parent_list(listpath_flag); | |
408 | if (check_flag) | |
409 | exitcode = parent_check(); | |
410 | } | |
411 | ||
412 | return 0; | |
413 | } | |
414 | ||
415 | static void | |
416 | parent_help(void) | |
417 | { | |
418 | printf(_( | |
419 | "\n" | |
420 | " list the current file's parents and their filenames\n" | |
421 | "\n" | |
422 | " -c -- check the current file's file system for parent consistency\n" | |
423 | " -p -- list the current file's parents and their full paths\n" | |
424 | " -v -- verbose mode\n" | |
425 | "\n")); | |
426 | } | |
427 | ||
428 | void | |
429 | parent_init(void) | |
430 | { | |
431 | parent_cmd.name = _("parent"); | |
432 | parent_cmd.cfunc = parent_f; | |
433 | parent_cmd.argmin = 0; | |
434 | parent_cmd.argmax = -1; | |
435 | parent_cmd.args = _("[-cpv]"); | |
436 | parent_cmd.flags = CMD_NOMAP_OK; | |
437 | parent_cmd.oneline = _("print or check parent inodes"); | |
438 | parent_cmd.help = parent_help; | |
439 | ||
440 | if (expert) | |
441 | add_command(&parent_cmd); | |
442 | } |