summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libmount/docs/libmount-sections.txt3
-rw-r--r--libmount/src/context.c47
-rw-r--r--libmount/src/context_mount.c27
-rw-r--r--libmount/src/libmount.h.in5
-rw-r--r--libmount/src/libmount.sym6
-rw-r--r--libmount/src/mountP.h2
-rw-r--r--sys-utils/mount.86
-rw-r--r--sys-utils/mount.c46
8 files changed, 109 insertions, 33 deletions
diff --git a/libmount/docs/libmount-sections.txt b/libmount/docs/libmount-sections.txt
index 78d89cae7..1d21879a0 100644
--- a/libmount/docs/libmount-sections.txt
+++ b/libmount/docs/libmount-sections.txt
@@ -35,8 +35,10 @@ mnt_context_enable_fork
mnt_context_enable_lazy
mnt_context_enable_loopdel
mnt_context_enable_rdonly_umount
+mnt_context_enable_rwonly_mount;
mnt_context_enable_sloppy
mnt_context_enable_verbose
+mnt_context_forced_rdonly;
mnt_context_get_cache
mnt_context_get_fs
mnt_context_get_fstab
@@ -72,6 +74,7 @@ mnt_context_is_nomtab
mnt_context_is_parent
mnt_context_is_rdonly_umount
mnt_context_is_restricted
+mnt_context_is_rwonly_mount;
mnt_context_is_sloppy
mnt_context_is_swapmatch
mnt_context_is_verbose
diff --git a/libmount/src/context.c b/libmount/src/context.c
index e731749b4..6a7c7d351 100644
--- a/libmount/src/context.c
+++ b/libmount/src/context.c
@@ -172,6 +172,7 @@ int mnt_reset_context(struct libmnt_context *cxt)
cxt->flags |= (fl & MNT_FL_FORCE);
cxt->flags |= (fl & MNT_FL_NOCANONICALIZE);
cxt->flags |= (fl & MNT_FL_RDONLY_UMOUNT);
+ cxt->flags |= (fl & MNT_FL_RWONLY_MOUNT);
cxt->flags |= (fl & MNT_FL_NOSWAPMATCH);
cxt->flags |= (fl & MNT_FL_TABPATHS_CHECKED);
return 0;
@@ -478,6 +479,48 @@ int mnt_context_is_rdonly_umount(struct libmnt_context *cxt)
}
/**
+ * mnt_context_enable_rwonly_mount:
+ * @cxt: mount context
+ * @enable: TRUE or FALSE
+ *
+ * Force read-write mount; if enabled libmount will never try MS_RDONLY
+ * after failed mount(2) EROFS. (See mount(8) man page, option -w).
+ *
+ * Returns: 0 on success, negative number in case of error.
+ */
+int mnt_context_enable_rwonly_mount(struct libmnt_context *cxt, int enable)
+{
+ return set_flag(cxt, MNT_FL_RWONLY_MOUNT, enable);
+}
+
+/**
+ * mnt_context_is_rwonly_mount
+ * @cxt: mount context
+ *
+ * See also mnt_context_enable_rwonly_mount() and mount(8) man page,
+ * option -w.
+ *
+ * Returns: 1 if only read-write mount is allowed.
+ */
+int mnt_context_is_rwonly_mount(struct libmnt_context *cxt)
+{
+ return cxt->flags & MNT_FL_RWONLY_MOUNT ? 1 : 0;
+}
+
+/**
+ * mnt_context_forced_rdonly:
+ * @cxt: mount context
+ *
+ * See also mnt_context_enable_rwonly_mount().
+ *
+ * Returns: 1 if mounted read-only on write-protected device.
+ */
+int mnt_context_forced_rdonly(struct libmnt_context *cxt)
+{
+ return cxt->flags & MNT_FL_FORCED_RDONLY ? 1 : 0;
+}
+
+/**
* mnt_context_disable_helpers:
* @cxt: mount context
* @disable: TRUE or FALSE
@@ -2002,8 +2045,10 @@ int mnt_context_apply_fstab(struct libmnt_context *cxt)
if (!cxt || !cxt->fs)
return -EINVAL;
- if (mnt_context_tab_applied(cxt)) /* already applied */
+ if (mnt_context_tab_applied(cxt)) { /* already applied */
+ DBG(CXT, ul_debugobj(cxt, "fstab already applied -- skip"));
return 0;
+ }
if (mnt_context_is_restricted(cxt)) {
DBG(CXT, ul_debugobj(cxt, "force fstab usage for non-root users!"));
diff --git a/libmount/src/context_mount.c b/libmount/src/context_mount.c
index 6368e9ba8..1c8a62924 100644
--- a/libmount/src/context_mount.c
+++ b/libmount/src/context_mount.c
@@ -1083,6 +1083,7 @@ int mnt_context_mount(struct libmnt_context *cxt)
assert(cxt->helper_exec_status == 1);
assert(cxt->syscall_status == 1);
+again:
rc = mnt_context_prepare_mount(cxt);
if (!rc)
rc = mnt_context_prepare_update(cxt);
@@ -1090,6 +1091,32 @@ int mnt_context_mount(struct libmnt_context *cxt)
rc = mnt_context_do_mount(cxt);
if (!rc)
rc = mnt_context_update_tabs(cxt);
+
+ /*
+ * Read-only device; try mount filesystem read-only
+ */
+ if ((rc == -EROFS && !mnt_context_syscall_called(cxt)) /* before syscall; rdonly loopdev */
+ || mnt_context_get_syscall_errno(cxt) == EROFS /* syscall failed with EROFS */
+ || mnt_context_get_syscall_errno(cxt) == EACCES) /* syscall failed with EACCES */
+ {
+ unsigned long mflags = 0;
+
+ mnt_context_get_mflags(cxt, &mflags);
+
+ if (!(mflags & MS_RDONLY) /* not yet RDONLY */
+ && !(mflags & MS_REMOUNT) /* not remount */
+ && !(mflags & MS_BIND) /* not bin mount */
+ && !mnt_context_is_rwonly_mount(cxt)) { /* no explicit read-write */
+
+ assert(!(cxt->flags & MNT_FL_FORCED_RDONLY));
+ DBG(CXT, ul_debugobj(cxt, "write-protected source, trying RDONLY."));
+
+ mnt_context_reset_status(cxt);
+ mnt_context_set_mflags(cxt, mflags | MS_RDONLY);
+ cxt->flags |= MNT_FL_FORCED_RDONLY;
+ goto again;
+ }
+ }
return rc;
}
diff --git a/libmount/src/libmount.h.in b/libmount/src/libmount.h.in
index f191a52fe..3f2da3230 100644
--- a/libmount/src/libmount.h.in
+++ b/libmount/src/libmount.h.in
@@ -610,6 +610,7 @@ extern int mnt_context_set_optsmode(struct libmnt_context *cxt, int mode);
extern int mnt_context_disable_canonicalize(struct libmnt_context *cxt, int disable);
extern int mnt_context_enable_lazy(struct libmnt_context *cxt, int enable);
extern int mnt_context_enable_rdonly_umount(struct libmnt_context *cxt, int enable);
+extern int mnt_context_enable_rwonly_mount(struct libmnt_context *cxt, int enable);
extern int mnt_context_disable_helpers(struct libmnt_context *cxt, int disable);
extern int mnt_context_enable_sloppy(struct libmnt_context *cxt, int enable);
extern int mnt_context_enable_fake(struct libmnt_context *cxt, int enable);
@@ -626,6 +627,8 @@ extern int mnt_context_is_lazy(struct libmnt_context *cxt)
__ul_attribute__((nonnull));
extern int mnt_context_is_rdonly_umount(struct libmnt_context *cxt)
__ul_attribute__((nonnull));
+extern int mnt_context_is_rwonly_mount(struct libmnt_context *cxt)
+ __ul_attribute__((nonnull));
extern int mnt_context_is_sloppy(struct libmnt_context *cxt)
__ul_attribute__((nonnull));
extern int mnt_context_is_fake(struct libmnt_context *cxt)
@@ -644,6 +647,8 @@ extern int mnt_context_is_nocanonicalize(struct libmnt_context *cxt)
__ul_attribute__((nonnull));
extern int mnt_context_is_swapmatch(struct libmnt_context *cxt)
__ul_attribute__((nonnull));
+extern int mnt_context_forced_rdonly(struct libmnt_context *cxt)
+ __ul_attribute__((nonnull));
extern int mnt_context_is_fork(struct libmnt_context *cxt)
__ul_attribute__((nonnull));
diff --git a/libmount/src/libmount.sym b/libmount/src/libmount.sym
index f0210c240..354332b43 100644
--- a/libmount/src/libmount.sym
+++ b/libmount/src/libmount.sym
@@ -315,3 +315,9 @@ MOUNT_2.28 {
mnt_table_find_target_with_option;
mnt_fs_set_priority;
} MOUNT_2.26;
+
+MOUNT_2.30 {
+ mnt_context_is_rwonly_mount;
+ mnt_context_forced_rdonly;
+ mnt_context_enable_rwonly_mount;
+} MOUNT_2.28;
diff --git a/libmount/src/mountP.h b/libmount/src/mountP.h
index 2baab55de..42957ecb9 100644
--- a/libmount/src/mountP.h
+++ b/libmount/src/mountP.h
@@ -328,6 +328,7 @@ struct libmnt_context
#define MNT_FL_RDONLY_UMOUNT (1 << 11) /* remount,ro after EBUSY umount(2) */
#define MNT_FL_FORK (1 << 12)
#define MNT_FL_NOSWAPMATCH (1 << 13)
+#define MNT_FL_RWONLY_MOUNT (1 << 14) /* explicit mount -w; never try read-only */
#define MNT_FL_MOUNTDATA (1 << 20)
#define MNT_FL_TAB_APPLIED (1 << 21) /* mtab/fstab merged to cxt->fs */
@@ -338,6 +339,7 @@ struct libmnt_context
#define MNT_FL_LOOPDEV_READY (1 << 26) /* /dev/loop<N> initialized by the library */
#define MNT_FL_MOUNTOPTS_FIXED (1 << 27)
#define MNT_FL_TABPATHS_CHECKED (1 << 28)
+#define MNT_FL_FORCED_RDONLY (1 << 29) /* mounted read-only on write-protected device */
/* default flags */
#define MNT_FL_DEFAULT 0
diff --git a/sys-utils/mount.8 b/sys-utils/mount.8
index 56ccbbd35..bbfe71b75 100644
--- a/sys-utils/mount.8
+++ b/sys-utils/mount.8
@@ -807,8 +807,12 @@ Mount the partition that has the specified
Verbose mode.
.TP
.BR \-w , " \-\-rw" , " \-\-read\-write"
-Mount the filesystem read/write. This is the default. A synonym is
+Mount the filesystem read/write. The read-write is kernel default. A synonym is
.BR "\-o rw" .
+
+Note that specify \fB\-w\fR on command line forces \fBmount\fR command
+to never try read-only mount on write-protected devices. The default is
+try read-only if the previous mount syscall with read-write flags failed.
.TP
.BR \-V , " \-\-version"
Display version information and exit.
diff --git a/sys-utils/mount.c b/sys-utils/mount.c
index b09e77616..bdf6e4bdb 100644
--- a/sys-utils/mount.c
+++ b/sys-utils/mount.c
@@ -51,8 +51,6 @@
* --options-source-force MNT_OMODE_FORCE
*/
-static int readwrite;
-
static int mk_exit_code(struct libmnt_context *cxt, int rc);
static void __attribute__((__noreturn__)) exit_non_root(const char *option)
@@ -369,7 +367,6 @@ static int mk_exit_code(struct libmnt_context *cxt, int rc)
const char *tgt = mnt_context_get_target(cxt);
const char *src = mnt_context_get_source(cxt);
-try_readonly:
if (mnt_context_helper_executed(cxt)) {
/*
* /sbin/mount.<type> called, return status
@@ -385,6 +382,9 @@ try_readonly:
*/
selinux_warning(cxt, tgt);
+ if (mnt_context_forced_rdonly(cxt))
+ warnx(_("WARNING: device write-protected, mounted read-only"));
+
return MOUNT_EX_SUCCESS; /* mount(2) success */
}
@@ -404,13 +404,14 @@ try_readonly:
return MOUNT_EX_USAGE;
/* -EROFS before syscall can happen only for loop mount */
case -EROFS:
- warnx(_("%s is used as read only loop, mounting read-only"), src);
- mnt_context_reset_status(cxt);
- mnt_context_set_mflags(cxt, mflags | MS_RDONLY);
- rc = mnt_context_mount(cxt);
- if (!rc)
- rc = mnt_context_finalize_mount(cxt);
- goto try_readonly;
+ if (mflags & MS_RDONLY)
+ warnx(_("cannot mount %s read-only"), src);
+ else if (mnt_context_is_rwonly_mount(cxt))
+ warnx(_("%s is write-protected but explicit `-w' flag given"), src);
+ else if (mflags & MS_REMOUNT)
+ warnx(_("cannot remount %s read-write, is write-protected"), src);
+ warnx(_("mount %s on %s failed"), src, tgt);
+ return MOUNT_EX_USAGE;
case -MNT_ERR_NOFSTAB:
if (mnt_context_is_swapmatch(cxt)) {
warnx(_("can't find %s in %s"),
@@ -481,7 +482,6 @@ try_readonly:
*/
syserr = mnt_context_get_syscall_errno(cxt);
-
switch(syserr) {
case EPERM:
if (geteuid() == 0) {
@@ -620,27 +620,11 @@ try_readonly:
case EROFS:
if (mflags & MS_RDONLY)
warnx(_("cannot mount %s read-only"), src);
-
- else if (readwrite)
+ else if (mnt_context_is_rwonly_mount(cxt))
warnx(_("%s is write-protected but explicit `-w' flag given"), src);
-
else if (mflags & MS_REMOUNT)
warnx(_("cannot remount %s read-write, is write-protected"), src);
-
- else if (mflags & MS_BIND)
- warn(_("mount %s on %s failed"), src, tgt);
-
- else {
- warnx(_("%s is write-protected, mounting read-only"), src);
-
- mnt_context_reset_status(cxt);
- mnt_context_set_mflags(cxt, mflags | MS_RDONLY);
- rc = mnt_context_do_mount(cxt);
- if (!rc)
- rc = mnt_context_finalize_mount(cxt);
-
- goto try_readonly;
- }
+ warnx(_("mount %s on %s failed"), src, tgt);
break;
case ENOMEDIUM:
@@ -924,7 +908,7 @@ int main(int argc, char **argv)
break;
case 'r':
append_option(cxt, "ro");
- readwrite = 0;
+ mnt_context_enable_rwonly_mount(cxt, FALSE);
break;
case 'v':
mnt_context_enable_verbose(cxt, TRUE);
@@ -934,7 +918,7 @@ int main(int argc, char **argv)
break;
case 'w':
append_option(cxt, "rw");
- readwrite = 1;
+ mnt_context_enable_rwonly_mount(cxt, TRUE);
break;
case 'o':
append_option(cxt, optarg);