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