]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blobdiff - fsr/xfs_fsr.c
xfs_scrub: remove moveon from progress report helpers
[thirdparty/xfsprogs-dev.git] / fsr / xfs_fsr.c
index 253a55d909c34bad8d65fbeef6a217aa8a77a0a3..af5d6169eb8ab4c98dca582be28a0b14482d1472 100644 (file)
@@ -1,62 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * Copyright (c) 2000-2002 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/jdm.h>
-#include <xfs/xfs_dfrag.h>
+#include "libxfs.h"
+#include "xfs.h"
+#include "xfs_types.h"
+#include "jdm.h"
+#include "xfs_bmap_btree.h"
+#include "xfs_attr_sf.h"
+#include "libfrog/paths.h"
+#include "libfrog/fsgeom.h"
+#include "libfrog/bulkstat.h"
 
 #include <fcntl.h>
 #include <errno.h>
-#include <malloc.h>
-#include <mntent.h>
 #include <syslog.h>
 #include <signal.h>
 #include <sys/ioctl.h>
 #include <sys/wait.h>
-#include <sys/vfs.h>
 #include <sys/statvfs.h>
 #include <sys/xattr.h>
+#include <paths.h>
 
+#define _PATH_FSRLAST          "/var/tmp/.fsrlast_xfs"
+#define _PATH_PROC_MOUNTS      "/proc/mounts"
 
-#ifndef XFS_XFLAG_NODEFRAG
-#define XFS_XFLAG_NODEFRAG 0x00002000 /* src dependancy, remove later */
-#endif
-
-#define _PATH_FSRLAST  "/var/tmp/.fsrlast_xfs"
 
 char *progname;
 
-int vflag;
-int gflag;
+static int vflag;
+static int gflag;
 static int Mflag;
 /* static int nflag; */
-int dflag = 0;
+static int dflag = 0;
 /* static int sflag; */
-int argv_blksz_dio;
+static int argv_blksz_dio;
 extern int max_ext_size;
 static int npasses = 10;
 static int startpass = 0;
 
-struct getbmap  *outmap = NULL;
-int             outmap_size = 0;
-int            RealUid;
-int            tmp_agi;
-static __int64_t       minimumfree = 2048;
+static struct getbmap  *outmap = NULL;
+static int             outmap_size = 0;
+static int             RealUid;
+static int             tmp_agi;
+static int64_t         minimumfree = 2048;
 
 #define MNTTYPE_XFS             "xfs"
 
@@ -65,16 +54,10 @@ static __int64_t    minimumfree = 2048;
 #define NULLFD         -1
 #define GRABSZ         64
 #define TARGETRANGE    10
-#define        V_NONE          0
-#define        V_OVERVIEW      1
-#define        V_ALL           2
-#define BUFFER_SIZE    (1<<16)
 #define BUFFER_MAX     (1<<24)
-#define min(x, y) ((x) < (y) ? (x) : (y))
 
 static time_t howlong = 7200;          /* default seconds of reorganizing */
 static char *leftofffile = _PATH_FSRLAST; /* where we left off last */
-static char *mtab = MOUNTED;
 static time_t endtime;
 static time_t starttime;
 static xfs_ino_t       leftoffino = 0;
@@ -83,29 +66,27 @@ static int  pagesize;
 void usage(int ret);
 static int  fsrfile(char *fname, xfs_ino_t ino);
 static int  fsrfile_common( char *fname, char *tname, char *mnt,
-                            int fd, xfs_bstat_t *statp);
+                            int fd, struct xfs_bstat *statp);
 static int  packfile(char *fname, char *tname, int fd,
-                     xfs_bstat_t *statp, struct fsxattr *fsxp);
+                     struct xfs_bstat *statp, struct fsxattr *fsxp);
 static void fsrdir(char *dirname);
 static int  fsrfs(char *mntdir, xfs_ino_t ino, int targetrange);
 static void initallfs(char *mtab);
-static void fsrallfs(int howlong, char *leftofffile);
+static void fsrallfs(char *mtab, int howlong, char *leftofffile);
 static void fsrall_cleanup(int timeout);
 static int  getnextents(int);
 int xfsrtextsize(int fd);
-int xfs_getrt(int fd, struct statvfs64 *sfbp);
+int xfs_getrt(int fd, struct statvfs *sfbp);
 char * gettmpname(char *fname);
 char * getparent(char *fname);
 int fsrprintf(const char *fmt, ...);
-int read_fd_bmap(int, xfs_bstat_t *, int *);
+int read_fd_bmap(int, struct xfs_bstat *, int *);
 int cmp(const void *, const void *);
 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 */
+static struct xfs_fsop_geom fsgeom;    /* geometry of active mounted system */
 
 #define NMOUNT 64
 static int numfs;
@@ -116,56 +97,25 @@ typedef struct fsdesc {
        int  npass;
 } fsdesc_t;
 
-fsdesc_t       *fs, *fsbase, *fsend;
-int            fsbufsize = 10; /* A starting value */
-int            nfrags = 0;     /* Debug option: Coerse into specific number
+static fsdesc_t        *fs, *fsbase, *fsend;
+static int     fsbufsize = 10; /* A starting value */
+static int     nfrags = 0;     /* Debug option: Coerse into specific number
                                 * of extents */
-int            openopts = O_CREAT|O_EXCL|O_RDWR|O_DIRECT;
-
-int
-xfs_fsgeometry(int fd, xfs_fsop_geom_v1_t *geom)
-{
-    return ioctl(fd, XFS_IOC_FSGEOMETRY_V1, geom);
-}
-
-int
-xfs_bulkstat_single(int fd, xfs_ino_t *lastip, xfs_bstat_t *ubuffer)
-{
-    xfs_fsop_bulkreq_t  bulkreq;
-
-    bulkreq.lastip = lastip;
-    bulkreq.icount = 1;
-    bulkreq.ubuffer = ubuffer;
-    bulkreq.ocount = NULL;
-    return ioctl(fd, XFS_IOC_FSBULKSTAT_SINGLE, &bulkreq);
-}
-
-int
-xfs_bulkstat(int fd, xfs_ino_t *lastip, int icount,
-                    xfs_bstat_t *ubuffer, __s32 *ocount)
-{
-    xfs_fsop_bulkreq_t  bulkreq;
-
-    bulkreq.lastip = lastip;
-    bulkreq.icount = icount;
-    bulkreq.ubuffer = ubuffer;
-    bulkreq.ocount = ocount;
-    return ioctl(fd, XFS_IOC_FSBULKSTAT, &bulkreq);
-}
+static int     openopts = O_CREAT|O_EXCL|O_RDWR|O_DIRECT;
 
-int
+static int
 xfs_swapext(int fd, xfs_swapext_t *sx)
 {
     return ioctl(fd, XFS_IOC_SWAPEXT, sx);
 }
 
-int
+static int
 xfs_fscounts(int fd, xfs_fsop_counts_t *counts)
 {
     return ioctl(fd, XFS_IOC_FSCOUNTS, counts);
 }
 
-void
+static void
 aborter(int unused)
 {
        fsrall_cleanup(1);
@@ -175,14 +125,11 @@ aborter(int unused)
 int
 main(int argc, char **argv)
 {
-       struct stat64 sb, sb2;
+       struct stat sb;
        char *argname;
-       char *cp;
        int c;
-       struct mntent mntpref;
-       register struct mntent *mntp;
-       struct mntent ment;
-       register FILE *mtabp;
+       struct fs_path  *fsp;
+       char *mtab = NULL;
 
        setlinebuf(stdout);
        progname = basename(argv[0]);
@@ -193,7 +140,7 @@ main(int argc, char **argv)
 
        gflag = ! isatty(0);
 
-       while ((c = getopt(argc, argv, "C:p:e:MgsdnvTt:f:m:b:N:FV")) != -1 )
+       while ((c = getopt(argc, argv, "C:p:e:MgsdnvTt:f:m:b:N:FV")) != -1) {
                switch (c) {
                case 'M':
                        Mflag = 1;
@@ -245,62 +192,57 @@ main(int argc, char **argv)
                default:
                        usage(1);
                }
+       }
+
+       /*
+        * If the user did not specify an explicit mount table, try to use
+        * /proc/mounts if it is available, else /etc/mtab.  We prefer
+        * /proc/mounts because it is kernel controlled, while /etc/mtab
+        * may contain garbage that userspace tools like pam_mounts wrote
+        * into it.
+        */
+       if (!mtab) {
+               if (access(_PATH_PROC_MOUNTS, R_OK) == 0)
+                       mtab = _PATH_PROC_MOUNTS;
+               else
+                       mtab = _PATH_MOUNTED;
+       }
+
        if (vflag)
                setbuf(stdout, NULL);
 
-       starttime = time(0);
+       starttime = time(NULL);
 
        /* Save the caller's real uid */
        RealUid = getuid();
 
        pagesize = getpagesize();
-
+       fs_table_initialise(0, NULL, 0, NULL);
        if (optind < argc) {
                for (; optind < argc; optind++) {
                        argname = argv[optind];
-                       mntp = NULL;
-                       if (lstat64(argname, &sb) < 0) {
+
+                       if (lstat(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 stat sb2;
+
+                               if (stat(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;
-                                       }
-                               }
                        }
-                       if (mntp != NULL) {
-                               fsrfs(mntp->mnt_dir, 0, 100);
+
+                       fsp = fs_table_lookup_mount(argname);
+                       if (!fsp)
+                               fsp = fs_table_lookup_blkdev(argname);
+                       if (fsp != NULL) {
+                               fsrfs(fsp->fs_dir, 0, 100);
                        } else if (S_ISCHR(sb.st_mode)) {
                                fprintf(stderr, _(
                                        "%s: char special not supported: %s\n"),
@@ -325,7 +267,7 @@ main(int argc, char **argv)
                }
        } else {
                initallfs(mtab);
-               fsrallfs(howlong, leftofffile);
+               fsrallfs(mtab, howlong, leftofffile);
        }
        return 0;
 }
@@ -334,20 +276,19 @@ void
 usage(int ret)
 {
        fprintf(stderr, _(
-"Usage: %s [-d] [-v] [-n] [-s] [-g] [-t time] [-p passes] [-f leftf] [-m mtab]\n"
-"       %s [-d] [-v] [-n] [-s] [-g] xfsdev | dir | file ...\n\n"
+"Usage: %s [-d] [-v] [-g] [-t time] [-p passes] [-f leftf] [-m mtab]\n"
+"       %s [-d] [-v] [-g] xfsdev | dir | file ...\n"
+"       %s -V\n\n"
 "Options:\n"
-"       -n              Do nothing, only interesting with -v. Not\n"
-"                       effective with in mtab mode.\n"
-"       -s             Print statistics only.\n"
 "       -g              Print to syslog (default if stdout not a tty).\n"
 "       -t time         How long to run in seconds.\n"
-"       -p passes      Number of passes before terminating global re-org.\n"
+"       -p passes       Number of passes before terminating global re-org.\n"
 "       -f leftoff      Use this instead of %s.\n"
 "       -m mtab         Use something other than /etc/mtab.\n"
 "       -d              Debug, print even more.\n"
-"       -v             Verbose, more -v's more verbose.\n"
-               ), progname, progname, _PATH_FSRLAST);
+"       -v              Verbose, more -v's more verbose.\n"
+"       -V              Print version number and exit.\n"
+               ), progname, progname, progname, _PATH_FSRLAST);
        exit(ret);
 }
 
@@ -357,17 +298,11 @@ usage(int ret)
 static void
 initallfs(char *mtab)
 {
-       FILE *fp;
-       struct mntent *mp;
+       struct mntent_cursor cursor;
+       struct mntent *mnt= NULL;
        int mi;
        char *cp;
-       struct stat64 sb;
-
-       fp = setmntent(mtab, "r");
-       if (fp == NULL) {
-               fsrprintf(_("could not open mtab file: %s\n"), mtab);
-               exit(1);
-       }
+       struct stat sb;
 
        /* malloc a number of descriptors, increased later if needed */
        if (!(fsbase = (fsdesc_t *)malloc(fsbufsize * sizeof(fsdesc_t)))) {
@@ -379,15 +314,21 @@ initallfs(char *mtab)
        /* find all rw xfs file systems */
        mi = 0;
        fs = fsbase;
-       while ((mp = getmntent(fp))) {
+
+       if (platform_mntent_open(&cursor, mtab) != 0){
+               fprintf(stderr, "Error: can't get mntent entries.\n");
+               exit(1);
+       }
+
+       while ((mnt = platform_mntent_next(&cursor)) != NULL) {
                int rw = 0;
 
-               if (strcmp(mp->mnt_type, MNTTYPE_XFS ) != 0 ||
-                   stat64(mp->mnt_fsname, &sb) == -1 ||
+               if (strcmp(mnt->mnt_type, MNTTYPE_XFS ) != 0 ||
+                   stat(mnt->mnt_fsname, &sb) == -1 ||
                    !S_ISBLK(sb.st_mode))
                        continue;
 
-               cp = strtok(mp->mnt_opts,",");
+               cp = strtok(mnt->mnt_opts,",");
                do {
                        if (strcmp("rw", cp) == 0)
                                rw++;
@@ -395,7 +336,7 @@ initallfs(char *mtab)
                if (rw == 0) {
                        if (dflag)
                                fsrprintf(_("Skipping %s: not mounted rw\n"),
-                                       mp->mnt_fsname);
+                                       mnt->mnt_fsname);
                        continue;
                }
 
@@ -415,19 +356,24 @@ initallfs(char *mtab)
                        fs = (fsbase + mi);  /* Needed ? */
                }
 
-               fs->dev = strdup(mp->mnt_fsname);
-               fs->mnt = strdup(mp->mnt_dir);
+               fs->dev = strdup(mnt->mnt_fsname);
+               fs->mnt = strdup(mnt->mnt_dir);
 
-               if (fs->mnt == NULL || fs->mnt == NULL) {
-                       fsrprintf(_("strdup(%s) failed\n"), mp->mnt_fsname);
+               if (fs->dev == NULL) {
+                       fsrprintf(_("strdup(%s) failed\n"), mnt->mnt_fsname);
+                       exit(1);
+               }
+               if (fs->mnt == NULL) {
+                       fsrprintf(_("strdup(%s) failed\n"), mnt->mnt_dir);
                        exit(1);
                }
                mi++;
                fs++;
        }
+       platform_mntent_close(&cursor);
+
        numfs = mi;
        fsend = (fsbase + numfs);
-       endmntent(fp);
        if (numfs == 0) {
                fsrprintf(_("no rw xfs file systems in mtab: %s\n"), mtab);
                exit(0);
@@ -442,7 +388,7 @@ initallfs(char *mtab)
 }
 
 static void
-fsrallfs(int howlong, char *leftofffile)
+fsrallfs(char *mtab, int howlong, char *leftofffile)
 {
        int fd;
        int error;
@@ -453,7 +399,7 @@ fsrallfs(int howlong, char *leftofffile)
        char *ptr;
        xfs_ino_t startino = 0;
        fsdesc_t *fsp;
-       struct stat64 sb, sb2;
+       struct stat sb, sb2;
 
        fsrprintf("xfs_fsr -m %s -t %d -f %s ...\n", mtab, howlong, leftofffile);
 
@@ -461,11 +407,11 @@ fsrallfs(int howlong, char *leftofffile)
        fs = fsbase;
 
        /* where'd we leave off last time? */
-       if (lstat64(leftofffile, &sb) == 0) {
+       if (lstat(leftofffile, &sb) == 0) {
                if ( (fd = open(leftofffile, O_RDONLY)) == -1 ) {
                        fsrprintf(_("%s: open failed\n"), leftofffile);
                }
-               else if ( fstat64(fd, &sb2) == 0) {
+               else if ( fstat(fd, &sb2) == 0) {
                        /*
                         * Verify that lstat & fstat point to the
                         * same regular file (no links/no quick spoofs)
@@ -501,6 +447,8 @@ fsrallfs(int howlong, char *leftofffile)
                        fsrprintf(_("could not read %s, starting with %s\n"),
                                leftofffile, *fs->dev);
                } else {
+                       /* Ensure the buffer we read is null terminated */
+                       buf[SMBUFSZ-1] = '\0';
                        for (fs = fsbase; fs < fsend; fs++) {
                                fsname = fs->dev;
                                if ((strncmp(buf,fsname,strlen(fsname)) == 0)
@@ -518,6 +466,17 @@ fsrallfs(int howlong, char *leftofffile)
                                ptr = strchr(ptr, ' ');
                                if (ptr) {
                                        startino = strtoull(++ptr, NULL, 10);
+                                       /*
+                                        * NOTE: The inode number read in from
+                                        * the leftoff file is the last inode
+                                        * to have been fsr'd.  Since the v5
+                                        * xfrog_bulkstat function wants to be
+                                        * passed the first inode that we want
+                                        * to examine, increment the value that
+                                        * we read in.  The debug message below
+                                        * prints the lastoff value.
+                                        */
+                                       startino++;
                                }
                        }
                        if (startpass < 0)
@@ -536,7 +495,7 @@ fsrallfs(int howlong, char *leftofffile)
 
        if (vflag) {
                fsrprintf(_("START: pass=%d ino=%llu %s %s\n"),
-                         fs->npass, (unsigned long long)startino,
+                         fs->npass, (unsigned long long)startino - 1,
                          fs->dev, fs->mnt);
        }
 
@@ -547,14 +506,9 @@ fsrallfs(int howlong, char *leftofffile)
        signal(SIGTERM, aborter);
 
        /* reorg for 'howlong' -- checked in 'fsrfs' */
-       while (endtime > time(0)) {
+       while (endtime > time(NULL)) {
                pid_t pid;
-               if (fs == fsend)
-                       fs = fsbase;
-               if (fs->npass == npasses) {
-                       fsrprintf(_("Completed all %d passes\n"), npasses);
-                       break;
-               }
+
                if (npasses > 1 && !fs->npass)
                        Mflag = 1;
                else
@@ -571,7 +525,6 @@ fsrallfs(int howlong, char *leftofffile)
                        break;
                default:
                        wait(&error);
-                       close(fd);
                        if (WIFEXITED(error) && WEXITSTATUS(error) == 1) {
                                /* child timed out & did fsrall_cleanup */
                                exit(0);
@@ -581,8 +534,14 @@ fsrallfs(int howlong, char *leftofffile)
                startino = 0;  /* reset after the first time through */
                fs->npass++;
                fs++;
+               if (fs == fsend)
+                       fs = fsbase;
+               if (fs->npass == npasses) {
+                       fsrprintf(_("Completed all %d passes\n"), npasses);
+                       break;
+               }
        }
-       fsrall_cleanup(endtime <= time(0));
+       fsrall_cleanup(endtime <= time(NULL));
 }
 
 /*
@@ -595,14 +554,19 @@ fsrall_cleanup(int timeout)
        int ret;
        char buf[SMBUFSZ];
 
-       /* record where we left off */
        unlink(leftofffile);
-       fd = open(leftofffile, O_WRONLY|O_CREAT|O_EXCL, 0644);
-       if (fd == -1)
-               fsrprintf(_("open(%s) failed: %s\n"),
-                         leftofffile, strerror(errno));
-       else {
-               if (timeout) {
+
+       if (timeout) {
+               fsrprintf(_("%s startpass %d, endpass %d, time %d seconds\n"),
+                       progname, startpass, fs->npass,
+                       time(NULL) - endtime + howlong);
+
+               /* record where we left off */
+               fd = open(leftofffile, O_WRONLY|O_CREAT|O_EXCL, 0644);
+               if (fd == -1) {
+                       fsrprintf(_("open(%s) failed: %s\n"),
+                                 leftofffile, strerror(errno));
+               } else {
                        ret = sprintf(buf, "%s %d %llu\n", fs->dev,
                                fs->npass, (unsigned long long)leftoffino);
                        if (write(fd, buf, ret) < strlen(buf))
@@ -611,11 +575,6 @@ fsrall_cleanup(int timeout)
                        close(fd);
                }
        }
-
-       if (timeout)
-               fsrprintf(_("%s startpass %d, endpass %d, time %d seconds\n"),
-                       progname, startpass, fs->npass,
-                       time(0) - endtime + howlong);
 }
 
 /*
@@ -624,16 +583,14 @@ fsrall_cleanup(int timeout)
 static int
 fsrfs(char *mntdir, xfs_ino_t startino, int targetrange)
 {
-
-       int     fsfd, fd;
+       struct xfs_fd   fsxfd = XFS_FD_INIT_EMPTY;
+       int     fd;
        int     count = 0;
        int     ret;
-       __s32   buflenout;
-       xfs_bstat_t buf[GRABSZ];
        char    fname[64];
        char    *tname;
        jdm_fshandle_t  *fshandlep;
-       xfs_ino_t       lastino = startino;
+       struct xfs_bulkstat_req *breq;
 
        fsrprintf(_("%s start inode=%llu\n"), mntdir,
                (unsigned long long)startino);
@@ -645,24 +602,32 @@ fsrfs(char *mntdir, xfs_ino_t startino, int targetrange)
                return -1;
        }
 
-       if ((fsfd = open(mntdir, O_RDONLY)) < 0) {
-               fsrprintf(_("unable to open: %s: %s\n"),
-                         mntdir, strerror( errno ));
+       ret = xfd_open(&fsxfd, mntdir, O_RDONLY);
+       if (ret) {
+               fsrprintf(_("unable to open XFS file: %s: %s\n"),
+                         mntdir, strerror(ret));
+               free(fshandlep);
                return -1;
        }
+       memcpy(&fsgeom, &fsxfd.fsgeom, sizeof(fsgeom));
 
-       if (xfs_getgeom(fsfd, &fsgeom) < 0 ) {
-               fsrprintf(_("Skipping %s: could not get XFS geometry\n"),
+       tmp_init(mntdir);
+
+       breq = xfrog_bulkstat_alloc_req(GRABSZ, startino);
+       if (!breq) {
+               fsrprintf(_("Skipping %s: not enough memory\n"),
                          mntdir);
+               xfd_close(&fsxfd);
+               free(fshandlep);
                return -1;
        }
 
-       tmp_init(mntdir);
-
-       while ((ret = xfs_bulkstat(fsfd,
-                               &lastino, GRABSZ, &buf[0], &buflenout) == 0)) {
-               xfs_bstat_t *p;
-               xfs_bstat_t *endp;
+       while ((ret = xfrog_bulkstat(&fsxfd, breq) == 0)) {
+               struct xfs_bstat        bs1;
+               struct xfs_bulkstat     *buf = breq->bulkstat;
+               struct xfs_bulkstat     *p;
+               struct xfs_bulkstat     *endp;
+               uint32_t                buflenout = breq->hdr.ocount;
 
                if (buflenout == 0)
                        goto out0;
@@ -670,7 +635,7 @@ fsrfs(char *mntdir, xfs_ino_t startino, int targetrange)
                /* Each loop through, defrag targetrange percent of the files */
                count = (buflenout * targetrange) / 100;
 
-               qsort((char *)buf, buflenout, sizeof(struct xfs_bstat), cmp);
+               qsort((char *)buf, buflenout, sizeof(struct xfs_bulkstat), cmp);
 
                for (p = buf, endp = (buf + buflenout); p < endp ; p++) {
                        /* Do some obvious checks now */
@@ -678,7 +643,15 @@ fsrfs(char *mntdir, xfs_ino_t startino, int targetrange)
                             (p->bs_extents < 2))
                                continue;
 
-                       if ((fd = jdm_open(fshandlep, p, O_RDWR)) < 0) {
+                       ret = xfrog_bulkstat_v5_to_v1(&fsxfd, &bs1, p);
+                       if (ret) {
+                               fsrprintf(_("bstat conversion error: %s\n"),
+                                               strerror(ret));
+                               continue;
+                       }
+
+                       fd = jdm_open(fshandlep, &bs1, O_RDWR | O_DIRECT);
+                       if (fd < 0) {
                                /* This probably means the file was
                                 * removed while in progress of handling
                                 * it.  Just quietly ignore this file.
@@ -695,7 +668,7 @@ fsrfs(char *mntdir, xfs_ino_t startino, int targetrange)
                        /* Get a tmp file name */
                        tname = tmp_next(mntdir);
 
-                       ret = fsrfile_common(fname, tname, mntdir, fd, p);
+                       ret = fsrfile_common(fname, tname, mntdir, fd, &bs1);
 
                        leftoffino = p->bs_ino;
 
@@ -706,18 +679,21 @@ fsrfs(char *mntdir, xfs_ino_t startino, int targetrange)
                                        break;
                        }
                }
-               if (endtime && endtime < time(0)) {
+               if (endtime && endtime < time(NULL)) {
+                       free(breq);
                        tmp_close(mntdir);
-                       close(fsfd);
+                       xfd_close(&fsxfd);
                        fsrall_cleanup(1);
                        exit(1);
                }
        }
-       if (ret < 0)
-               fsrprintf(_("%s: xfs_bulkstat: %s\n"), progname, strerror(errno));
+       if (ret)
+               fsrprintf(_("%s: bulkstat: %s\n"), progname, strerror(ret));
 out0:
+       free(breq);
        tmp_close(mntdir);
-       close(fsfd);
+       xfd_close(&fsxfd);
+       free(fshandlep);
        return 0;
 }
 
@@ -727,8 +703,8 @@ out0:
 int
 cmp(const void *s1, const void *s2)
 {
-       return( ((xfs_bstat_t *)s2)->bs_extents -
-               ((xfs_bstat_t *)s1)->bs_extents);
+       return( ((struct xfs_bstat *)s2)->bs_extents -
+               ((struct xfs_bstat *)s1)->bs_extents);
 
 }
 
@@ -749,62 +725,69 @@ fsrdir(char *dirname)
  * an open on the file and passes this all to fsrfile_common.
  */
 static int
-fsrfile(char *fname, xfs_ino_t ino)
+fsrfile(
+       char                    *fname,
+       xfs_ino_t               ino)
 {
-       xfs_bstat_t     statbuf;
-       jdm_fshandle_t  *fshandlep;
-       int     fd, fsfd;
-       int     error = 0;
-       char    *tname;
+       struct xfs_fd           fsxfd = XFS_FD_INIT_EMPTY;
+       struct xfs_bulkstat     bulkstat;
+       struct xfs_bstat        statbuf;
+       jdm_fshandle_t          *fshandlep;
+       int                     fd = -1;
+       int                     error = -1;
+       char                    *tname;
 
        fshandlep = jdm_getfshandle(getparent (fname) );
-       if (! fshandlep) {
+       if (!fshandlep) {
                fsrprintf(_("unable to construct sys handle for %s: %s\n"),
                        fname, strerror(errno));
-               return -1;
+               goto out;
        }
 
        /*
         * Need to open something on the same filesystem as the
         * file.  Open the parent.
         */
-       fsfd = open(getparent(fname), O_RDONLY);
-       if (fsfd < 0) {
-               fsrprintf(_("unable to open sys handle for %s: %s\n"),
-                       fname, strerror(errno));
-               return -1;
+       error = xfd_open(&fsxfd, getparent(fname), O_RDONLY);
+       if (error) {
+               fsrprintf(_("unable to open sys handle for XFS file %s: %s\n"),
+                       fname, strerror(error));
+               goto out;
        }
 
-       if ((xfs_bulkstat_single(fsfd, &ino, &statbuf)) < 0) {
+       error = xfrog_bulkstat_single(&fsxfd, ino, 0, &bulkstat);
+       if (error) {
                fsrprintf(_("unable to get bstat on %s: %s\n"),
-                       fname, strerror(errno));
-               close(fsfd);
-               return -1;
+                       fname, strerror(error));
+               goto out;
+       }
+       error = xfrog_bulkstat_v5_to_v1(&fsxfd, &statbuf, &bulkstat);
+       if (error) {
+               fsrprintf(_("bstat conversion error on %s: %s\n"),
+                       fname, strerror(error));
+               goto out;
        }
 
-       fd = jdm_open( fshandlep, &statbuf, O_RDWR);
+       fd = jdm_open(fshandlep, &statbuf, O_RDWR|O_DIRECT);
        if (fd < 0) {
                fsrprintf(_("unable to open handle %s: %s\n"),
                        fname, strerror(errno));
-               close(fsfd);
-               return -1;
+               goto out;
        }
 
-       /* Get the fs geometry */
-       if (xfs_getgeom(fsfd, &fsgeom) < 0 ) {
-               fsrprintf(_("Unable to get geom on fs for: %s\n"), fname);
-               close(fsfd);
-               return -1;
-       }
-
-       close(fsfd);
+       /* Stash the fs geometry for general use. */
+       memcpy(&fsgeom, &fsxfd.fsgeom, sizeof(fsgeom));
 
        tname = gettmpname(fname);
 
        if (tname)
                error = fsrfile_common(fname, tname, NULL, fd, &statbuf);
 
-       close(fd);
+out:
+       xfd_close(&fsxfd);
+       if (fd >= 0)
+               close(fd);
+       free(fshandlep);
 
        return error;
 }
@@ -830,10 +813,10 @@ fsrfile_common(
        char            *tname,
        char            *fsname,
        int             fd,
-       xfs_bstat_t     *statp)
+       struct xfs_bstat *statp)
 {
        int             error;
-       struct statvfs64 vfss;
+       struct statvfs  vfss;
        struct fsxattr  fsx;
        unsigned long   bsize;
 
@@ -885,7 +868,7 @@ fsrfile_common(
         * Note that xfs_bstat.bs_blksize returns the filesystem blocksize,
         * not the optimal I/O size as struct stat.
         */
-       if (statvfs64(fsname ? fsname : fname, &vfss) < 0) {
+       if (statvfs(fsname ? fsname : fname, &vfss) < 0) {
                fsrprintf(_("unable to get fs stat on %s: %s\n"),
                        fname, strerror(errno));
                return -1;
@@ -899,22 +882,22 @@ fsrfile_common(
                return 1;
        }
 
-       if ((ioctl(fd, XFS_IOC_FSGETXATTR, &fsx)) < 0) {
+       if ((ioctl(fd, FS_IOC_FSGETXATTR, &fsx)) < 0) {
                fsrprintf(_("failed to get inode attrs: %s\n"), fname);
                return(-1);
        }
-       if (fsx.fsx_xflags & (XFS_XFLAG_IMMUTABLE|XFS_XFLAG_APPEND)) {
+       if (fsx.fsx_xflags & (FS_XFLAG_IMMUTABLE|FS_XFLAG_APPEND)) {
                if (vflag)
                        fsrprintf(_("%s: immutable/append, ignoring\n"), fname);
                return(0);
        }
-       if (fsx.fsx_xflags & XFS_XFLAG_NODEFRAG) {
+       if (fsx.fsx_xflags & FS_XFLAG_NODEFRAG) {
                if (vflag)
                        fsrprintf(_("%s: marked as don't defrag, ignoring\n"),
                            fname);
                return(0);
        }
-       if (fsx.fsx_xflags & XFS_XFLAG_REALTIME) {
+       if (fsx.fsx_xflags & FS_XFLAG_REALTIME) {
                if (xfs_getrt(fd, &vfss) < 0) {
                        fsrprintf(_("cannot get realtime geometry for: %s\n"),
                                fname);
@@ -946,20 +929,214 @@ fsrfile_common(
        return -1; /* no error */
 }
 
+/*
+ * Attempt to set the attr fork up correctly. This is simple for attr1
+ * filesystems as they have a fixed inode fork offset. In that case
+ * just create an attribute and that's all we need to do.
+ *
+ * For attr2 filesystems, see if we have the actual fork offset in
+ * the bstat structure. If so, just create additional attributes on
+ * the temporary inode until the offset matches.
+ *
+ * If it doesn't exist, we can only do best effort. Add an attribute at a time
+ * to move the inode fork around, but take into account that the attribute
+ * might be too small to move the fork every time we add one.  This should
+ * hopefully put the fork offset in the right place. It's not a big deal if we
+ * don't get it right - the kernel will reject it when we try to swap extents.
+ */
+static int
+fsr_setup_attr_fork(
+       int             fd,
+       int             tfd,
+       struct xfs_bstat *bstatp)
+{
+#ifdef HAVE_FSETXATTR
+       struct xfs_fd   txfd = XFS_FD_INIT(tfd);
+       struct stat     tstatbuf;
+       int             i;
+       int             diff = 0;
+       int             last_forkoff = 0;
+       int             no_change_cnt = 0;
+       int             ret;
+
+       if (!(bstatp->bs_xflags & FS_XFLAG_HASATTR))
+               return 0;
+
+       /*
+        * use the old method if we have attr1 or the kernel does not yet
+        * support passing the fork offset in the bulkstat data.
+        */
+       if (!(fsgeom.flags & XFS_FSOP_GEOM_FLAGS_ATTR2) ||
+           bstatp->bs_forkoff == 0) {
+               /* attr1 */
+               ret = fsetxattr(txfd.fd, "user.X", "X", 1, XATTR_CREATE);
+               if (ret) {
+                       fsrprintf(_("could not set ATTR\n"));
+                       return -1;
+               }
+               goto out;
+       }
+
+       /* attr2 w/ fork offsets */
+
+       if (fstat(txfd.fd, &tstatbuf) < 0) {
+               fsrprintf(_("unable to stat temp file: %s\n"),
+                                       strerror(errno));
+               return -1;
+       }
+
+       i = 0;
+       do {
+               struct xfs_bulkstat     tbstat;
+               char            name[64];
+               int             ret;
+
+               /*
+                * bulkstat the temp inode to see what the forkoff is.  Use
+                * this to compare against the target and determine what we
+                * need to do.
+                */
+               ret = xfrog_bulkstat_single(&txfd, tstatbuf.st_ino, 0, &tbstat);
+               if (ret) {
+                       fsrprintf(_("unable to get bstat on temp file: %s\n"),
+                                               strerror(ret));
+                       return -1;
+               }
+               if (dflag)
+                       fsrprintf(_("orig forkoff %d, temp forkoff %d\n"),
+                                       bstatp->bs_forkoff, tbstat.bs_forkoff);
+               diff = tbstat.bs_forkoff - bstatp->bs_forkoff;
+
+               /* if they are equal, we are done */
+               if (!diff)
+                       goto out;
+
+               snprintf(name, sizeof(name), "user.%d", i);
+
+               /*
+                * If there is no attribute, then we need to create one to get
+                * an attribute fork at the default location.
+                */
+               if (!tbstat.bs_forkoff) {
+                       ASSERT(i == 0);
+                       ret = fsetxattr(txfd.fd, name, "XX", 2, XATTR_CREATE);
+                       if (ret) {
+                               fsrprintf(_("could not set ATTR\n"));
+                               return -1;
+                       }
+                       continue;
+               } else if (i == 0) {
+                       /*
+                        * First pass, and temp file already has an inline
+                        * xattr, probably due to selinux.
+                        *
+                        * It's *possible* that the temp file attr area
+                        * is larger than the target file's:
+                        *
+                        *  Target               Temp
+                        * +-------+ 0          +-------+ 0
+                        * |       |            |       |
+                        * |       |            | Data  |
+                        * | Data  |            |       |
+                        * |       |            v-------v forkoff
+                        * |       |            |       |
+                        * v-------v forkoff    | Attr  | local
+                        * | Attr  |            |       |
+                        * +-------+            +-------+
+                        */
+
+                       /*
+                        * If target attr area is less than the temp's
+                        * (diff < 0) write a big attr to the temp file to knock
+                        * the attr out of local format.
+                        * (This should actually *increase* the temp file's
+                        * forkoffset when the attr moves out of the inode)
+                        */
+                       if (diff < 0) {
+                               char val[2048];
+                               memset(val, 'X', 2048);
+                               if (fsetxattr(txfd.fd, name, val, 2048, 0)) {
+                                       fsrprintf(_("big ATTR set failed\n"));
+                                       return -1;
+                               }
+                               /* Go back & see where we're at now */
+                               continue;
+                       }
+               }
+
+               /*
+                * make a progress check so we don't get stuck trying to extend
+                * a large btree form attribute fork.
+                */
+               if (last_forkoff == tbstat.bs_forkoff) {
+                       if (no_change_cnt++ > 10)
+                               break;
+               } else /* progress! */
+                       no_change_cnt = 0;
+               last_forkoff = tbstat.bs_forkoff;
+
+               /* work out which way to grow the fork */
+               if (abs(diff) > fsgeom.inodesize - sizeof(struct xfs_dinode)) {
+                       fsrprintf(_("forkoff diff %d too large!\n"), diff);
+                       return -1;
+               }
+
+               /*
+                * if the temp inode fork offset is still smaller then we have
+                * to grow the data fork
+                */
+               if (diff < 0) {
+                       /*
+                        * create some temporary extents in the inode to move
+                        * the fork in the direction we need. This can be done
+                        * by preallocating some single block extents at
+                        * non-contiguous offsets.
+                        */
+                       /* XXX: unimplemented! */
+                       if (dflag)
+                               printf(_("data fork growth unimplemented\n"));
+                       goto out;
+               }
+
+               /* we need to grow the attr fork, so create another attr */
+               ret = fsetxattr(txfd.fd, name, "XX", 2, XATTR_CREATE);
+               if (ret) {
+                       fsrprintf(_("could not set ATTR\n"));
+                       return -1;
+               }
+
+       } while (++i < 100); /* don't go forever */
+
+out:
+       if (dflag)
+               fsrprintf(_("set temp attr\n"));
+       /* We failed to resolve the fork difference */
+       if (dflag && diff)
+               fsrprintf(_("failed to match fork offset\n"));;
+
+#endif /* HAVE_FSETXATTR */
+       return 0;
+}
 
 /*
  * Do the defragmentation of a single file.
  * We already are pretty sure we can and want to
  * defragment the file.  Create the tmp file, copy
  * the data (maintaining holes) and call the kernel
- * extent swap routinte.
+ * extent swap routine.
+ *
+ * Return values:
+ * -1: Some error was encountered
+ *  0: Successfully defragmented the file
+ *  1: No change / No Error
  */
 static int
 packfile(char *fname, char *tname, int fd,
-        xfs_bstat_t *statp, struct fsxattr *fsxp)
+        struct xfs_bstat *statp, struct fsxattr *fsxp)
 {
-       int             tfd;
+       int             tfd = -1;
        int             srval;
+       int             retval = -1;    /* Failure is the default */
        int             nextents, extent, cur_nextents, new_nextents;
        unsigned        blksz_dio;
        unsigned        dio_min;
@@ -967,7 +1144,7 @@ packfile(char *fname, char *tname, int fd,
        static xfs_swapext_t   sx;
        struct xfs_flock64  space;
        off64_t         cnt, pos;
-       void            *fbuf;
+       void            *fbuf = NULL;
        int             ct, wc, wc_b4;
        char            ffname[SMBUFSZ];
        int             ffd = -1;
@@ -983,7 +1160,8 @@ packfile(char *fname, char *tname, int fd,
        if (cur_nextents == 1 || cur_nextents <= nextents) {
                if (vflag)
                        fsrprintf(_("%s already fully defragmented.\n"), fname);
-               return 1; /* indicates no change/no error */
+               retval = 1; /* indicates no change/no error */
+               goto out;
        }
 
        if (dflag)
@@ -995,35 +1173,28 @@ packfile(char *fname, char *tname, int fd,
                if (vflag)
                        fsrprintf(_("could not open tmp file: %s: %s\n"),
                                   tname, strerror(errno));
-               return -1;
+               goto out;
        }
        unlink(tname);
 
        /* Setup extended attributes */
-       if (statp->bs_xflags & XFS_XFLAG_HASATTR) {
-               if (fsetxattr(tfd, "user.X", "X", 1, XATTR_CREATE) != 0) {
-                       fsrprintf(_("could not set ATTR on tmp: %s:\n"), tname);
-                       close(tfd);
-                       return -1;
-               }
-               if (dflag)
-                       fsrprintf(_("%s set temp attr\n"), tname);
+       if (fsr_setup_attr_fork(fd, tfd, statp) != 0) {
+               fsrprintf(_("failed to set ATTR fork on tmp: %s:\n"), tname);
+               goto out;
        }
 
        /* Setup extended inode flags, project identifier, etc */
        if (fsxp->fsx_xflags || fsxp->fsx_projid) {
-               if (ioctl(tfd, XFS_IOC_FSSETXATTR, fsxp) < 0) {
+               if (ioctl(tfd, FS_IOC_FSSETXATTR, fsxp) < 0) {
                        fsrprintf(_("could not set inode attrs on tmp: %s\n"),
                                tname);
-                       close(tfd);
-                       return -1;
+                       goto out;
                }
        }
 
        if ((ioctl(tfd, XFS_IOC_DIOINFO, &dio)) < 0 ) {
                fsrprintf(_("could not get DirectIO info on tmp: %s\n"), tname);
-               close(tfd);
-               return -1;
+               goto out;
        }
 
        dio_min = dio.d_miniosz;
@@ -1045,8 +1216,7 @@ packfile(char *fname, char *tname, int fd,
 
        if (!(fbuf = (char *)memalign(dio.d_mem, blksz_dio))) {
                fsrprintf(_("could not allocate buf: %s\n"), tname);
-               close(tfd);
-               return -1;
+               goto out;
        }
 
        if (nfrags) {
@@ -1057,9 +1227,7 @@ packfile(char *fname, char *tname, int fd,
                if ((ffd = open(ffname, openopts, 0666)) < 0) {
                        fsrprintf(_("could not open fragfile: %s : %s\n"),
                                   ffname, strerror(errno));
-                       close(tfd);
-                       free(fbuf);
-                       return -1;
+                       goto out;
                }
                unlink(ffname);
        }
@@ -1075,7 +1243,11 @@ packfile(char *fname, char *tname, int fd,
                                fsrprintf(_("could not trunc tmp %s\n"),
                                           tname);
                        }
-                       lseek64(tfd, outmap[extent].bmv_length, SEEK_CUR);
+                       if (lseek(tfd, outmap[extent].bmv_length, SEEK_CUR) < 0) {
+                               fsrprintf(_("could not lseek in tmpfile: %s : %s\n"),
+                                  tname, strerror(errno));
+                               goto out;
+                       }
                        continue;
                } else if (outmap[extent].bmv_length == 0) {
                        /* to catch holes at the beginning of the file */
@@ -1089,19 +1261,19 @@ packfile(char *fname, char *tname, int fd,
                        if (ioctl(tfd, XFS_IOC_RESVSP64, &space) < 0) {
                                fsrprintf(_("could not pre-allocate tmp space:"
                                        " %s\n"), tname);
-                               close(tfd);
-                               free(fbuf);
-                               return -1;
+                               goto out;
+                       }
+                       if (lseek(tfd, outmap[extent].bmv_length, SEEK_CUR) < 0) {
+                               fsrprintf(_("could not lseek in tmpfile: %s : %s\n"),
+                                  tname, strerror(errno));
+                               goto out;
                        }
-                       lseek64(tfd, outmap[extent].bmv_length, SEEK_CUR);
                }
        } /* end of space allocation loop */
 
-       if (lseek64(tfd, 0, SEEK_SET)) {
+       if (lseek(tfd, 0, SEEK_SET)) {
                fsrprintf(_("Couldn't rewind on temporary file\n"));
-               close(tfd);
-               free(fbuf);
-               return -1;
+               goto out;
        }
 
        /* Check if the temporary file has fewer extents */
@@ -1111,17 +1283,24 @@ packfile(char *fname, char *tname, int fd,
        if (cur_nextents <= new_nextents) {
                if (vflag)
                        fsrprintf(_("No improvement will be made (skipping): %s\n"), fname);
-               free(fbuf);
-               close(tfd);
-               return 1; /* no change/no error */
+               retval = 1; /* no change/no error */
+               goto out;
        }
 
        /* Loop through block map copying the file. */
        for (extent = 0; extent < nextents; extent++) {
                pos = outmap[extent].bmv_offset;
                if (outmap[extent].bmv_block == -1) {
-                       lseek64(tfd, outmap[extent].bmv_length, SEEK_CUR);
-                       lseek64(fd, outmap[extent].bmv_length, SEEK_CUR);
+                       if (lseek(tfd, outmap[extent].bmv_length, SEEK_CUR) < 0) {
+                               fsrprintf(_("could not lseek in tmpfile: %s : %s\n"),
+                                  tname, strerror(errno));
+                               goto out;
+                       }
+                       if (lseek(fd, outmap[extent].bmv_length, SEEK_CUR) < 0) {
+                               fsrprintf(_("could not lseek in file: %s : %s\n"),
+                                  fname, strerror(errno));
+                               goto out;
+                       }
                        continue;
                } else if (outmap[extent].bmv_length == 0) {
                        /* to catch holes at the beginning of the file */
@@ -1184,9 +1363,7 @@ packfile(char *fname, char *tname, int fd,
                                                        tname);
                                        }
                                }
-                               free(fbuf);
-                               close(tfd);
-                               return -1;
+                               goto out;
                        }
                        if (nfrags) {
                                /* Do a matching write to the tmp file */
@@ -1199,11 +1376,16 @@ packfile(char *fname, char *tname, int fd,
                        }
                }
        }
-       ftruncate64(tfd, statp->bs_size);
-       if (ffd > 0) close(ffd);
-       fsync(tfd);
-
-       free(fbuf);
+       if (ftruncate(tfd, statp->bs_size) < 0) {
+               fsrprintf(_("could not truncate tmpfile: %s : %s\n"),
+                               fname, strerror(errno));
+               goto out;
+       }
+       if (fsync(tfd) < 0) {
+               fsrprintf(_("could not fsync tmpfile: %s : %s\n"),
+                               fname, strerror(errno));
+               goto out;
+       }
 
        sx.sx_stat     = *statp; /* struct copy */
        sx.sx_version  = XFS_SX_VERSION;
@@ -1217,8 +1399,7 @@ packfile(char *fname, char *tname, int fd,
                 if (vflag)
                         fsrprintf(_("failed to fchown tmpfile %s: %s\n"),
                                    tname, strerror(errno));
-               close(tfd);
-                return -1;
+               goto out;
         }
 
        /* Swap the extents */
@@ -1240,8 +1421,7 @@ packfile(char *fname, char *tname, int fd,
                        fsrprintf(_("XFS_IOC_SWAPEXT failed: %s: %s\n"),
                                  fname, strerror(errno));
                }
-               close(tfd);
-               return -1;
+               goto out;
        }
 
        /* Report progress */
@@ -1250,8 +1430,15 @@ packfile(char *fname, char *tname, int fd,
                          cur_nextents, new_nextents,
                          (new_nextents <= nextents ? "DONE" : "    " ),
                          fname);
-       close(tfd);
-       return 0;
+       retval = 0;
+
+out:
+       free(fbuf);
+       if (tfd != -1)
+               close(tfd);
+       if (ffd != -1)
+               close(ffd);
+       return retval;
 }
 
 char *
@@ -1263,7 +1450,8 @@ gettmpname(char *fname)
 
        sprintf(sbuf, "/.fsr%d", getpid());
 
-       strcpy(buf, fname);
+       strncpy(buf, fname, PATH_MAX);
+       buf[PATH_MAX] = '\0';
        ptr = strrchr(buf, '/');
        if (ptr) {
                *ptr = '\0';
@@ -1287,7 +1475,8 @@ getparent(char *fname)
        static char     buf[PATH_MAX+1];
        char            *ptr;
 
-       strcpy(buf, fname);
+       strncpy(buf, fname, PATH_MAX);
+       buf[PATH_MAX] = '\0';
        ptr = strrchr(buf, '/');
        if (ptr) {
                if (ptr == &buf[0])
@@ -1310,7 +1499,7 @@ getparent(char *fname)
 #define MAPSIZE        128
 #define        OUTMAP_SIZE_INCREMENT   MAPSIZE
 
-int    read_fd_bmap(int fd, xfs_bstat_t *sin, int *cur_nextents)
+int    read_fd_bmap(int fd, struct xfs_bstat *sin, int *cur_nextents)
 {
        int             i, cnt;
        struct getbmap  map[MAPSIZE];
@@ -1398,7 +1587,7 @@ int       read_fd_bmap(int fd, xfs_bstat_t *sin, int *cur_nextents)
 /*
  * Read the block map and return the number of extents.
  */
-int
+static int
 getnextents(int fd)
 {
        int             nextents;
@@ -1424,23 +1613,11 @@ getnextents(int fd)
        return(nextents);
 }
 
-/*
- * Get the fs geometry
- */
-int
-xfs_getgeom(int fd, xfs_fsop_geom_v1_t * fsgeom)
-{
-       if (xfs_fsgeometry(fd, fsgeom) < 0) {
-               return -1;
-       }
-       return 0;
-}
-
 /*
  * Get xfs realtime space information
  */
 int
-xfs_getrt(int fd, struct statvfs64 *sfbp)
+xfs_getrt(int fd, struct statvfs *sfbp)
 {
        unsigned long   bsize;
        unsigned long   factor;
@@ -1478,35 +1655,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
@@ -1541,7 +1689,7 @@ tmp_init(char *mnt)
        }
        for (i=0; i < fsgeom.agcount; i++) {
                sprintf(buf, "%s/.fsr/ag%d", mnt, i);
-               if (mkdir(buf, 0777) < 0) {
+               if (mkdir(buf, 0700) < 0) {
                        if (errno == EEXIST) {
                                if (dflag)
                                        fsrprintf(