From: Karel Zak Date: Tue, 12 Oct 2010 13:04:28 +0000 (+0200) Subject: libmount: add umount(2) support X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ea8f06f97913ebfe62fc971e952a309ae15d6544;p=util-linux libmount: add umount(2) support Signed-off-by: Karel Zak --- diff --git a/shlibs/mount/src/Makefile.am b/shlibs/mount/src/Makefile.am index f1db1ad1..820ab8bc 100644 --- a/shlibs/mount/src/Makefile.am +++ b/shlibs/mount/src/Makefile.am @@ -12,7 +12,7 @@ usrlib_exec_LTLIBRARIES = libmount.la libmount_la_SOURCES = mountP.h version.c utils.c test.c init.c cache.c \ optstr.c optmap.c iter.c lock.c \ fs.c tab.c tab_parse.c tab_update.c \ - context.c context_mount.c \ + context.c context_mount.c context_umount.c \ $(mountinc_HEADERS) \ $(top_srcdir)/lib/at.c \ $(top_srcdir)/include/list.h \ diff --git a/shlibs/mount/src/context.c b/shlibs/mount/src/context.c index bf364a49..08d4e1e8 100644 --- a/shlibs/mount/src/context.c +++ b/shlibs/mount/src/context.c @@ -217,6 +217,21 @@ int mnt_context_enable_lazy(mnt_context *cxt, int enable) return set_flag(cxt, MNT_FL_LAZY, enable); } +/** + * mnt_context_enable_rdonly_umount: + * @cxt: mount context + * @enable: TRUE or FALSE + * + * Enable/disable read-only remount on failed umount(2) + * (see umount(8) man page, option -r). + * + * Returns: 0 on success, negative number in case of error. + */ +int mnt_context_enable_rdonly_umount(mnt_context *cxt, int enable) +{ + return set_flag(cxt, MNT_FL_RDONLY_UMOUNT, enable); +} + /** * mnt_context_disable_helpers: * @cxt: mount context @@ -568,7 +583,7 @@ int mnt_context_get_mtab(mnt_context *cxt, mnt_tab **tb) int rc; cxt->mtab = mnt_new_tab(); - if (!cxt->fstab) + if (!cxt->mtab) return -ENOMEM; rc = mnt_tab_parse_mtab(cxt->mtab); if (rc) @@ -980,6 +995,11 @@ int mnt_context_prepare_helper(mnt_context *cxt, const char *name, int mnt_context_prepare_update(mnt_context *cxt, int act) { int rc; + const char *tgt = cxt->fs ? mnt_fs_get_target(cxt->fs) : NULL; + + if (act == MNT_ACT_UMOUNT && tgt && !strcmp(tgt, "/")) + /* Don't try to touch mtab if umounting root FS */ + cxt->flags |= MNT_FL_NOMTAB; if ((cxt->flags & MNT_FL_NOMTAB) || cxt->helper) return 0; @@ -1131,3 +1151,146 @@ err: DBG(CXT, mnt_debug_h(cxt, "failed to found entry in fstab/mtab")); return rc; } + + +#ifdef TEST_PROGRAM + +mnt_lock *lock; + +static void lock_fallback(void) +{ + if (lock) { + mnt_unlock_file(lock); + mnt_free_lock(lock); + } +} + +int test_mount(struct mtest *ts, int argc, char *argv[]) +{ + int idx = 1, rc = 0; + mnt_context *cxt; + + if (argc < 2) + return -EINVAL; + + cxt = mnt_new_context(); + if (!cxt) + return -ENOMEM; + + if (!strcmp(argv[idx], "-o")) { + mnt_context_set_optstr(cxt, argv[idx + 1]); + idx += 2; + } + if (!strcmp(argv[idx], "-t")) { + /* TODO: use mnt_context_set_fstype_pattern() */ + mnt_context_set_fstype(cxt, argv[idx + 1]); + idx += 2; + } + + if (argc == idx + 1) + /* mount | */ + mnt_context_set_target(cxt, argv[idx++]); + + else if (argc == idx + 2) { + /* mount */ + mnt_context_set_source(cxt, argv[idx++]); + mnt_context_set_target(cxt, argv[idx++]); + } + + rc = mnt_context_prepare_mount(cxt); + if (rc) + printf("failed to prepare mount\n"); + else { + lock = mnt_context_get_lock(cxt); + if (lock) + atexit(lock_fallback); + + rc = mnt_context_do_mount(cxt); + if (rc) + printf("failed to mount\n"); + else { + printf("successfully mounted"); + rc = mnt_context_post_mount(cxt); + if (rc) + printf("mtab update failed\n"); + } + } + + mnt_free_context(cxt); + return rc; +} + +int test_umount(struct mtest *ts, int argc, char *argv[]) +{ + int idx = 1, rc = 0; + mnt_context *cxt; + + if (argc < 2) + return -EINVAL; + + cxt = mnt_new_context(); + if (!cxt) + return -ENOMEM; + + if (!strcmp(argv[idx], "-t")) { + mnt_context_set_fstype(cxt, argv[idx + 1]); + idx += 2; + } + + if (!strcmp(argv[idx], "-f")) { + mnt_context_enable_force(cxt, TRUE); + idx++; + } + + if (!strcmp(argv[idx], "-l")) { + mnt_context_enable_lazy(cxt, TRUE); + idx++; + } + + if (!strcmp(argv[idx], "-r")) { + mnt_context_enable_rdonly_umount(cxt, TRUE); + idx++; + } + + if (argc == idx + 1) { + /* mount | */ + mnt_context_set_target(cxt, argv[idx++]); + } else { + rc = -EINVAL; + goto err; + } + + rc = mnt_context_prepare_umount(cxt); + if (rc) + printf("failed to prepare umount\n"); + else { + lock = mnt_context_get_lock(cxt); + if (lock) + atexit(lock_fallback); + + rc = mnt_context_do_umount(cxt); + if (rc) + printf("failed to umount\n"); + else { + printf("successfully umounted"); + rc = mnt_context_post_umount(cxt); + if (rc) + printf("mtab update failed\n"); + } + } +err: + mnt_free_context(cxt); + return rc; +} + +int main(int argc, char *argv[]) +{ + struct mtest tss[] = { + { "--mount", test_mount, "[-o ] [-t ] | " }, + { "--umount", test_umount, "[-t ] [-f][-l][-r] |" }, + { NULL }}; + + return mnt_run_test(tss, argc, argv); +} + +#endif /* TEST_PROGRAM */ diff --git a/shlibs/mount/src/context_mount.c b/shlibs/mount/src/context_mount.c index a09eee93..4bfdb267 100644 --- a/shlibs/mount/src/context_mount.c +++ b/shlibs/mount/src/context_mount.c @@ -246,7 +246,7 @@ static int exec_helper(mnt_context *cxt) rc = generate_helper_optstr(cxt, &o); if (rc) - goto done; + return -EINVAL; DBG_FLUSH; @@ -313,8 +313,6 @@ static int exec_helper(mnt_context *cxt) break; } -done: - free(o); return rc; } @@ -351,20 +349,22 @@ static int do_mount(mnt_context *cxt, const char *try_type) if (!(flags & MS_MGC_MSK)) flags |= MS_MGC_VAL; - DBG(CXT, mnt_debug_h(cxt, "calling mount(2) " + DBG(CXT, mnt_debug_h(cxt, "%smount(2) " "[source=%s, target=%s, type=%s, " " mountflags=%08lx, mountdata=%s]", + (cxt->flags & MNT_FL_FAKE) ? "(FAKE) " : "", src, target, type, flags, cxt->mountdata ? "yes" : "")); - if (mount(src, target, type, flags, cxt->mountdata)) { - cxt->syscall_errno = errno; - DBG(CXT, mnt_debug_h(cxt, "mount(2) failed [errno=%d]", - cxt->syscall_errno)); - return -cxt->syscall_errno; + if (!(cxt->flags & MNT_FL_FAKE)) { + if (mount(src, target, type, flags, cxt->mountdata)) { + cxt->syscall_errno = errno; + DBG(CXT, mnt_debug_h(cxt, "mount(2) failed [errno=%d]", + cxt->syscall_errno)); + return -cxt->syscall_errno; + } + DBG(CXT, mnt_debug_h(cxt, "mount(2) success")); } - - DBG(CXT, mnt_debug_h(cxt, "mount(2) success")); return 0; } @@ -502,81 +502,3 @@ int mnt_context_mount_strerror(mnt_context *cxt, char *buf, size_t bufsiz) return 0; } -#ifdef TEST_PROGRAM - -mnt_lock *lock; - -static void lock_fallback(void) -{ - if (lock) { - mnt_unlock_file(lock); - mnt_free_lock(lock); - } -} - -int test_mount(struct mtest *ts, int argc, char *argv[]) -{ - int idx = 1, rc = 0; - mnt_context *cxt; - - if (argc < 2) - return -EINVAL; - - cxt = mnt_new_context(); - if (!cxt) - return -ENOMEM; - - if (!strcmp(argv[idx], "-o")) { - mnt_context_set_optstr(cxt, argv[idx + 1]); - idx += 2; - } - if (!strcmp(argv[idx], "-t")) { - /* TODO: use mnt_context_set_fstype_pattern() */ - mnt_context_set_fstype(cxt, argv[idx + 1]); - idx += 2; - } - - if (argc == idx + 1) - /* mount | */ - mnt_context_set_target(cxt, argv[idx++]); - - else if (argc == idx + 2) { - /* mount */ - mnt_context_set_source(cxt, argv[idx++]); - mnt_context_set_target(cxt, argv[idx++]); - } - - rc = mnt_context_prepare_mount(cxt); - if (rc) - printf("failed to prepare mount\n"); - else { - lock = mnt_context_get_lock(cxt); - if (lock) - atexit(lock_fallback); - - rc = mnt_context_do_mount(cxt); - if (rc) - printf("failed to mount\n"); - else { - printf("successfully mounted"); - rc = mnt_context_post_mount(cxt); - if (rc) - printf("mtab update failed\n"); - } - } - - mnt_free_context(cxt); - return rc; -} - -int main(int argc, char *argv[]) -{ - struct mtest tss[] = { - { "--mount", test_mount, "[-o ] [-t ] | " }, - { NULL } - }; - - return mnt_run_test(tss, argc, argv); -} - -#endif /* TEST_PROGRAM */ diff --git a/shlibs/mount/src/context_umount.c b/shlibs/mount/src/context_umount.c new file mode 100644 index 00000000..1222fe6f --- /dev/null +++ b/shlibs/mount/src/context_umount.c @@ -0,0 +1,529 @@ +/* + * Copyright (C) 2010 Karel Zak + * + * This file may be redistributed under the terms of the + * GNU Lesser General Public License. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "c.h" +#include "pathnames.h" +#include "strutils.h" +#include "mountP.h" + +static int lookup_umount_fs(mnt_context *cxt) +{ + int rc; + const char *tgt; + mnt_tab *mtab; + mnt_fs *fs; + + tgt = mnt_fs_get_target(cxt->fs); + if (!tgt) { + DBG(CXT, mnt_debug_h(cxt, "umount: undefined target")); + return -EINVAL; + } + rc = mnt_context_get_mtab(cxt, &mtab); + if (rc) { + DBG(CXT, mnt_debug_h(cxt, "umount: failed to read mtab")); + return rc; + } + fs = mnt_tab_find_target(mtab, tgt, MNT_ITER_BACKWARD); + if (!fs) { + /* maybe the option is source rather than target (mountpoint) */ + fs = mnt_tab_find_source(mtab, tgt, MNT_ITER_BACKWARD); + + if (fs) { + mnt_fs *fs1 = mnt_tab_find_target(mtab, + mnt_fs_get_target(fs), + MNT_ITER_BACKWARD); + if (!fs1) { + DBG(CXT, mnt_debug_h(cxt, "mtab is broken?!?!")); + return -EINVAL; + } + if (fs != fs1) { + /* Something was stacked over `file' on the + * same mount point. */ + DBG(CXT, mnt_debug_h(cxt, + "umount: %s: %s is mounted " + "over it on the same point", + tgt, mnt_fs_get_source(fs1))); + return -EINVAL; + } + } + } + + if (!fs) { + DBG(CXT, mnt_debug_h(cxt, "cannot found %s in mtab", tgt)); + return 0; + } + + /* copy from mtab/fstab to our FS description + */ + rc = mnt_fs_set_source(cxt->fs, mnt_fs_get_source(fs)); + if (!rc) + rc = mnt_fs_set_target(cxt->fs, mnt_fs_get_target(fs)); + + if (!rc && !mnt_fs_get_fstype(cxt->fs)) + rc = mnt_fs_set_fstype(cxt->fs, mnt_fs_get_fstype(fs)); + if (!rc) + rc = mnt_fs_set_optstr(cxt->fs, mnt_fs_get_optstr(fs)); + + cxt->flags |= MNT_FL_TAB_APPLIED; + return rc; +} + +/* check if @devname is loopdev and if the device is associated + * with a source from @fstab_fs + * + * TODO : move this to loopdev.c + */ +static int mnt_loopdev_associated_fs(const char *devname, mnt_fs *fs) +{ + uintmax_t offset = 0; + const char *src; + char *val, *optstr; + size_t valsz; + + /* check if it begins with /dev/loop */ + if (strncmp(devname, _PATH_DEV_LOOP, sizeof(_PATH_DEV_LOOP))) + return 0; + + src = mnt_fs_get_srcpath(fs); + if (!src) + return 0; + + /* check for offset option in @fs */ + optstr = (char *) mnt_fs_get_optstr(fs); + if (optstr && !mnt_optstr_get_option(optstr, "offset=", &val, &valsz)) { + int rc; + + val = strndup(val, valsz); + if (!val) + return 0; + rc = strtosize(val, &offset); + free(val); + if (rc) + return 0; + } + + /* TODO: + * if (mnt_loopdev_associated_file(devname, src, offset)) + * return 1; + */ + return 0; +} + +/* + * Note that cxt->fs contains relevant mtab entry! + */ +static int evaluate_permissions(mnt_context *cxt) +{ + mnt_tab *fstab; + unsigned long u_flags; + const char *tgt, *src, *optstr; + int rc, ok = 0; + mnt_fs *fs; + + if (!cxt || !cxt->fs) + return -EINVAL; + + if (!mnt_context_is_restricted(cxt)) + return 0; /* superuser mount */ + + if (!(cxt->flags & MNT_FL_TAB_APPLIED)) { + DBG(CXT, mnt_debug_h(cxt, + "cannot found %s in mtab and you are not root", + mnt_fs_get_target(cxt->fs))); + goto eperm; + } + + mnt_context_get_userspace_mountflags(cxt, &u_flags); + + if (!(cxt->flags & MNT_FL_NOHELPERS) && (u_flags & MNT_MS_UHELPER)) { + char *suffix = NULL; + char *o = (char *) mnt_fs_get_optstr(cxt->fs); + size_t valsz; + + rc = mnt_optstr_get_option(o, "uhelper", &suffix, &valsz); + if (!rc) { + suffix = strndup(suffix, valsz); + if (!suffix) + return -ENOMEM; + rc = mnt_context_prepare_helper(cxt, "umount", suffix); + } + if (rc < 0) + return rc; + if (cxt->helper) + return 0; /* we'll call /sbin/umount. */ + } + + /* + * User mounts has to be in /etc/fstab + */ + rc = mnt_context_get_fstab(cxt, &fstab); + if (rc) + return rc; + + tgt = mnt_fs_get_target(cxt->fs); + src = mnt_fs_get_source(cxt->fs); + + /* If fstab contains the two lines + * /dev/sda1 /mnt/zip auto user,noauto 0 0 + * /dev/sda4 /mnt/zip auto user,noauto 0 0 + * then "mount /dev/sda4" followed by "umount /mnt/zip" used to fail. + * So, we must not look for file, but for the pair (dev,file) in fstab. + */ + fs = mnt_tab_find_pair(fstab, src, tgt, MNT_ITER_FORWARD); + if (!fs) { + /* + * It's possible that there is /path/file.img in fstab and + * /dev/loop0 in mtab -- then we have to check releation + * between loopdev and the file. + */ + fs = mnt_tab_find_target(fstab, tgt, MNT_ITER_FORWARD); + if (fs) { + const char *dev = mnt_fs_get_srcpath(cxt->fs); /* devname from mtab */ + + if (!dev || !mnt_loopdev_associated_fs(dev, fs)) + fs = NULL; + } + if (!fs) { + DBG(CXT, mnt_debug_h(cxt, + "umount %s: mtab disagrees with fstab", + tgt)); + goto eperm; + } + } + + /* + * User mounting and unmounting is allowed only if fstab contains one + * of the options `user', `users' or `owner' or `group'. + * + * The option `users' allows arbitrary users to mount and unmount - + * this may be a security risk. + * + * The options `user', `owner' and `group' only allow unmounting by the + * user that mounted (visible in mtab). + */ + optstr = mnt_fs_get_optstr(fs); + if (!optstr) + goto eperm; + + if (mnt_optstr_get_userspace_mountflags(optstr, &u_flags)) + goto eperm; + + if (u_flags & MNT_MS_USERS) + /* promiscuous setting in fstab */ + return 0; + /* + * Check user= setting from mtab if there is user, owner or + * group option in /etc/fstab + */ + if ((u_flags & MNT_MS_USER) || (u_flags & MNT_MS_OWNER) || + (u_flags & MNT_MS_GROUP)) { + + char *curr_user = mnt_get_username(getuid()); + char *mtab_user = NULL; + size_t sz; + + if (!curr_user) { + DBG(CXT, mnt_debug_h(cxt, "umount %s: cannot " + "convert %d to username", + tgt, getuid())); + goto eperm; + } + + /* get options from mtab */ + optstr = mnt_fs_get_optstr(cxt->fs); + if (optstr && !mnt_optstr_get_option((char *) optstr, + "user", &mtab_user, &sz) && sz) + ok = !strncmp(curr_user, mtab_user, sz); + } + + if (ok) { + DBG(CXT, mnt_debug_h(cxt, "umount %s is allowed", tgt)); + return 0; + } +eperm: + DBG(CXT, mnt_debug_h(cxt, "umount %s is not allowed for you", tgt)); + return -EPERM; +} + +static int exec_helper(mnt_context *cxt) +{ + int rc; + + assert(cxt); + assert(cxt->fs); + assert(cxt->helper); + + DBG_FLUSH; + + switch (fork()) { + case 0: + { + const char *args[10], *type; + int i = 0; + + if (setgid(getgid()) < 0) + exit(EXIT_FAILURE); + + if (setuid(getuid()) < 0) + exit(EXIT_FAILURE); + + type = mnt_fs_get_fstype(cxt->fs); + + args[i++] = cxt->helper; /* 1 */ + args[i++] = mnt_fs_get_target(cxt->fs); /* 2 */ + + if (cxt->flags & MNT_FL_NOMTAB) + args[i++] = "-n"; /* 3 */ + if (cxt->flags & MNT_FL_LAZY) + args[i++] = "-l"; /* 4 */ + if (cxt->flags & MNT_FL_FORCE) + args[i++] = "-f"; /* 5 */ + if (cxt->flags & MNT_FL_VERBOSE) + args[i++] = "-v"; /* 6 */ + if (cxt->flags & MNT_FL_RDONLY_UMOUNT) + args[i++] = "-r"; /* 7 */ + if (type && !endswith(cxt->helper, type)) { + args[i++] = "-t"; /* 8 */ + args[i++] = (char *) type; /* 9 */ + } + + args[i] = NULL; /* 10 */ +#ifdef CONFIG_LIBMOUNT_DEBUG + i = 0; + for (i = 0; args[i]; i++) + DBG(CXT, mnt_debug_h(cxt, "argv[%d] = \"%s\"", + i, args[i])); +#endif + DBG_FLUSH; + execv(cxt->helper, (char * const *) args); + exit(EXIT_FAILURE); + } + default: + { + int st; + wait(&st); + cxt->helper_status = WIFEXITED(st) ? WEXITSTATUS(st) : -1; + + DBG(CXT, mnt_debug_h(cxt, "%s executed [status=%d]", + cxt->helper, cxt->helper_status)); + rc = 0; + break; + } + + case -1: + rc = -errno; + DBG(CXT, mnt_debug_h(cxt, "fork() failed")); + break; + } + + return rc; +} + +static int do_umount(mnt_context *cxt) +{ + int rc = 0; + const char *src, *target; + + assert(cxt); + assert(cxt->fs); + + if (cxt->helper) + return exec_helper(cxt); + + src = mnt_fs_get_srcpath(cxt->fs); + target = mnt_fs_get_target(cxt->fs); + + if (!target) + return -EINVAL; + + if (cxt->flags & MNT_FL_FAKE) + return 0; + + if (cxt->flags & MNT_FL_LAZY) + rc = umount2(target, MNT_DETACH); + + else if (cxt->flags & MNT_FL_FORCE) { + rc = umount2(target, MNT_FORCE); + + if (rc < 0 && errno == ENOSYS) + rc = umount(target); + } else + rc = umount(target); + + if (rc < 0) + cxt->syscall_errno = errno; + + /* + * try remount read-only + */ + if (rc < 0 && cxt->syscall_errno == EBUSY && + (cxt->flags & MNT_FL_RDONLY_UMOUNT) && src) { + + cxt->mountflags |= MS_REMOUNT | MS_RDONLY; + cxt->flags &= ~MNT_FL_LOOPDEL; + DBG(CXT, mnt_debug_h(cxt, "umount(2) failed [errno=%d] -- " + "tring remount read-only", + cxt->syscall_errno)); + + rc = mount(src, target, NULL, + MS_MGC_VAL | MS_REMOUNT | MS_RDONLY, NULL); + if (rc < 0) { + cxt->syscall_errno = errno; + DBG(CXT, mnt_debug_h(cxt, "read-only re-mount(2) failed " + "[errno=%d]", + cxt->syscall_errno)); + return -cxt->syscall_errno; + } + cxt->syscall_errno = 0; + DBG(CXT, mnt_debug_h(cxt, "read-only re-mount(2) success")); + return 0; + } + + if (rc < 0) { + DBG(CXT, mnt_debug_h(cxt, "umount(2) failed [errno=%d]", + cxt->syscall_errno)); + return -cxt->syscall_errno; + } + DBG(CXT, mnt_debug_h(cxt, "umount(2) success")); + return 0; +} + +/** + * mnt_context_prepare_umount: + * @cxt: mount context + * + * This function: + * - read information from fstab/mtab (if necessary) + * - check premissions + * - prepare for mtab update (if necessary) + * + * It's strongly recommended to use this function before mnt_context_do_umount(). + * + * Returns: 0 on success, and negative number in case of error. + */ +int mnt_context_prepare_umount(mnt_context *cxt) +{ + int rc = 0; + + if (!cxt) + return -EINVAL; + + if (!cxt->fs || (!mnt_fs_get_source(cxt->fs) && + !mnt_fs_get_target(cxt->fs))) + return -EINVAL; + + free(cxt->helper); /* be paranoid */ + cxt->helper = NULL; + + rc = lookup_umount_fs(cxt); + if (!rc) + rc = evaluate_permissions(cxt); + if (!rc && !cxt->helper) + rc = mnt_context_prepare_helper(cxt, "umount", NULL); +/* TODO + if ((cxt->flags & MNT_FL_LOOPDEL) && + (!mnt_is_loopdev(src) || mnt_loopdev_is_autoclear(src))) + cxt->flags &= ~MNT_FL_LOOPDEL; +*/ + if (!rc) + rc = mnt_context_prepare_update(cxt, MNT_ACT_UMOUNT); + if (!rc) { + DBG(CXT, mnt_debug_h(cxt, "umount sucessfully prepared")); + return 0; + } + + DBG(CXT, mnt_debug_h(cxt, "umount prepare failed")); + return rc; +} + +/** + * mnt_context_do_umount: + * @cxt: mount context + * + * Umount filesystem by umount(2) or fork()+exec(/sbin/umount.). + * + * See also mnt_context_disable_helpers(). + * + * Returns: 0 on success, and negative number in case of error. + */ +int mnt_context_do_umount(mnt_context *cxt) +{ + if (!cxt || !cxt->fs || (cxt->fs->flags & MNT_FS_SWAP)) + return -EINVAL; + + return do_umount(cxt); +} + +/** + * mnt_context_post_umount: + * @cxt: mount context + * + * Updates mtab and detroy loopdev etc. This function should be always called after + * mnt_context_do_umount(). + * + * Returns: 0 on success, and negative number in case of error. + */ +int mnt_context_post_umount(mnt_context *cxt) +{ + int rc = 0; + + if (!cxt) + return -EINVAL; + if (cxt->syscall_errno || cxt->helper) + return 0; +/* TODO + if (cxt->flags & MNT_FL_LOOPDEL) + rc = mnt_loopdev_clean(mnt_fs_get_source(cxt->fs)); +*/ + if (cxt->flags & MNT_FL_NOMTAB) + return rc; + + if ((cxt->flags & MNT_FL_RDONLY_UMOUNT) && + (cxt->mountflags & (MS_RDONLY | MS_REMOUNT))) { + /* + * refresh update to handle remount to read-only + */ + rc = mnt_context_prepare_update(cxt, MNT_ACT_MOUNT); + if (rc) + return rc; + } + + /* + * Update /etc/mtab or /var/run/mount/mountinfo + */ + if (cxt->update && !mnt_update_is_pointless(cxt->update)) { + rc = mnt_update_file(cxt->update); + if (!rc) + return rc; + } + return rc; +} + +/** + * mnt_context_umount_strerror + * @cxt: mount context + * @buf: buffer + * @bufsiz: size of the buffer + * + * Returns: 0 or negative number in case of error. + */ +int mnt_context_umount_strerror(mnt_context *cxt, char *buf, size_t bufsiz) +{ + /* TODO: based on cxt->syscall_errno or cxt->helper_status */ + return 0; +} diff --git a/shlibs/mount/src/mount.h.in b/shlibs/mount/src/mount.h.in index 43f81080..f4b4e6ad 100644 --- a/shlibs/mount/src/mount.h.in +++ b/shlibs/mount/src/mount.h.in @@ -326,6 +326,7 @@ extern int mnt_context_disable_lock(mnt_context *cxt, int disable); extern int mnt_context_enable_force(mnt_context *cxt, int enable); extern int mnt_context_enable_verbose(mnt_context *cxt, int enable); extern int mnt_context_enable_loopdel(mnt_context *cxt, int enable); +extern int mnt_context_enable_rdonly_umount(mnt_context *cxt, int enable); extern int mnt_context_set_fs(mnt_context *cxt, mnt_fs *fs); extern int mnt_context_set_source(mnt_context *cxt, const char *source); extern int mnt_context_set_target(mnt_context *cxt, const char *target); @@ -335,6 +336,8 @@ extern int mnt_context_append_optstr(mnt_context *cxt, const char *optstr); extern int mnt_context_set_fstype_pattern(mnt_context *cxt, const char *pattern); extern int mnt_context_set_optstr_pattern(mnt_context *cxt, const char *pattern); extern int mnt_context_set_fstab(mnt_context *cxt, mnt_tab *tb); +extern int mnt_context_get_fstab(mnt_context *cxt, mnt_tab **tb); +extern int mnt_context_get_mtab(mnt_context *cxt, mnt_tab **tb); extern int mnt_context_set_cache(mnt_context *cxt, mnt_cache *cache); extern mnt_cache *mnt_context_get_cache(mnt_context *cxt); extern mnt_lock *mnt_context_get_lock(mnt_context *cxt); diff --git a/shlibs/mount/src/mountP.h b/shlibs/mount/src/mountP.h index 96490b16..9f05cf55 100644 --- a/shlibs/mount/src/mountP.h +++ b/shlibs/mount/src/mountP.h @@ -250,6 +250,7 @@ struct _mnt_context #define MNT_FL_FORCE (1 << 8) #define MNT_FL_NOCANONICALIZE (1 << 9) #define MNT_FL_NOLOCK (1 << 10) /* don't lock mtab file */ +#define MNT_FL_RDONLY_UMOUNT (1 << 11) /* remount,ro after EBUSY umount(2) */ #define MNT_FL_EXTERN_FS (1 << 15) /* cxt->fs is not private */ #define MNT_FL_EXTERN_FSTAB (1 << 16) /* cxt->fstab is not private */