From: Karel Zak Date: Thu, 5 Sep 2019 14:28:49 +0000 (+0200) Subject: fstrim: ignore non-directory mountpoints X-Git-Tag: v2.35-rc1~235 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=f227757c77bf0992de4c3c03349ab4a345e6b409;p=thirdparty%2Futil-linux.git fstrim: ignore non-directory mountpoints It seems better to silently ignore mount binds on file (= mountpoint is not a directory). This patch also fixes use-after-free bug from commit 402006fa6e. Addresses: https://github.com/karelzak/util-linux/issues/857 Signed-off-by: Karel Zak --- diff --git a/sys-utils/fstrim.8 b/sys-utils/fstrim.8 index 7e39b33d75..eba52ab9e9 100644 --- a/sys-utils/fstrim.8 +++ b/sys-utils/fstrim.8 @@ -100,7 +100,7 @@ LVM setup, etc. These reductions would not be reflected in fstrim_range.len option). .TP .B \-\-quiet -Suppress error messages. This option is meant to be used in systemd service +Suppress trim operation (ioctl) error messages. This option is meant to be used in systemd service file or in cron scripts to hide warnings that are result of known problems, such as NTFS driver reporting diff --git a/sys-utils/fstrim.c b/sys-utils/fstrim.c index 2c11a317f0..e6d7af3ea9 100644 --- a/sys-utils/fstrim.c +++ b/sys-utils/fstrim.c @@ -65,11 +65,27 @@ struct fstrim_control { dryrun : 1; }; +static int is_directory(const char *path, int silent) +{ + struct stat sb; + + if (stat(path, &sb) == -1) { + if (!silent) + warn(_("stat of %s failed"), path); + return 0; + } + if (!S_ISDIR(sb.st_mode)) { + if (!silent) + warnx(_("%s: not a directory"), path); + return 0; + } + return 1; +} + /* returns: 0 = success, 1 = unsupported, < 0 = error */ static int fstrim_filesystem(struct fstrim_control *ctl, const char *path, const char *devname) { int fd = -1, rc; - struct stat sb; struct fstrim_range range; char *rpath = realpath(path, NULL); @@ -87,16 +103,6 @@ static int fstrim_filesystem(struct fstrim_control *ctl, const char *path, const rc = -errno; goto done; } - if (fstat(fd, &sb) == -1) { - warn(_("stat of %s failed"), path); - rc = -errno; - goto done; - } - if (!S_ISDIR(sb.st_mode)) { - warnx(_("%s: not a directory"), path); - rc = -EINVAL; - goto done; - } if (ctl->dryrun) { if (devname) @@ -328,14 +334,15 @@ static int fstrim_all(struct fstrim_control *ctl) continue; /* overlaying mount */ /* FITRIM on read-only filesystem can fail, and it can fail */ - if (access(path, W_OK) != 0) { + if (access(tgt, W_OK) != 0) { if (errno == EROFS) continue; if (errno == EACCES) continue; } - if (!has_discard(src, &wholedisk)) + if (!is_directory(tgt, 1) || + !has_discard(src, &wholedisk)) continue; cnt++; @@ -384,7 +391,7 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -l, --length the number of bytes to discard\n"), out); fputs(_(" -m, --minimum the minimum extent length to discard\n"), out); fputs(_(" -v, --verbose print number of discarded bytes\n"), out); - fputs(_(" --quiet suppress error messages\n"), out); + fputs(_(" --quiet suppress trim error messages\n"), out); fputs(_(" -n, --dry-run does everything, but trim\n"), out); fputs(USAGE_SEPARATOR, out); @@ -475,6 +482,9 @@ int main(int argc, char **argv) if (all) return fstrim_all(&ctl); /* MNT_EX_* codes */ + if (!is_directory(path, 0)) + return EXIT_FAILURE; + rc = fstrim_filesystem(&ctl, path, NULL); if (rc == 1 && !ctl.quiet) warnx(_("%s: the discard operation is not supported"), path);