]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - io/parent.c
xfs_io: hook up statx
[thirdparty/xfsprogs-dev.git] / io / parent.c
1 /*
2 * Copyright (c) 2005-2006 Silicon Graphics, Inc.
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 "command.h"
20 #include "input.h"
21 #include "path.h"
22 #include "parent.h"
23 #include "handle.h"
24 #include "jdm.h"
25 #include "init.h"
26 #include "io.h"
27
28 #define PARENTBUF_SZ 16384
29 #define BSTATBUF_SZ 16384
30
31 static cmdinfo_t parent_cmd;
32 static int verbose_flag;
33 static int err_status;
34 static __u64 inodes_checked;
35 static char *mntpt;
36
37 /*
38 * check out a parent entry to see if the values seem valid
39 */
40 static void
41 check_parent_entry(xfs_bstat_t *bstatp, parent_t *parent)
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,
53 _("inode-path for inode: %llu is incorrect - path \"%s\" non-existent\n"),
54 (unsigned long long) bstatp->bs_ino, fullpath);
55 if (verbose_flag) {
56 fprintf(stderr,
57 _("path \"%s\" does not stat for inode: %llu; err = %s\n"),
58 fullpath,
59 (unsigned long long) bstatp->bs_ino,
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"),
73 (unsigned long long) bstatp->bs_ino);
74 if (verbose_flag) {
75 fprintf(stderr,
76 _("ino mismatch for path \"%s\" %llu vs %llu\n"),
77 fullpath,
78 (unsigned long long)statbuf.st_ino,
79 (unsigned long long)bstatp->bs_ino);
80 }
81 err_status++;
82 return;
83 } else if (verbose_flag > 1) {
84 printf(_("inode number match: %llu\n"),
85 (unsigned long long)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 (unsigned long long) bstatp->bs_ino);
104 if (verbose_flag) {
105 fprintf(stderr,
106 _("ino mismatch for path \"%s\" %llu vs %llu\n"),
107 fullpath,
108 (unsigned long long)parent->p_ino,
109 (unsigned long long)statbuf.st_ino);
110 }
111 err_status++;
112 return;
113 } else {
114 if (verbose_flag > 1) {
115 printf(_("parent ino match for %llu\n"),
116 (unsigned long long) parent->p_ino);
117 }
118 }
119 }
120 }
121
122 static void
123 check_parents(parent_t *parentbuf, size_t *parentbuf_size,
124 jdm_fshandle_t *fshandlep, xfs_bstat_t *statp)
125 {
126 int error, i;
127 __u32 count;
128 parent_t *entryp;
129
130 do {
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"),
138 (unsigned long long) statp->bs_ino,
139 strerror(errno));
140 err_status++;
141 break;
142 }
143 } while (error == ERANGE);
144
145
146 if (count == 0) {
147 /* no links for inode - something wrong here */
148 fprintf(stderr, _("inode-path for inode: %llu is missing\n"),
149 (unsigned long long) statp->bs_ino);
150 err_status++;
151 }
152
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 }
158 }
159
160 static int
161 do_bulkstat(parent_t *parentbuf, size_t *parentbuf_size, xfs_bstat_t *bstatbuf,
162 int fsfd, jdm_fshandle_t *fshandlep)
163 {
164 __s32 buflenout;
165 __u64 lastino = 0;
166 xfs_bstat_t *p;
167 xfs_bstat_t *endp;
168 xfs_fsop_bulkreq_t bulkreq;
169 struct stat mntstat;
170
171 if (stat(mntpt, &mntstat)) {
172 fprintf(stderr, _("can't stat mount point \"%s\": %s\n"),
173 mntpt, strerror(errno));
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"),
194 (unsigned long long) p->bs_ino);
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"),
200 (unsigned long long) p->bs_ino);
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) {
211 printf(_("checking inode %llu\n"),
212 (unsigned long long) p->bs_ino);
213 }
214
215 /* print dotted progress */
216 if ((inodes_checked % 100) == 0 && verbose_flag == 1) {
217 printf("."); fflush(stdout);
218 }
219 inodes_checked++;
220
221 check_parents(parentbuf, parentbuf_size, fshandlep, p);
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 {
233 int fsfd;
234 jdm_fshandle_t *fshandlep;
235 parent_t *parentbuf;
236 size_t parentbuf_size = PARENTBUF_SZ;
237 xfs_bstat_t *bstatbuf;
238
239 err_status = 0;
240 inodes_checked = 0;
241
242 sync();
243
244 fsfd = file->fd;
245
246 fshandlep = jdm_getfshandle(mntpt);
247 if (fshandlep == NULL) {
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));
256 parentbuf = (parent_t *)malloc(parentbuf_size);
257 if (!bstatbuf || !parentbuf) {
258 fprintf(stderr, _("unable to allocate buffers: %s\n"),
259 strerror(errno));
260 err_status = 1;
261 goto out;
262 }
263
264 if (do_bulkstat(parentbuf, &parentbuf_size, bstatbuf, fsfd, fshandlep) != 0)
265 err_status++;
266
267 if (err_status > 0)
268 fprintf(stderr, _("num errors: %d\n"), err_status);
269 else
270 printf(_("succeeded checking %llu inodes\n"),
271 (unsigned long long) inodes_checked);
272
273 out:
274 free(bstatbuf);
275 free(parentbuf);
276 free(fshandlep);
277 return err_status;
278 }
279
280 static void
281 print_parent_entry(parent_t *parent, int fullpath)
282 {
283 printf(_("p_ino = %llu\n"), (unsigned long long) parent->p_ino);
284 printf(_("p_gen = %u\n"), parent->p_gen);
285 printf(_("p_reclen = %u\n"), parent->p_reclen);
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);
290 }
291
292 static int
293 parent_list(int fullpath)
294 {
295 void *handlep = NULL;
296 size_t handlen;
297 int error, i;
298 int retval = 1;
299 __u32 count;
300 parent_t *entryp;
301 parent_t *parentbuf = NULL;
302 char *path = file->name;
303 int pb_size = PARENTBUF_SZ;
304
305 /* XXXX for linux libhandle version - to set libhandle fsfd cache */
306 {
307 void *fshandle;
308 size_t fshlen;
309
310 if (path_to_fshandle(mntpt, &fshandle, &fshlen) != 0) {
311 fprintf(stderr, _("%s: failed path_to_fshandle \"%s\": %s\n"),
312 progname, path, strerror(errno));
313 goto error;
314 }
315 free_handle(fshandle, fshlen);
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
323 do {
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));
328 goto error;
329 }
330
331 if (fullpath) {
332 error = parentpaths_by_handle(handlep,
333 handlen,
334 parentbuf,
335 pb_size,
336 &count);
337 } else {
338 error = parents_by_handle(handlep,
339 handlen,
340 parentbuf,
341 pb_size,
342 &count);
343 }
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));
350 goto error;
351 }
352 } while (error == ERANGE);
353
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 }
359
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 }
365
366 retval = 0;
367 error:
368 free(handlep);
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;
379 fs_path_t *fs;
380 static int tab_init;
381
382 if (!tab_init) {
383 tab_init = 1;
384 fs_table_initialise(0, NULL, 0, NULL);
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;
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 {
440 parent_cmd.name = "parent";
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 }