summaryrefslogtreecommitdiffstats
path: root/mount/mount.c
diff options
context:
space:
mode:
authorKarel Zak2010-09-20 13:10:36 +0200
committerKarel Zak2010-09-20 14:37:24 +0200
commit1b85dcd9cabd478859e46bcfc9f7847acec98db6 (patch)
tree29c6631f26e0a81b1fe659d0ac64f37ad59181f8 /mount/mount.c
parentul: use atexit() to deallocate buffer, print errors by err() (diff)
downloadkernel-qcow2-util-linux-1b85dcd9cabd478859e46bcfc9f7847acec98db6.tar.gz
kernel-qcow2-util-linux-1b85dcd9cabd478859e46bcfc9f7847acec98db6.tar.xz
kernel-qcow2-util-linux-1b85dcd9cabd478859e46bcfc9f7847acec98db6.zip
mount: rewrite is_readonly()
This new implementation is more optimistic and always calls access(2). The fallback solution (modify atime by futimens(2)) should be used very rarely. Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'mount/mount.c')
-rw-r--r--mount/mount.c46
1 files changed, 27 insertions, 19 deletions
diff --git a/mount/mount.c b/mount/mount.c
index 84986e36b..22828b4e2 100644
--- a/mount/mount.c
+++ b/mount/mount.c
@@ -1308,38 +1308,46 @@ cdrom_setspeed(const char *spec) {
}
/*
- * Check if @node is read-only filesystem by access() or futimens().
- *
- * Note that access(2) uses real-UID (= useless for suid programs)
- * and euidaccess(2) does not check for read-only FS.
+ * Check if @path is on read-only filesystem independently on file permissions.
*/
static int
-is_readonly(const char *node)
+is_readonly(const char *path)
{
- int res = 0;
+ int fd;
+
+ if (access(path, W_OK) == 0)
+ return 0;
+ if (errno == EROFS)
+ return 1;
+ if (errno != EACCES)
+ return 0;
- if (getuid() == geteuid()) {
- if (access(node, W_OK) == -1 && errno == EROFS)
- res = 1;
- }
#ifdef HAVE_FUTIMENS
- else {
+ /*
+ * access(2) returns EACCES on read-only FS:
+ *
+ * - for set-uid application if one component of the path is not
+ * accessible for the current rUID. (Note that euidaccess(2) does not
+ * check for EROFS at all).
+ *
+ * - for read-write filesystem with read-only VFS node (aka -o remount,ro,bind)
+ */
+ fd = open(path, O_RDONLY);
+ if (fd >= 0) {
struct timespec times[2];
- int fd = open(node, O_RDONLY);
-
- if (fd < 0)
- goto done;
+ int errsv = 0;
times[0].tv_nsec = UTIME_NOW; /* atime */
times[1].tv_nsec = UTIME_OMIT; /* mtime */
- if (futimens(fd, times) == -1 && errno == EROFS)
- res = 1;
+ if (futimens(fd, times) == -1)
+ errsv = errno;
close(fd);
+
+ return errsv == EROFS;
}
-done:
#endif
- return res;
+ return 0;
}
/*