[PATCH] xfs_io: fix exitcode handling (was Re: generic/399 and xfs_io pwrite command)

Dave Chinner
2017-12-06T00:26:42Z

On Wed, Dec 06, 2017 at 08:18:50AM +1100, Dave Chinner wrote:
> On Tue, Dec 05, 2017 at 04:23:43PM +0200, Ari Sundholm wrote:
> > On 12/05/2017 12:28 AM, Dave Chinner wrote:
> > >On Thu, Nov 30, 2017 at 04:21:47PM +0200, Ari Sundholm wrote:
> > >>Hi!
> > >>
> > >>While debugging an issue, we found out that generic/399 seems to
> > >>rely on a behavior that is specific to ext4 in the following section
> > >>of code:
> > >>----------------8<--------snip--------8<------------------------------
> > >>#
> > >># Write files of 1 MB of all the same byte until we hit ENOSPC.
> > >>Note that we
> > >># must not create sparse files, since the contents of sparse files are not
> > >># stored on-disk. Also, we create multiple files rather than one big file
> > >># because we want to test for reuse of per-file keys.
> > >>#
> > >>total_file_size=0
> > >>i=1
> > >>while true; do
> > >> file=$SCRATCH_MNT/encrypted_dir/file$i
> > >> if ! $XFS_IO_PROG -f $file -c 'pwrite 0 1M' &> $tmp.out; then
> > >> if ! grep -q 'No space left on device' $tmp.out; then
> > >> echo "FAIL: unexpected pwrite failure"
> > >> cat $tmp.out
> > >> elif [ -e $file ]; then
> > >> total_file_size=$((total_file_size + $(stat -c %s $file)))
> > >> fi
> > >> break
> > >> fi
> > >> total_file_size=$((total_file_size + $(stat -c %s $file)))
> > >> i=$((i + 1))
> > >> if [ $i -gt $fs_size_in_mb ]; then
> > >> echo "FAIL: filesystem never filled up!"
> > >> break
> > >> fi
> > >>done
> > >>----------------8<--------snip--------8<------------------------------
> > >>
> > >>What happens with ext4 is that the xfs_io command gives a nonzero
> > >>exit value not when the pwrite command fails with ENOSPC but during
> > >>the *next* iteration when opening the file fails with ENOSPC. Turns
> > >>out the pwrite command failing does not cause xfs_io to give a
> > >>nonzero exit value.
> > >
> > >That implies ext4 is returning zero bytes written to the pwrite()
> > >call rather than ENOSPC. i.e.:
> > >
> > > bytes = do_pwrite(file->fd, off, cnt, buffersize,
> > > pwritev2_flags);
> > > if (bytes == 0)
> > > break;
> > > if (bytes < 0) {
> > > perror("pwrite");
> > > return -1;
> > > }
> > >
> > >So if it's exiting with no error, then we can't have got an error
> > >from ext4 at ENOSPC. If that's the case, it probably should be
> > >considered an ext4 bug, not an issue with xfs_io...
> > >
> >
> > No, according to what we've observed, that is not what happens. The
> > pwrite() call does fail and errno is ENOSPC after the call. The
> > immediate problem is that xfs_io does not reflect this failure in
> > its exit value and thus the check in generic/399 does not work in
> > this case. Only when open() fails during the next iteration does
> > xfs_io give a nonzero exit value and cause the check in the test
> > case to allow the test case to end successfully.
>
> Ah, io/pwrite.c fails to set exitcode on failure iappropriately
> before returning. Looks like there is a bunch of xfs_io commands
> that fail to do this properly.
>
> > What is specific to ext4 here is, as stated in my original message,
> > that open() fails.
>
> Because there are no more inodes to allocate (i.e. inode table is
> full) and so attempts to create more fail with ENOSPC. The xfs_io
> open command set exitcode appropriately, and that's why it finally
> triggers a test abort.
>
> Looks like xfs_io does need fixing to set exitcode appropriately on
> all failures...

Try the patch below.

Cheers,

Dave.
--
Dave Chinner
david@fromorbit.com

xfs_io: set exitcode on failure appropriately

From: Dave Chinner <dchinner@redhat.com>

Many operations don't set the exitcode when they fail, resulting
in xfs_io exiting with a zero (no failure) exit code despite the
command failing and returning an error. Fix this.

Signed-Off-By: Dave Chinner <dchinner@redhat.com>
---
io/attr.c | 18 ++++++++++++++----
io/copy_file_range.c | 3 +++
io/cowextsize.c | 5 +++++
io/encrypt.c | 3 ++-
io/fadvise.c | 2 ++
io/fiemap.c | 5 ++---
io/file.c | 1 +
io/fsmap.c | 6 ++----
io/fsync.c | 2 ++
io/getrusage.c | 1 +
io/imap.c | 4 +++-
io/inject.c | 1 +
io/link.c | 1 +
io/madvise.c | 2 ++
io/mincore.c | 2 ++
io/mmap.c | 25 ++++++++++++++++++++-----
io/open.c | 32 +++++++++++++++++++++++++++-----
io/parent.c | 1 +
io/pread.c | 3 +++
io/prealloc.c | 22 ++++++++++++++++++++++
io/pwrite.c | 3 +++
io/readdir.c | 6 ++++--
io/reflink.c | 15 +++++++++++++--
io/resblks.c | 2 ++
io/seek.c | 6 +++++-
io/sendfile.c | 3 +++
io/shutdown.c | 2 ++
io/stat.c | 7 +++++++
io/sync_file_range.c | 2 ++
io/truncate.c | 2 ++
io/utimes.c | 2 ++
31 files changed, 161 insertions(+), 28 deletions(-)

diff --git a/io/attr.c b/io/attr.c
index 728560e1d1fb..86527b05461b 100644
--- a/io/attr.c
+++ b/io/attr.c
@@ -175,10 +175,11 @@ lsattr_callback(
if ((fd = open(path, O_RDONLY)) == -1)
fprintf(stderr, _("%s: cannot open %s: %s\n"),
progname, path, strerror(errno));
- else if ((xfsctl(path, fd, FS_IOC_FSGETXATTR, &fsx)) < 0)
+ else if ((xfsctl(path, fd, FS_IOC_FSGETXATTR, &fsx)) < 0) {
fprintf(stderr, _("%s: cannot get flags on %s: %s\n"),
progname, path, strerror(errno));
- else
+ exitcode = 1;
+ } else
printxattr(fsx.fsx_xflags, 0, 1, path, 0, 1);

if (fd != -1)
@@ -225,6 +226,7 @@ lsattr_f(
} else if ((xfsctl(name, file->fd, FS_IOC_FSGETXATTR, &fsx)) < 0) {
fprintf(stderr, _("%s: cannot get flags on %s: %s\n"),
progname, name, strerror(errno));
+ exitcode = 1;
} else {
printxattr(fsx.fsx_xflags, vflag, !aflag, name, vflag, !aflag);
if (aflag) {
@@ -257,9 +259,11 @@ chattr_callback(
} else {
attr.fsx_xflags |= orflags;
attr.fsx_xflags &= ~andflags;
- if (xfsctl(path, fd, FS_IOC_FSSETXATTR, &attr) < 0)
+ if (xfsctl(path, fd, FS_IOC_FSSETXATTR, &attr) < 0) {
fprintf(stderr, _("%s: cannot set flags on %s: %s\n"),
progname, path, strerror(errno));
+ exitcode = 1;
+ }
}

if (fd != -1)
@@ -295,6 +299,7 @@ chattr_f(
if (!p->flag) {
fprintf(stderr, _("%s: unknown flag\n"),
progname);
+ exitcode = 1;
return 0;
}
}
@@ -309,12 +314,14 @@ chattr_f(
if (!p->flag) {
fprintf(stderr, _("%s: unknown flag\n"),
progname);
+ exitcode = 1;
return 0;
}
}
} else {
fprintf(stderr, _("%s: bad chattr command, not +/-X\n"),
progname);
+ exitcode = 1;
return 0;
}
}
@@ -325,12 +332,15 @@ chattr_f(
} else if (xfsctl(name, file->fd, FS_IOC_FSGETXATTR, &attr) < 0) {
fprintf(stderr, _("%s: cannot get flags on %s: %s\n"),
progname, name, strerror(errno));
+ exitcode = 1;
} else {
attr.fsx_xflags |= orflags;
attr.fsx_xflags &= ~andflags;
- if (xfsctl(name, file->fd, FS_IOC_FSSETXATTR, &attr) < 0)
+ if (xfsctl(name, file->fd, FS_IOC_FSSETXATTR, &attr) < 0) {
fprintf(stderr, _("%s: cannot set flags on %s: %s\n"),
progname, name, strerror(errno));
+ exitcode = 1;
+ }
}
return 0;
}
diff --git a/io/copy_file_range.c b/io/copy_file_range.c
index d1dfc5a5e33a..9b737eff4c02 100644
--- a/io/copy_file_range.c
+++ b/io/copy_file_range.c
@@ -92,6 +92,7 @@ copy_range_f(int argc, char **argv)
int ret;
int fd;

+ exitcode = 1;
while ((opt = getopt(argc, argv, "s:d:l:")) != -1) {
switch (opt) {
case 's':
@@ -132,6 +133,8 @@ copy_range_f(int argc, char **argv)

ret = copy_file_range(fd, &src, &dst, len);
close(fd);
+ if (ret >= 0)
+ exitcode = 0;
return ret;
}

diff --git a/io/cowextsize.c b/io/cowextsize.c
index c4cd6de24da5..d5872449cb60 100644
--- a/io/cowextsize.c
+++ b/io/cowextsize.c
@@ -53,6 +53,7 @@ get_cowextsize(const char *path, int fd)
if ((xfsctl(path, fd, FS_IOC_FSGETXATTR, &fsx)) < 0) {
printf("%s: XFS_IOC_FSGETXATTR %s: %s\n",
progname, path, strerror(errno));
+ exitcode = 1;
return 0;
}
printf("[%u] %s\n", fsx.fsx_cowextsize, path);
@@ -67,11 +68,13 @@ set_cowextsize(const char *path, int fd, long extsz)

if (fstat64(fd, &stat) < 0) {
perror("fstat64");
+ exitcode = 1;
return 0;
}
if ((xfsctl(path, fd, FS_IOC_FSGETXATTR, &fsx)) < 0) {
printf("%s: XFS_IOC_FSGETXATTR %s: %s\n",
progname, path, strerror(errno));
+ exitcode = 1;
return 0;
}

@@ -86,6 +89,7 @@ set_cowextsize(const char *path, int fd, long extsz)
if ((xfsctl(path, fd, FS_IOC_FSSETXATTR, &fsx)) < 0) {
printf("%s: XFS_IOC_FSSETXATTR %s: %s\n",
progname, path, strerror(errno));
+ exitcode = 1;
return 0;
}

@@ -168,6 +172,7 @@ cowextsize_f(
if (cowextsize < 0) {
printf(_("non-numeric cowextsize argument -- %s\n"),
argv[optind]);
+ exitcode = 1;
return 0;
}
} else {
diff --git a/io/encrypt.c b/io/encrypt.c
index 26ab97ce614b..3351e0ff8666 100644
--- a/io/encrypt.c
+++ b/io/encrypt.c
@@ -192,6 +192,7 @@ set_encpolicy_f(int argc, char **argv)
struct fscrypt_policy policy;

/* Initialize the policy structure with default values */
+ exitcode = 1;
memset(&policy, 0, sizeof(policy));
policy.contents_encryption_mode = FS_ENCRYPTION_MODE_AES_256_XTS;
policy.filenames_encryption_mode = FS_ENCRYPTION_MODE_AES_256_CTS;
@@ -269,10 +270,10 @@ set_encpolicy_f(int argc, char **argv)
if (ioctl(file->fd, FS_IOC_SET_ENCRYPTION_POLICY, &policy) < 0) {
fprintf(stderr, "%s: failed to set encryption policy: %s\n",
file->name, strerror(errno));
- exitcode = 1;
return 0;
}

+ exitcode = 0;
return 0;
}

diff --git a/io/fadvise.c b/io/fadvise.c
index 46174f34680e..9cc91a5712e1 100644
--- a/io/fadvise.c
+++ b/io/fadvise.c
@@ -54,6 +54,7 @@ fadvise_f(
off64_t offset = 0, length = 0;
int c, range = 0, advise = POSIX_FADV_NORMAL;

+ exitcode = 1;
while ((c = getopt(argc, argv, "dnrsw")) != EOF) {
switch (c) {
case 'd': /* Don't need these pages */
@@ -107,6 +108,7 @@ fadvise_f(
perror("fadvise");
return 0;
}
+ exitcode = 0;
return 0;
}

diff --git a/io/fiemap.c b/io/fiemap.c
index bdcfacdb2811..d97f53ae8d79 100644
--- a/io/fiemap.c
+++ b/io/fiemap.c
@@ -238,6 +238,7 @@ fiemap_f(
__u64 last_logical = 0;
struct stat st;

+ exitcode = 1;
while ((c = getopt(argc, argv, "aln:v")) != EOF) {
switch (c) {
case 'a':
@@ -263,7 +264,6 @@ fiemap_f(
if (!fiemap) {
fprintf(stderr, _("%s: malloc of %d bytes failed.\n"),
progname, map_size);
- exitcode = 1;
return 0;
}

@@ -282,7 +282,6 @@ fiemap_f(
fprintf(stderr, "%s: ioctl(FS_IOC_FIEMAP) [\"%s\"]: "
"%s\n", progname, file->name, strerror(errno));
free(fiemap);
- exitcode = 1;
return 0;
}

@@ -332,7 +331,6 @@ fiemap_f(
fprintf(stderr, "%s: fstat failed: %s\n", progname,
strerror(errno));
free(fiemap);
- exitcode = 1;
return 0;
}

@@ -341,6 +339,7 @@ fiemap_f(
BTOBBT(last_logical), BTOBBT(st.st_size));

out:
+ exitcode = 0;
free(fiemap);
return 0;
}
diff --git a/io/file.c b/io/file.c
index 349b19cdc420..2afb42e60620 100644
--- a/io/file.c
+++ b/io/file.c
@@ -79,6 +79,7 @@ file_f(
i = atoi(argv[1]);
if (i < 0 || i >= filecount) {
printf(_("value %d is out of range (0-%d)\n"), i, filecount-1);
+ exitcode = 1;
} else {
file = &filetable[i];
filelist_f();
diff --git a/io/fsmap.c b/io/fsmap.c
index 448fb5356466..4e3ae7ca2bab 100644
--- a/io/fsmap.c
+++ b/io/fsmap.c
@@ -404,6 +404,7 @@ fsmap_f(
bool dumped_flags = false;
int dflag, lflag, rflag;

+ exitcode = 1;
init_cvtnum(&fsblocksize, &fssectsize);

dflag = lflag = rflag = 0;
@@ -466,7 +467,6 @@ fsmap_f(
fprintf(stderr,
_("%s: can't get geometry [\"%s\"]: %s\n"),
progname, file->name, strerror(errno));
- exitcode = 1;
return 0;
}
}
@@ -476,7 +476,6 @@ fsmap_f(
if (head == NULL) {
fprintf(stderr, _("%s: malloc of %zu bytes failed.\n"),
progname, fsmap_sizeof(map_size));
- exitcode = 1;
return 0;
}

@@ -509,7 +508,6 @@ fsmap_f(
progname, head->fmh_iflags, file->name,
strerror(errno));
free(head);
- exitcode = 1;
return 0;
}
if (head->fmh_entries > map_size + 2) {
@@ -548,7 +546,6 @@ fsmap_f(
progname, head->fmh_iflags, file->name,
strerror(errno));
free(head);
- exitcode = 1;
return 0;
}

@@ -571,6 +568,7 @@ fsmap_f(
if (dumped_flags)
dump_verbose_key();

+ exitcode = 0;
free(head);
return 0;
}
diff --git a/io/fsync.c b/io/fsync.c
index 9fe5e2f50c62..61061c401a04 100644
--- a/io/fsync.c
+++ b/io/fsync.c
@@ -31,6 +31,7 @@ fsync_f(
{
if (fsync(file->fd) < 0) {
perror("fsync");
+ exitcode = 1;
return 0;
}
return 0;
@@ -43,6 +44,7 @@ fdatasync_f(
{
if (fdatasync(file->fd) < 0) {
perror("fdatasync");
+ exitcode = 1;
return 0;
}
return 0;
diff --git a/io/getrusage.c b/io/getrusage.c
index cf1f2afd19a8..9fc51709a73e 100644
--- a/io/getrusage.c
+++ b/io/getrusage.c
@@ -62,6 +62,7 @@ getrusage_f(

if (getrusage(RUSAGE_SELF, &rusage) < 0) {
perror("getrusage");
+ exitcode = 1;
return 0;
}

diff --git a/io/imap.c b/io/imap.c
index f52238e0c450..410e1662b76c 100644
--- a/io/imap.c
+++ b/io/imap.c
@@ -39,8 +39,10 @@ imap_f(int argc, char **argv)
nent = atoi(argv[1]);

t = malloc(nent * sizeof(*t));
- if (!t)
+ if (!t) {
+ exitcode = 1;
return 0;
+ }

bulkreq.lastip = &last;
bulkreq.icount = nent;
diff --git a/io/inject.c b/io/inject.c
index 964ebfe13bd6..db0795023a64 100644
--- a/io/inject.c
+++ b/io/inject.c
@@ -156,6 +156,7 @@ inject_f(
command = XFS_IOC_ERROR_CLEARALL;
if ((xfsctl(file->name, file->fd, command, &error)) < 0) {
perror("XFS_IOC_ERROR_INJECTION");
+ exitcode = 1;
continue;
}
}
diff --git a/io/link.c b/io/link.c
index 9b2e8a970942..55bb806024eb 100644
--- a/io/link.c
+++ b/io/link.c
@@ -47,6 +47,7 @@ flink_f(

if (linkat(file->fd, "", AT_FDCWD, argv[1], AT_EMPTY_PATH) < 0) {
perror("flink");
+ exitcode = 1;
return 0;
}
return 0;
diff --git a/io/madvise.c b/io/madvise.c
index 1d8b53cb516f..fbfe35cc1c13 100644
--- a/io/madvise.c
+++ b/io/madvise.c
@@ -57,6 +57,7 @@ madvise_f(
int advise = MADV_NORMAL, c;
size_t blocksize, sectsize;

+ exitcode = 1;
while ((c = getopt(argc, argv, "drsw")) != EOF) {
switch (c) {
case 'd': /* Don't need these pages */
@@ -111,6 +112,7 @@ madvise_f(
perror("madvise");
return 0;
}
+ exitcode = 0;
return 0;
}

diff --git a/io/mincore.c b/io/mincore.c
index 9e0d3a620319..09a165737705 100644
--- a/io/mincore.c
+++ b/io/mincore.c
@@ -37,6 +37,7 @@ mincore_f(
unsigned char *vec;
int i;

+ exitcode = 1;
if (argc == 1) {
offset = mapping->offset;
length = mapping->length;
@@ -106,6 +107,7 @@ mincore_f(
(unsigned long)(current - previous));

free(vec);
+ exitcode = 0;
return 0;
}

diff --git a/io/mmap.c b/io/mmap.c
index 7a8150e3d517..b0c1f764b8c4 100644
--- a/io/mmap.c
+++ b/io/mmap.c
@@ -121,6 +121,7 @@ mapset_f(
i = atoi(argv[1]);
if (i < 0 || i >= mapcount) {
printf("value %d is out of range (0-%d)\n", i, mapcount);
+ exitcode = 1;
} else {
mapping = &maptable[i];
maplist_f();
@@ -163,6 +164,7 @@ mmap_f(
size_t blocksize, sectsize;
int c, prot = 0;

+ exitcode = 1;
if (argc == 1) {
if (mapping)
return maplist_f();
@@ -263,6 +265,7 @@ mmap_f(
mapping->offset = offset;
mapping->name = filename;
mapping->prot = prot;
+ exitcode = 0;
return 0;
}

@@ -294,6 +297,7 @@ msync_f(
int c, flags = 0;
size_t blocksize, sectsize;

+ exitcode = 1;
while ((c = getopt(argc, argv, "ais")) != EOF) {
switch (c) {
case 'a':
@@ -336,9 +340,12 @@ msync_f(
if (!start)
return 0;

- if (msync(start, length, flags) < 0)
+ if (msync(start, length, flags) < 0) {
perror("msync");
+ return 0;
+ }

+ exitcode = 0;
return 0;
}

@@ -380,6 +387,7 @@ mread_f(
int dump = 0, rflag = 0, c;
size_t blocksize, sectsize;

+ exitcode = 1;
while ((c = getopt(argc, argv, "frv")) != EOF) {
switch (c) {
case 'f':
@@ -467,6 +475,7 @@ mread_f(
}
}
}
+ exitcode = 0;
return 0;
}

@@ -478,6 +487,7 @@ munmap_f(
ssize_t length;
unsigned int offset;

+ exitcode = 1;
if (munmap(mapping->addr, mapping->length) < 0) {
perror("munmap");
return 0;
@@ -503,6 +513,7 @@ munmap_f(
mapping = maptable = NULL;
}
maplist_f();
+ exitcode = 0;
return 0;
}

@@ -538,6 +549,7 @@ mwrite_f(
int c;
size_t blocksize, sectsize;

+ exitcode = 1;
while ((c = getopt(argc, argv, "rS:")) != EOF) {
switch (c) {
case 'r':
@@ -590,6 +602,7 @@ mwrite_f(
((char *)mapping->addr)[tmp] = seed;
}

+ exitcode = 0;
return 0;
}

@@ -622,6 +635,7 @@ mremap_f(
int c;
size_t blocksize, sectsize;

+ exitcode = 1;
init_cvtnum(&blocksize, &sectsize);

while ((c = getopt(argc, argv, "f:m")) != EOF) {
@@ -655,13 +669,14 @@ mremap_f(
else
new_addr = mremap(mapping->addr, mapping->length,
new_length, flags, new_addr);
- if (new_addr == MAP_FAILED)
+ if (new_addr == MAP_FAILED) {
perror("mremap");
- else {
- mapping->addr = new_addr;
- mapping->length = new_length;
+ return 0;
}

+ mapping->addr = new_addr;
+ mapping->length = new_length;
+ exitcode = 0;
return 0;
}
#endif /* HAVE_MREMAP */
diff --git a/io/open.c b/io/open.c
index 1abcb2ff2a01..0523f68263ec 100644
--- a/io/open.c
+++ b/io/open.c
@@ -209,6 +209,7 @@ open_f(
struct xfs_fsop_geom geometry = { 0 };
struct fs_path fsp;

+ exitcode = 1;
if (argc == 1) {
if (file)
return stat_f(argc, argv);
@@ -277,7 +278,10 @@ open_f(
if (!platform_test_xfs_fd(fd))
flags |= IO_FOREIGN;

- addfile(argv[optind], fd, &geometry, flags, &fsp);
+ if (addfile(argv[optind], fd, &geometry, flags, &fsp) != 0)
+ return 0;
+
+ exitcode = 0;
return 0;
}

@@ -289,6 +293,7 @@ close_f(
size_t length;
unsigned int offset;

+ exitcode = 1;
if (close(file->fd) < 0) {
perror("close");
return 0;
@@ -314,6 +319,7 @@ close_f(
file = filetable = NULL;
}
filelist_f();
+ exitcode = 0;
return 0;
}

@@ -346,9 +352,12 @@ lsproj_callback(
if ((fd = open(path, O_RDONLY)) == -1) {
fprintf(stderr, _("%s: cannot open %s: %s\n"),
progname, path, strerror(errno));
+ exitcode = 1;
} else {
if (getprojid(path, fd, &projid) == 0)
printf("[%u] %s\n", (unsigned int)projid, path);
+ else
+ exitcode = 1;
close(fd);
}
return 0;
@@ -384,9 +393,10 @@ lsproj_f(
if (recurse_all || recurse_dir)
nftw(file->name, lsproj_callback,
100, FTW_PHYS | FTW_MOUNT | FTW_DEPTH);
- else if (getprojid(file->name, file->fd, &projid) < 0)
+ else if (getprojid(file->name, file->fd, &projid) < 0) {
perror("getprojid");
- else
+ exitcode = 1;
+ } else
printf(_("projid = %u\n"), (unsigned int)projid);
return 0;
}
@@ -418,9 +428,12 @@ chproj_callback(
if ((fd = open(path, O_RDONLY)) == -1) {
fprintf(stderr, _("%s: cannot open %s: %s\n"),
progname, path, strerror(errno));
+ exitcode = 1;
} else {
- if (setprojid(path, fd, prid) < 0)
+ if (setprojid(path, fd, prid) < 0) {
+ exitcode = 1;
perror("setprojid");
+ }
close(fd);
}
return 0;
@@ -455,14 +468,17 @@ chproj_f(
prid = prid_from_string(argv[optind]);
if (prid == -1) {
printf(_("invalid project ID -- %s\n"), argv[optind]);
+ exitcode = 1;
return 0;
}

if (recurse_all || recurse_dir)
nftw(file->name, chproj_callback,
100, FTW_PHYS | FTW_MOUNT | FTW_DEPTH);
- else if (setprojid(file->name, file->fd, prid) < 0)
+ else if (setprojid(file->name, file->fd, prid) < 0) {
perror("setprojid");
+ exitcode = 1;
+ }
return 0;
}

@@ -486,6 +502,7 @@ get_extsize(const char *path, int fd)
if ((xfsctl(path, fd, FS_IOC_FSGETXATTR, &fsx)) < 0) {
printf("%s: FS_IOC_FSGETXATTR %s: %s\n",
progname, path, strerror(errno));
+ exitcode = 1;
return 0;
}
printf("[%u] %s\n", fsx.fsx_extsize, path);
@@ -498,6 +515,7 @@ set_extsize(const char *path, int fd, long extsz)
struct fsxattr fsx;
struct stat stat;

+ exitcode = 1;
if (fstat(fd, &stat) < 0) {
perror("fstat");
return 0;
@@ -524,6 +542,7 @@ set_extsize(const char *path, int fd, long extsz)
return 0;
}

+ exitcode = 0;
return 0;
}

@@ -542,6 +561,7 @@ get_extsize_callback(
if ((fd = open(path, O_RDONLY)) == -1) {
fprintf(stderr, _("%s: cannot open %s: %s\n"),
progname, path, strerror(errno));
+ exitcode = 1;
} else {
get_extsize(path, fd);
close(fd);
@@ -564,6 +584,7 @@ set_extsize_callback(
if ((fd = open(path, O_RDONLY)) == -1) {
fprintf(stderr, _("%s: cannot open %s: %s\n"),
progname, path, strerror(errno));
+ exitcode = 1;
} else {
set_extsize(path, fd, extsize);
close(fd);
@@ -601,6 +622,7 @@ extsize_f(
if (extsize < 0) {
printf(_("non-numeric extsize argument -- %s\n"),
argv[optind]);
+ exitcode = 1;
return 0;
}
} else {
diff --git a/io/parent.c b/io/parent.c
index 1968516d2c00..4653ddf3789a 100644
--- a/io/parent.c
+++ b/io/parent.c
@@ -387,6 +387,7 @@ parent_f(int argc, char **argv)
if (!fs) {
fprintf(stderr, _("file argument, \"%s\", is not in a mounted XFS filesystem\n"),
file->name);
+ exitcode = 1;
return 1;
}
mntpt = fs->fs_dir;
diff --git a/io/pread.c b/io/pread.c
index 60650aa340f6..7e9425fe21e8 100644
--- a/io/pread.c
+++ b/io/pread.c
@@ -390,6 +390,7 @@ pread_f(
int eof = 0, direction = IO_FORWARD;
int c;

+ exitcode = 1;
Cflag = qflag = uflag = vflag = 0;
init_cvtnum(&fsblocksize, &fssectsize);
bsize = fsblocksize;
@@ -488,6 +489,8 @@ pread_f(
}
if (c < 0)
return 0;
+
+ exitcode = 0;
if (qflag)
return 0;
gettimeofday(&t2, NULL);
diff --git a/io/prealloc.c b/io/prealloc.c
index 1a1c9ca37da2..2ddde9023760 100644
--- a/io/prealloc.c
+++ b/io/prealloc.c
@@ -88,6 +88,7 @@ allocsp_f(
{
xfs_flock64_t segment;

+ exitcode = 1;
if (!offset_length(argv[1], argv[2], &segment))
return 0;

@@ -95,6 +96,7 @@ allocsp_f(
perror("XFS_IOC_ALLOCSP64");
return 0;
}
+ exitcode = 0;
return 0;
}

@@ -105,6 +107,7 @@ freesp_f(
{
xfs_flock64_t segment;

+ exitcode = 1;
if (!offset_length(argv[1], argv[2], &segment))
return 0;

@@ -112,6 +115,7 @@ freesp_f(
perror("XFS_IOC_FREESP64");
return 0;
}
+ exitcode = 0;
return 0;
}

@@ -122,6 +126,7 @@ resvsp_f(
{
xfs_flock64_t segment;

+ exitcode = 1;
if (!offset_length(argv[1], argv[2], &segment))
return 0;

@@ -129,6 +134,7 @@ resvsp_f(
perror("XFS_IOC_RESVSP64");
return 0;
}
+ exitcode = 0;
return 0;
}

@@ -139,6 +145,7 @@ unresvsp_f(
{
xfs_flock64_t segment;

+ exitcode = 1;
if (!offset_length(argv[1], argv[2], &segment))
return 0;

@@ -146,6 +153,7 @@ unresvsp_f(
perror("XFS_IOC_UNRESVSP64");
return 0;
}
+ exitcode = 0;
return 0;
}

@@ -156,6 +164,7 @@ zero_f(
{
xfs_flock64_t segment;

+ exitcode = 1;
if (!offset_length(argv[1], argv[2], &segment))
return 0;

@@ -163,6 +172,7 @@ zero_f(
perror("XFS_IOC_ZERO_RANGE");
return 0;
}
+ exitcode = 0;
return 0;
}

@@ -198,6 +208,7 @@ fallocate_f(
int mode = 0;
int c;

+ exitcode = 1;
while ((c = getopt(argc, argv, "cikpu")) != EOF) {
switch (c) {
case 'c':
@@ -230,6 +241,7 @@ fallocate_f(
perror("fallocate");
return 0;
}
+ exitcode = 0;
return 0;
}

@@ -241,6 +253,7 @@ fpunch_f(
xfs_flock64_t segment;
int mode = FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE;

+ exitcode = 1;
if (!offset_length(argv[1], argv[2], &segment))
return 0;

@@ -249,6 +262,7 @@ fpunch_f(
perror("fallocate");
return 0;
}
+ exitcode = 0;
return 0;
}

@@ -260,6 +274,7 @@ fcollapse_f(
xfs_flock64_t segment;
int mode = FALLOC_FL_COLLAPSE_RANGE;

+ exitcode = 1;
if (!offset_length(argv[1], argv[2], &segment))
return 0;

@@ -268,6 +283,7 @@ fcollapse_f(
perror("fallocate");
return 0;
}
+ exitcode = 0;
return 0;
}

@@ -279,6 +295,7 @@ finsert_f(
xfs_flock64_t segment;
int mode = FALLOC_FL_INSERT_RANGE;

+ exitcode = 1;
if (!offset_length(argv[1], argv[2], &segment))
return 0;

@@ -287,6 +304,7 @@ finsert_f(
perror("fallocate");
return 0;
}
+ exitcode = 0;
return 0;
}

@@ -299,6 +317,7 @@ fzero_f(
int mode = FALLOC_FL_ZERO_RANGE;
int index = 1;

+ exitcode = 1;
if (strncmp(argv[index], "-k", 3) == 0) {
mode |= FALLOC_FL_KEEP_SIZE;
index++;
@@ -312,6 +331,7 @@ fzero_f(
perror("fallocate");
return 0;
}
+ exitcode = 0;
return 0;
}

@@ -324,6 +344,7 @@ funshare_f(
int mode = FALLOC_FL_UNSHARE_RANGE;
int index = 1;

+ exitcode = 1;
if (!offset_length(argv[index], argv[index + 1], &segment))
return 0;

@@ -332,6 +353,7 @@ funshare_f(
perror("fallocate");
return 0;
}
+ exitcode = 0;
return 0;
}
#endif /* HAVE_FALLOCATE */
diff --git a/io/pwrite.c b/io/pwrite.c
index a89edfd0496f..ca262bc40b25 100644
--- a/io/pwrite.c
+++ b/io/pwrite.c
@@ -295,6 +295,7 @@ pwrite_f(
int c, fd = -1;
int pwritev2_flags = 0;

+ exitcode = 1;
Cflag = qflag = uflag = dflag = wflag = Wflag = 0;
init_cvtnum(&fsblocksize, &fssectsize);
bsize = fsblocksize;
@@ -446,6 +447,8 @@ pwrite_f(
goto done;
}
}
+
+ exitcode = 0;
if (qflag)
goto done;
gettimeofday(&t2, NULL);
diff --git a/io/readdir.c b/io/readdir.c
index ca7a881d27e4..65fe51d2ca68 100644
--- a/io/readdir.c
+++ b/io/readdir.c
@@ -149,6 +149,7 @@ readdir_f(
DIR *dir;
int dfd;

+ exitcode = 1;
init_cvtnum(&fsblocksize, &fssectsize);

while ((c = getopt(argc, argv, "l:o:v")) != EOF) {
@@ -169,12 +170,12 @@ readdir_f(

dfd = dup(file->fd);
if (dfd < 0)
- return -1;
+ return 0;

dir = fdopendir(dfd);
if (!dir) {
close(dfd);
- return -1;
+ return 0;
}

if (offset == -1) {
@@ -199,6 +200,7 @@ readdir_f(
printf(_("%s, %d ops, %s (%s/sec and %.4f ops/sec)\n"),
s1, cnt, ts, s2, tdiv(cnt, t2));

+ exitcode = 0;
return 0;
}

diff --git a/io/reflink.c b/io/reflink.c
index f584e8f1fe43..86a20b2c629e 100644
--- a/io/reflink.c
+++ b/io/reflink.c
@@ -75,6 +75,7 @@ dedupe_ioctl(
error = ioctl(fd, XFS_IOC_FILE_EXTENT_SAME, args);
if (error) {
perror("XFS_IOC_FILE_EXTENT_SAME");
+ exitcode = 1;
goto done;
}
if (info->status < 0) {
@@ -139,24 +140,29 @@ dedupe_f(
soffset = cvtnum(fsblocksize, fssectsize, argv[optind]);
if (soffset < 0) {
printf(_("non-numeric src offset argument -- %s\n"), argv[optind]);
+ exitcode = 1;
return 0;
}
optind++;
doffset = cvtnum(fsblocksize, fssectsize, argv[optind]);
if (doffset < 0) {
printf(_("non-numeric dest offset argument -- %s\n"), argv[optind]);
+ exitcode = 1;
return 0;
}
optind++;
count = cvtnum(fsblocksize, fssectsize, argv[optind]);
if (count < 0) {
printf(_("non-positive length argument -- %s\n"), argv[optind]);
+ exitcode = 1;
return 0;
}

fd = openfile(infile, NULL, IO_READONLY, 0, NULL);
- if (fd < 0)
+ if (fd < 0) {
+ exitcode = 1;
return 0;
+ }

gettimeofday(&t1, NULL);
total = dedupe_ioctl(fd, soffset, doffset, count, &ops);
@@ -237,6 +243,7 @@ reflink_f(
struct timeval t1, t2;
int c, ops = 0, fd = -1;

+ exitcode = 1;
condensed = quiet_flag = 0;
doffset = soffset = 0;
init_cvtnum(&fsblocksize, &fssectsize);
@@ -284,7 +291,11 @@ clone_all:

gettimeofday(&t1, NULL);
total = reflink_ioctl(fd, soffset, doffset, count, &ops);
- if (ops == 0 || quiet_flag)
+ if (ops == 0)
+ goto done;
+
+ exitcode = 0;
+ if (quiet_flag)
goto done;
gettimeofday(&t2, NULL);
t2 = tsub(t2, t1);
diff --git a/io/resblks.c b/io/resblks.c
index 06903f5bb748..33da10711a0b 100644
--- a/io/resblks.c
+++ b/io/resblks.c
@@ -32,6 +32,7 @@ resblks_f(
xfs_fsop_resblks_t res;
long long blks;

+ exitcode = 1;
if (argc == 2) {
blks = cvtnum(file->geom.blocksize, file->geom.sectsize, argv[1]);
if (blks < 0) {
@@ -51,6 +52,7 @@ resblks_f(
(unsigned long long) res.resblks);
printf(_("available reserved blocks = %llu\n"),
(unsigned long long) res.resblks_avail);
+ exitcode = 0;
return 0;
}

diff --git a/io/seek.c b/io/seek.c
index 871b47262f03..e43a8f05ea36 100644
--- a/io/seek.c
+++ b/io/seek.c
@@ -111,6 +111,7 @@ seek_f(
int flag;
int startflag;

+ exitcode = 1;
flag = startflag = 0;
init_cvtnum(&fsblocksize, &fssectsize);

@@ -186,9 +187,11 @@ found_hole:
for (c = 0; flag; c++) {
if (offset == -1) {
/* print error or eof if the only entry */
- if (errno != ENXIO || c == 0 )
+ if (errno != ENXIO || c == 0 ) {
seek_output(startflag, seekinfo[current].name,
start, offset);
+ exitcode = 0;
+ }
return 0; /* stop on error or EOF */
}

@@ -210,6 +213,7 @@ found_hole:
if (offset != -1 && offset <= start)
goto bad_result;
}
+ exitcode = 0;
return 0;

bad_result:
diff --git a/io/sendfile.c b/io/sendfile.c
index 063fa7f48114..ce6b9f127e4e 100644
--- a/io/sendfile.c
+++ b/io/sendfile.c
@@ -85,6 +85,7 @@ sendfile_f(
int Cflag, qflag;
int c, fd = -1;

+ exitcode = 1;
Cflag = qflag = 0;
init_cvtnum(&blocksize, &sectsize);
while ((c = getopt(argc, argv, "Cf:i:q")) != EOF) {
@@ -146,6 +147,8 @@ sendfile_f(
c = send_buffer(offset, count, fd, &total);
if (c < 0)
goto done;
+
+ exitcode = 0;
if (qflag)
goto done;
gettimeofday(&t2, NULL);
diff --git a/io/shutdown.c b/io/shutdown.c
index 022a0e9a07ae..6374c973b44d 100644
--- a/io/shutdown.c
+++ b/io/shutdown.c
@@ -30,6 +30,7 @@ shutdown_f(
{
int c, flag = XFS_FSOP_GOING_FLAGS_NOLOGFLUSH;

+ exitcode = 1;
while ((c = getopt(argc, argv, "fv")) != -1) {
switch (c) {
case 'f':
@@ -44,6 +45,7 @@ shutdown_f(
perror("XFS_IOC_GOINGDOWN");
return 0;
}
+ exitcode = 0;
return 0;
}

diff --git a/io/stat.c b/io/stat.c
index 41d421525791..2e5e90f7a172 100644
--- a/io/stat.c
+++ b/io/stat.c
@@ -137,6 +137,7 @@ stat_f(
struct stat st;
int c, verbose = 0, raw = 0;

+ exitcode = 1;
while ((c = getopt(argc, argv, "rv")) != EOF) {
switch (c) {
case 'r':
@@ -157,6 +158,7 @@ stat_f(
perror("fstat");
return 0;
}
+ exitcode = 0;

if (raw)
return dump_raw_stat(&st);
@@ -193,6 +195,7 @@ statfs_f(
printf(_("fd.path = \"%s\"\n"), file->name);
if (platform_fstatfs(file->fd, &st) < 0) {
perror("fstatfs");
+ exitcode = 1;
} else {
printf(_("statfs.f_bsize = %lld\n"), (long long) st.f_bsize);
printf(_("statfs.f_blocks = %lld\n"), (long long) st.f_blocks);
@@ -207,6 +210,7 @@ statfs_f(
return 0;
if ((xfsctl(file->name, file->fd, XFS_IOC_FSGEOMETRY_V1, &fsgeo)) < 0) {
perror("XFS_IOC_FSGEOMETRY_V1");
+ exitcode = 1;
} else {
printf(_("geom.bsize = %u\n"), fsgeo.blocksize);
printf(_("geom.agcount = %u\n"), fsgeo.agcount);
@@ -223,6 +227,7 @@ statfs_f(
}
if ((xfsctl(file->name, file->fd, XFS_IOC_FSCOUNTS, &fscounts)) < 0) {
perror("XFS_IOC_FSCOUNTS");
+ exitcode = 1;
} else {
printf(_("counts.freedata = %llu\n"),
(unsigned long long) fscounts.freedata);
@@ -315,6 +320,7 @@ statx_f(
int atflag = 0;
unsigned int mask = STATX_ALL;

+ exitcode = 1;
while ((c = getopt(argc, argv, "m:rvFD")) != EOF) {
switch (c) {
case 'm':
@@ -358,6 +364,7 @@ statx_f(
perror("statx");
return 0;
}
+ exitcode = 0;

if (raw)
return dump_raw_statx(&stx);
diff --git a/io/sync_file_range.c b/io/sync_file_range.c
index 7e4f3e6da397..2a9965b098d2 100644
--- a/io/sync_file_range.c
+++ b/io/sync_file_range.c
@@ -46,6 +46,7 @@ sync_range_f(
int c, sync_mode = 0;
size_t blocksize, sectsize;

+ exitcode = 1;
while ((c = getopt(argc, argv, "abw")) != EOF) {
switch (c) {
case 'a':
@@ -87,6 +88,7 @@ sync_range_f(
perror("sync_file_range");
return 0;
}
+ exitcode = 0;
return 0;
}

diff --git a/io/truncate.c b/io/truncate.c
index 20bada82c4aa..d741e36860b6 100644
--- a/io/truncate.c
+++ b/io/truncate.c
@@ -31,6 +31,7 @@ truncate_f(
off64_t offset;
size_t blocksize, sectsize;

+ exitcode = 1;
init_cvtnum(&blocksize, &sectsize);
offset = cvtnum(blocksize, sectsize, argv[1]);
if (offset < 0) {
@@ -42,6 +43,7 @@ truncate_f(
perror("ftruncate");
return 0;
}
+ exitcode = 0;
return 0;
}

diff --git a/io/utimes.c b/io/utimes.c
index faf9b8d55dbc..9fcb44c22bc0 100755
--- a/io/utimes.c
+++ b/io/utimes.c
@@ -44,6 +44,7 @@ utimes_f(
struct timespec t[2];
int result;

+ exitcode = 1;
/* Get the timestamps */
result = timespec_from_string(argv[1], argv[2], &t[0]);
if (result) {
@@ -62,6 +63,7 @@ utimes_f(
return 0;
}

+ exitcode = 0;
return 0;
}