diff options
-rw-r--r-- | libmount/docs/libmount-sections.txt | 3 | ||||
-rw-r--r-- | libmount/src/context.c | 47 | ||||
-rw-r--r-- | libmount/src/context_mount.c | 27 | ||||
-rw-r--r-- | libmount/src/libmount.h.in | 5 | ||||
-rw-r--r-- | libmount/src/libmount.sym | 6 | ||||
-rw-r--r-- | libmount/src/mountP.h | 2 | ||||
-rw-r--r-- | sys-utils/mount.8 | 6 | ||||
-rw-r--r-- | sys-utils/mount.c | 46 |
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); |