Beispiel #1
0
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;
}
Beispiel #2
0
/**
 * 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;
}
Beispiel #3
0
/**
 * 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;
}
Beispiel #4
0
/*
 * 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;
}
Beispiel #5
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;
}