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