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