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