From: Christoph Hellwig Date: Fri, 2 Mar 2012 08:35:04 +0000 (+0000) Subject: fsr: fix /proc/mounts parsing X-Git-Tag: v3.1.8~9 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=3e50d8886920a4332cc7d0471a280308046df9a3;p=thirdparty%2Fxfsprogs-dev.git fsr: fix /proc/mounts parsing Make sure we do not reject an XFS root mount just because /dev/root is also listed in /proc/mounts. The root cause for this was the awkward getmntany function, which is replaced with a broader reach find_mountpoint function which replace getmntany and the surrounding code from the main routine in a structured way. This changes the flow from finding a mounted filesystem matching the argument and checking that it's XFS to find a mounted XFS filesystem and thus fixes the bug. Based on analysis and an earlier patch from Carlos Maiolino . Reviewed-by: Eric Sandeen Signed-off-by: Christoph Hellwig --- diff --git a/fsr/xfs_fsr.c b/fsr/xfs_fsr.c index 40c2e6fdf..2db222498 100644 --- a/fsr/xfs_fsr.c +++ b/fsr/xfs_fsr.c @@ -109,7 +109,6 @@ static void tmp_init(char *mnt); static char * tmp_next(char *mnt); static void tmp_close(char *mnt); int xfs_getgeom(int , xfs_fsop_geom_v1_t * ); -static int getmntany(FILE *, struct mntent *, struct mntent *, struct stat64 *); xfs_fsop_geom_v1_t fsgeom; /* geometry of active mounted system */ @@ -178,18 +177,71 @@ aborter(int unused) exit(1); } +/* + * Check if the argument is either the device name or mountpoint of an XFS + * filesystem. Note that we do not care about bind mounted regular files + * here - the code that handles defragmentation of invidual files takes care + * of that. + */ +static char * +find_mountpoint(char *mtab, char *argname, struct stat64 *sb) +{ + struct mntent *t; + struct stat64 ms; + FILE *mtabp; + char *mntp = NULL; + + mtabp = setmntent(mtab, "r"); + if (!mtabp) { + fprintf(stderr, _("%s: cannot read %s\n"), + progname, mtab); + exit(1); + } + + while ((t = getmntent(mtabp))) { + if (S_ISDIR(sb->st_mode)) { /* mount point */ + if (stat64(t->mnt_dir, &ms) < 0) + continue; + if (sb->st_ino != ms.st_ino) + continue; + if (sb->st_dev != ms.st_dev) + continue; + if (strcmp(t->mnt_type, MNTTYPE_XFS) != 0) + continue; + } else { /* device */ + struct stat64 sb2; + + if (stat64(t->mnt_fsname, &ms) < 0) + continue; + if (sb->st_rdev != ms.st_rdev) + continue; + if (strcmp(t->mnt_type, MNTTYPE_XFS) != 0) + continue; + + /* + * Make sure the mountpoint given by mtab is accessible + * before using it. + */ + if (stat64(t->mnt_dir, &sb2) < 0) + continue; + } + + mntp = t->mnt_dir; + break; + } + + endmntent(mtabp); + return mntp; +} + int main(int argc, char **argv) { - struct stat64 sb, sb2; + struct stat64 sb; char *argname; - char *cp; int c; - struct mntent mntpref; - register struct mntent *mntp; - struct mntent ment; + char *mntp; char *mtab = NULL; - register FILE *mtabp; setlinebuf(stdout); progname = basename(argv[0]); @@ -281,49 +333,26 @@ main(int argc, char **argv) if (optind < argc) { for (; optind < argc; optind++) { argname = argv[optind]; - mntp = NULL; + if (lstat64(argname, &sb) < 0) { fprintf(stderr, _("%s: could not stat: %s: %s\n"), progname, argname, strerror(errno)); continue; } - if (S_ISLNK(sb.st_mode) && stat64(argname, &sb2) == 0 && - (S_ISBLK(sb2.st_mode) || S_ISCHR(sb2.st_mode))) + + if (S_ISLNK(sb.st_mode)) { + struct stat64 sb2; + + if (stat64(argname, &sb2) == 0 && + (S_ISBLK(sb2.st_mode) || + S_ISCHR(sb2.st_mode))) sb = sb2; - if (S_ISBLK(sb.st_mode) || (S_ISDIR(sb.st_mode))) { - if ((mtabp = setmntent(mtab, "r")) == NULL) { - fprintf(stderr, - _("%s: cannot read %s\n"), - progname, mtab); - exit(1); - } - bzero(&mntpref, sizeof(mntpref)); - if (S_ISDIR(sb.st_mode)) - mntpref.mnt_dir = argname; - else - mntpref.mnt_fsname = argname; - - if (getmntany(mtabp, &ment, &mntpref, &sb) && - strcmp(ment.mnt_type, MNTTYPE_XFS) == 0) { - mntp = &ment; - if (S_ISBLK(sb.st_mode)) { - cp = mntp->mnt_dir; - if (cp == NULL || - stat64(cp, &sb2) < 0) { - fprintf(stderr, _( - "%s: could not stat: %s: %s\n"), - progname, argname, - strerror(errno)); - continue; - } - sb = sb2; - argname = cp; - } - } } + + mntp = find_mountpoint(mtab, argname, &sb); if (mntp != NULL) { - fsrfs(mntp->mnt_dir, 0, 100); + fsrfs(mntp, 0, 100); } else if (S_ISCHR(sb.st_mode)) { fprintf(stderr, _( "%s: char special not supported: %s\n"), @@ -1638,35 +1667,6 @@ fsrprintf(const char *fmt, ...) return 0; } -/* - * emulate getmntany - */ -static int -getmntany(FILE *fp, struct mntent *mp, struct mntent *mpref, struct stat64 *s) -{ - struct mntent *t; - struct stat64 ms; - - while ((t = getmntent(fp))) { - if (mpref->mnt_fsname) { /* device */ - if (stat64(t->mnt_fsname, &ms) < 0) - continue; - if (s->st_rdev != ms.st_rdev) - continue; - } - if (mpref->mnt_dir) { /* mount point */ - if (stat64(t->mnt_dir, &ms) < 0) - continue; - if (s->st_ino != ms.st_ino || s->st_dev != ms.st_dev) - continue; - } - *mp = *t; - break; - } - return (t != NULL); -} - - /* * Initialize a directory for tmp file use. This is used * by the full filesystem defragmentation when we're walking