/
githubmirror
/
xfsprogs
Обзор
Документация
Войти
/
githubmirror
/
xfsprogs
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
preadv2
io/parent.c
452 строки
10 KB
Eric Sandeen
xfs_io: fix leaks in parent_list()
16 сен 2014, 03:19
16 сен 2014, 03:19
70ac12f
Код
Авторство
О чём код?
/* * Copyright (c) 2005-2006 Silicon Graphics, Inc. * All Rights Reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation. * * This program is distributed in the hope that it would be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include <xfs/xfs.h> #include <xfs/command.h> #include <xfs/input.h> #include <xfs/path.h> #include <xfs/parent.h> #include <xfs/handle.h> #include <xfs/jdm.h> #include "init.h" #include "io.h" #define PARENTBUF_SZ 16384 #define BSTATBUF_SZ 16384 static cmdinfo_t parent_cmd; static int verbose_flag; static int err_status; static __u64 inodes_checked; static char *mntpt; /* * check out a parent entry to see if the values seem valid */ static void check_parent_entry(xfs_bstat_t *bstatp, parent_t *parent) { int sts; char fullpath[PATH_MAX]; struct stat statbuf; char *str; sprintf(fullpath, _("%s%s"), mntpt, parent->p_name); sts = lstat(fullpath, &statbuf); if (sts != 0) { fprintf(stderr, _("inode-path for inode: %llu is incorrect - path \"%s\" non-existent\n"), (unsigned long long) bstatp->bs_ino, fullpath); if (verbose_flag) { fprintf(stderr, _("path \"%s\" does not stat for inode: %llu; err = %s\n"), fullpath, (unsigned long long) bstatp->bs_ino, strerror(errno)); } err_status++; return; } else { if (verbose_flag > 1) { printf(_("path \"%s\" found\n"), fullpath); } } if (statbuf.st_ino != bstatp->bs_ino) { fprintf(stderr, _("inode-path for inode: %llu is incorrect - wrong inode#\n"), (unsigned long long) bstatp->bs_ino); if (verbose_flag) { fprintf(stderr, _("ino mismatch for path \"%s\" %llu vs %llu\n"), fullpath, (unsigned long long)statbuf.st_ino, (unsigned long long)bstatp->bs_ino); } err_status++; return; } else if (verbose_flag > 1) { printf(_("inode number match: %llu\n"), (unsigned long long)statbuf.st_ino); } /* get parent path */ str = strrchr(fullpath, '/'); *str = '\0'; sts = stat(fullpath, &statbuf); if (sts != 0) { fprintf(stderr, _("parent path \"%s\" does not stat: %s\n"), fullpath, strerror(errno)); err_status++; return; } else { if (parent->p_ino != statbuf.st_ino) { fprintf(stderr, _("inode-path for inode: %llu is incorrect - wrong parent inode#\n"), (unsigned long long) bstatp->bs_ino); if (verbose_flag) { fprintf(stderr, _("ino mismatch for path \"%s\" %llu vs %llu\n"), fullpath, (unsigned long long)parent->p_ino, (unsigned long long)statbuf.st_ino); } err_status++; return; } else { if (verbose_flag > 1) { printf(_("parent ino match for %llu\n"), (unsigned long long) parent->p_ino); } } } } static void check_parents(parent_t *parentbuf, size_t *parentbuf_size, jdm_fshandle_t *fshandlep, xfs_bstat_t *statp) { int error, i; __u32 count; parent_t *entryp; do { error = jdm_parentpaths(fshandlep, statp, parentbuf, *parentbuf_size, &count); if (error == ERANGE) { *parentbuf_size *= 2; parentbuf = (parent_t *)realloc(parentbuf, *parentbuf_size); } else if (error) { fprintf(stderr, _("parentpaths failed for ino %llu: %s\n"), (unsigned long long) statp->bs_ino, strerror(errno)); err_status++; break; } } while (error == ERANGE); if (count == 0) { /* no links for inode - something wrong here */ fprintf(stderr, _("inode-path for inode: %llu is missing\n"), (unsigned long long) statp->bs_ino); err_status++; } entryp = parentbuf; for (i = 0; i < count; i++) { check_parent_entry(statp, entryp); entryp = (parent_t*) (((char*)entryp) + entryp->p_reclen); } } static int do_bulkstat(parent_t *parentbuf, size_t *parentbuf_size, xfs_bstat_t *bstatbuf, int fsfd, jdm_fshandle_t *fshandlep) { __s32 buflenout; __u64 lastino = 0; xfs_bstat_t *p; xfs_bstat_t *endp; xfs_fsop_bulkreq_t bulkreq; struct stat mntstat; if (stat(mntpt, &mntstat)) { fprintf(stderr, _("can't stat mount point \"%s\": %s\n"), mntpt, strerror(errno)); return 1; } bulkreq.lastip = &lastino; bulkreq.icount = BSTATBUF_SZ; bulkreq.ubuffer = (void *)bstatbuf; bulkreq.ocount = &buflenout; while (xfsctl(mntpt, fsfd, XFS_IOC_FSBULKSTAT, &bulkreq) == 0) { if (*(bulkreq.ocount) == 0) { return 0; } for (p = bstatbuf, endp = bstatbuf + *bulkreq.ocount; p < endp; p++) { /* inode being modified, get synced data with iget */ if ( (!p->bs_nlink || !p->bs_mode) && p->bs_ino != 0 ) { if (xfsctl(mntpt, fsfd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq) < 0) { fprintf(stderr, _("failed to get bulkstat information for inode %llu\n"), (unsigned long long) p->bs_ino); continue; } if (!p->bs_nlink || !p->bs_mode || !p->bs_ino) { fprintf(stderr, _("failed to get valid bulkstat information for inode %llu\n"), (unsigned long long) p->bs_ino); continue; } } /* skip root */ if (p->bs_ino == mntstat.st_ino) { continue; } if (verbose_flag > 1) { printf(_("checking inode %llu\n"), (unsigned long long) p->bs_ino); } /* print dotted progress */ if ((inodes_checked % 100) == 0 && verbose_flag == 1) { printf("."); fflush(stdout); } inodes_checked++; check_parents(parentbuf, parentbuf_size, fshandlep, p); } }/*while*/ fprintf(stderr, _("syssgi bulkstat failed: %s\n"), strerror(errno)); return 1; } static int parent_check(void) { int fsfd; jdm_fshandle_t *fshandlep; parent_t *parentbuf; size_t parentbuf_size = PARENTBUF_SZ; xfs_bstat_t *bstatbuf; err_status = 0; inodes_checked = 0; sync(); fsfd = file->fd; fshandlep = jdm_getfshandle(mntpt); if (fshandlep == NULL) { fprintf(stderr, _("unable to open \"%s\" for jdm: %s\n"), mntpt, strerror(errno)); return 1; } /* allocate buffers */ bstatbuf = (xfs_bstat_t *)calloc(BSTATBUF_SZ, sizeof(xfs_bstat_t)); parentbuf = (parent_t *)malloc(parentbuf_size); if (!bstatbuf || !parentbuf) { fprintf(stderr, _("unable to allocate buffers: %s\n"), strerror(errno)); err_status = 1; goto out; } if (do_bulkstat(parentbuf, &parentbuf_size, bstatbuf, fsfd, fshandlep) != 0) err_status++; if (err_status > 0) fprintf(stderr, _("num errors: %d\n"), err_status); else printf(_("succeeded checking %llu inodes\n"), (unsigned long long) inodes_checked); out: free(bstatbuf); free(parentbuf); free(fshandlep); return err_status; } static void print_parent_entry(parent_t *parent, int fullpath) { printf(_("p_ino = %llu\n"), (unsigned long long) parent->p_ino); printf(_("p_gen = %u\n"), parent->p_gen); printf(_("p_reclen = %u\n"), parent->p_reclen); if (fullpath) printf(_("p_name = \"%s%s\"\n"), mntpt, parent->p_name); else printf(_("p_name = \"%s\"\n"), parent->p_name); } static int parent_list(int fullpath) { void *handlep = NULL; size_t handlen; int error, i; int retval = 1; __u32 count; parent_t *entryp; parent_t *parentbuf = NULL; char *path = file->name; int pb_size = PARENTBUF_SZ; /* XXXX for linux libhandle version - to set libhandle fsfd cache */ { void *fshandle; size_t fshlen; if (path_to_fshandle(mntpt, &fshandle, &fshlen) != 0) { fprintf(stderr, _("%s: failed path_to_fshandle \"%s\": %s\n"), progname, path, strerror(errno)); goto error; } free_handle(fshandle, fshlen); } if (path_to_handle(path, &handlep, &handlen) != 0) { fprintf(stderr, _("%s: path_to_handle failed for \"%s\"\n"), progname, path); goto error; } do { parentbuf = (parent_t *)realloc(parentbuf, pb_size); if (!parentbuf) { fprintf(stderr, _("%s: unable to allocate parent buffer: %s\n"), progname, strerror(errno)); goto error; } if (fullpath) { error = parentpaths_by_handle(handlep, handlen, parentbuf, pb_size, &count); } else { error = parents_by_handle(handlep, handlen, parentbuf, pb_size, &count); } if (error == ERANGE) { pb_size *= 2; } else if (error) { fprintf(stderr, _("%s: %s call failed for \"%s\": %s\n"), progname, fullpath ? "parentpaths" : "parents", path, strerror(errno)); goto error; } } while (error == ERANGE); if (count == 0) { /* no links for inode - something wrong here */ fprintf(stderr, _("%s: inode-path is missing\n"), progname); goto error; } entryp = parentbuf; for (i = 0; i < count; i++) { print_parent_entry(entryp, fullpath); entryp = (parent_t*) (((char*)entryp) + entryp->p_reclen); } retval = 0; error: free(handlep); free(parentbuf); return retval; } int parent_f(int argc, char **argv) { int c; int listpath_flag = 0; int check_flag = 0; fs_path_t *fs; static int tab_init; if (!tab_init) { tab_init = 1; fs_table_initialise(0, NULL, 0, NULL); } fs = fs_table_lookup(file->name, FS_MOUNT_POINT); if (!fs) { fprintf(stderr, _("file argument, \"%s\", is not in a mounted XFS filesystem\n"), file->name); return 1; } mntpt = fs->fs_dir; verbose_flag = 0; while ((c = getopt(argc, argv, "cpv")) != EOF) { switch (c) { case 'c': check_flag = 1; break; case 'p': listpath_flag = 1; break; case 'v': verbose_flag++; break; default: return command_usage(&parent_cmd); } } if (!check_flag && !listpath_flag) /* default case */ exitcode = parent_list(listpath_flag); else { if (listpath_flag) exitcode = parent_list(listpath_flag); if (check_flag) exitcode = parent_check(); } return 0; } static void parent_help(void) { printf(_( "\n" " list the current file's parents and their filenames\n" "\n" " -c -- check the current file's file system for parent consistency\n" " -p -- list the current file's parents and their full paths\n" " -v -- verbose mode\n" "\n")); } void parent_init(void) { parent_cmd.name = "parent"; parent_cmd.cfunc = parent_f; parent_cmd.argmin = 0; parent_cmd.argmax = -1; parent_cmd.args = _("[-cpv]"); parent_cmd.flags = CMD_NOMAP_OK; parent_cmd.oneline = _("print or check parent inodes"); parent_cmd.help = parent_help; if (expert) add_command(&parent_cmd); }