static int do_mount_by_pattern(struct libmnt_context *cxt, const char *pattern) { int neg = pattern && strncmp(pattern, "no", 2) == 0; int rc = -EINVAL; char **filesystems, **fp; assert(cxt); assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED)); if (!neg && pattern) { /* * try all types from the list */ char *p, *p0; DBG(CXT, mnt_debug_h(cxt, "trying to mount by FS pattern list")); p0 = p = strdup(pattern); if (!p) return -ENOMEM; do { char *end = strchr(p, ','); if (end) *end = '\0'; rc = do_mount(cxt, p); p = end ? end + 1 : NULL; } while (!mnt_context_get_status(cxt) && p); free(p0); if (mnt_context_get_status(cxt)) return rc; } /* * try /etc/filesystems and /proc/filesystems */ DBG(CXT, mnt_debug_h(cxt, "trying to mount by filesystems lists")); rc = mnt_get_filesystems(&filesystems, neg ? pattern : NULL); if (rc) return rc; for (fp = filesystems; *fp; fp++) { rc = do_mount(cxt, *fp); if (mnt_context_get_status(cxt)) break; if (mnt_context_get_syscall_errno(cxt) != EINVAL) break; } mnt_free_filesystems(filesystems); return rc; }
/** * mnt_context_do_mount * @cxt: context * * Call mount(2) or mount.type helper. Unnecessary for mnt_context_mount(). * * Note that this function could be called only once. If you want to mount * another source or target than you have to call mnt_reset_context(). * * If you want to call mount(2) for the same source and target with a diffrent * mount flags or fstype then call mnt_context_reset_status() and then try * again mnt_context_do_mount(). * * WARNING: non-zero return code does not mean that mount(2) syscall or * mount.type helper wasn't successfully called. * * Check mnt_context_get_status() after error! * * Returns: 0 on success; * >0 in case of mount(2) error (returns syscall errno), * <0 in case of other errors. */ int mnt_context_do_mount(struct libmnt_context *cxt) { const char *type; int res; assert(cxt); assert(cxt->fs); assert(cxt->helper_exec_status == 1); assert(cxt->syscall_status == 1); assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED)); assert((cxt->flags & MNT_FL_PREPARED)); assert((cxt->action == MNT_ACT_MOUNT)); DBG(CXT, mnt_debug_h(cxt, "mount: do mount")); if (!(cxt->flags & MNT_FL_MOUNTDATA)) cxt->mountdata = (char *) mnt_fs_get_fs_options(cxt->fs); type = mnt_fs_get_fstype(cxt->fs); if (type) res = do_mount(cxt, NULL); else res = do_mount_by_pattern(cxt, cxt->fstype_pattern); if (mnt_context_get_status(cxt) && !mnt_context_is_fake(cxt) && !cxt->helper) { /* * Mounted by mount(2), do some post-mount checks * * Kernel allows to use MS_RDONLY for bind mounts, but the * read-only request could be silently ignored. Check it to * avoid 'ro' in mtab and 'rw' in /proc/mounts. */ if ((cxt->mountflags & MS_BIND) && (cxt->mountflags & MS_RDONLY) && !mnt_is_readonly(mnt_context_get_target(cxt))) mnt_context_set_mflags(cxt, cxt->mountflags & ~MS_RDONLY); /* Kernel can silently add MS_RDONLY flag when mounting file * system that does not have write support. Check this to avoid * 'ro' in /proc/mounts and 'rw' in mtab. */ if (!(cxt->mountflags & (MS_RDONLY | MS_PROPAGATION | MS_MOVE)) && mnt_is_readonly(mnt_context_get_target(cxt))) mnt_context_set_mflags(cxt, cxt->mountflags | MS_RDONLY); } return res; }
/** * mnt_context_do_umount: * @cxt: mount context * * Umount filesystem by umount(2) or fork()+exec(/sbin/umount.type). * Unnecessary for mnt_context_umount(). * * See also mnt_context_disable_helpers(). * * WARNING: non-zero return code does not mean that umount(2) syscall or * umount.type helper wasn't successfully called. * * Check mnt_context_get_status() after error! * * Returns: 0 on success; * >0 in case of umount(2) error (returns syscall errno), * <0 in case of other errors. */ int mnt_context_do_umount(struct libmnt_context *cxt) { int rc; assert(cxt); assert(cxt->fs); assert(cxt->helper_exec_status == 1); assert(cxt->syscall_status == 1); assert((cxt->flags & MNT_FL_PREPARED)); assert((cxt->action == MNT_ACT_UMOUNT)); assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED)); rc = do_umount(cxt); if (rc) return rc; if (mnt_context_get_status(cxt) && !mnt_context_is_fake(cxt)) { /* * Umounted, do some post-umount operations * - remove loopdev * - refresh in-memory mtab stuff if remount rather than * umount has been performed */ if (mnt_context_is_loopdel(cxt) && !(cxt->mountflags & MS_REMOUNT)) rc = mnt_context_delete_loopdev(cxt); if (!mnt_context_is_nomtab(cxt) && mnt_context_get_status(cxt) && !cxt->helper && mnt_context_is_rdonly_umount(cxt) && (cxt->mountflags & MS_REMOUNT)) { /* use "remount" instead of "umount" in /etc/mtab */ if (!rc && cxt->update && cxt->mtab_writable) rc = mnt_update_set_fs(cxt->update, cxt->mountflags, NULL, cxt->fs); } } return rc; }
/* * Clears loopdev stuff in context, should be called after * failed or successful mount(2). */ int mnt_context_clear_loopdev(struct libmnt_context *cxt) { assert(cxt); if (mnt_context_get_status(cxt) == 0 && (cxt->flags & MNT_FL_LOOPDEV_READY)) { /* * mount(2) failed, delete loopdev */ mnt_context_delete_loopdev(cxt); } else if (cxt->loopdev_fd > -1) { /* * mount(2) success, close the device */ DBG(LOOP, ul_debugobj(cxt, "closing FD")); close(cxt->loopdev_fd); } cxt->loopdev_fd = -1; return 0; }
static int umount_main(struct libmnt_context *cxt, int argc, char **argv) { int rc, c; char *spec = NULL, *opts = NULL; static const struct option longopts[] = { { "force", 0, 0, 'f' }, { "help", 0, 0, 'h' }, { "no-mtab", 0, 0, 'n' }, { "verbose", 0, 0, 'v' }, { "read-only", 0, 0, 'r' }, { "lazy", 0, 0, 'l' }, { "types", 1, 0, 't' }, { NULL, 0, 0, 0 } }; mnt_context_init_helper(cxt, MNT_ACT_UMOUNT, 0); while ((c = getopt_long (argc, argv, "fvnrlh", longopts, NULL)) != -1) { rc = mnt_context_helper_setopt(cxt, c, optarg); if (rc == 0) /* valid option */ continue; if (rc < 0) /* error (probably ENOMEM) */ goto err; /* rc==1 means unknow option */ umount_usage(); return EX_USAGE; } if (optind < argc) spec = argv[optind++]; if (!spec || (*spec != '/' && strchr(spec,':') == NULL)) { nfs_error(_("%s: no mount point provided"), progname); return EX_USAGE; } if (mnt_context_set_target(cxt, spec)) goto err; if (mnt_context_set_fstype_pattern(cxt, "nfs,nfs4")) /* restrict filesystems */ goto err; /* read mtab/fstab, evaluate permissions, etc. */ rc = mnt_context_prepare_umount(cxt); if (rc) { nfs_error(_("%s: failed to prepare umount: %s\n"), progname, strerror(-rc)); goto err; } opts = retrieve_mount_options(mnt_context_get_fs(cxt)); if (!mnt_context_is_lazy(cxt)) { if (opts) { /* we have full FS description (e.g. from mtab or /proc) */ switch (is_vers4(cxt)) { case 0: /* We ignore the error from nfs_umount23. * If the actual umount succeeds (in del_mtab), * we don't want to signal an error, as that * could cause /sbin/mount to retry! */ nfs_umount23(mnt_context_get_source(cxt), opts); break; case 1: /* unknown */ break; default: /* error */ goto err; } } else /* strange, no entry in mtab or /proc not mounted */ nfs_umount23(spec, "tcp,v3"); } rc = mnt_context_do_umount(cxt); /* call umount(2) syscall */ mnt_context_finalize_mount(cxt); /* mtab update */ if (rc && !mnt_context_get_status(cxt)) { /* mnt_context_do_umount() returns errno if umount(2) failed */ umount_error(rc, spec); goto err; } free(opts); return EX_SUCCESS; err: free(opts); return EX_FAIL; }