Esempio n. 1
0
/**
 * mnt_context_find_umount_fs:
 * @cxt: mount context
 * @tgt: mountpoint, device, ...
 * @pfs: returns point to filesystem
 *
 * Returns: 0 on success, <0 on error, 1 if target filesystem not found
 */
int mnt_context_find_umount_fs(struct libmnt_context *cxt,
			       const char *tgt,
			       struct libmnt_fs **pfs)
{
	int rc;
	struct libmnt_table *mtab = NULL;
	struct libmnt_fs *fs;
	char *loopdev = NULL;

	if (pfs)
		*pfs = NULL;

	if (!cxt || !tgt || !pfs)
		return -EINVAL;

	DBG(CXT, ul_debugobj(cxt, "umount: lookup FS for '%s'", tgt));

	if (!*tgt)
		return 1; /* empty string is not an error */

	/*
	 * The mount table may be huge, and on systems with utab we have to merge
	 * userspace mount options into /proc/self/mountinfo. This all is
	 * expensive. The tab filter allows to filter out entries, then
	 * a mount table and utab are very tiny files.
	 *
	 * *but*... the filter uses mnt_fs_streq_{target,srcpath} functions
	 * where LABEL, UUID or symlinks are canonicalized. It means that
	 * it's usable only for canonicalized stuff (e.g. kernel mountinfo).
	 */
	if (!mnt_context_mtab_writable(cxt) && *tgt == '/' &&
	    !mnt_context_is_force(cxt) && !mnt_context_is_lazy(cxt))
		rc = mnt_context_get_mtab_for_target(cxt, &mtab, tgt);
	else
		rc = mnt_context_get_mtab(cxt, &mtab);

	if (rc) {
		DBG(CXT, ul_debugobj(cxt, "umount: failed to read mtab"));
		return rc;
	}

	if (mnt_table_get_nents(mtab) == 0) {
		DBG(CXT, ul_debugobj(cxt, "umount: mtab empty"));
		return 1;
	}

try_loopdev:
	fs = mnt_table_find_target(mtab, tgt, MNT_ITER_BACKWARD);
	if (!fs && mnt_context_is_swapmatch(cxt)) {
		/*
		 * Maybe the option is source rather than target (sometimes
		 * people use e.g. "umount /dev/sda1")
		 */
		fs = mnt_table_find_source(mtab, tgt, MNT_ITER_BACKWARD);

		if (fs) {
			struct libmnt_fs *fs1 = mnt_table_find_target(mtab,
							mnt_fs_get_target(fs),
							MNT_ITER_BACKWARD);
			if (!fs1) {
				DBG(CXT, ul_debugobj(cxt, "mtab is broken?!?!"));
				rc = -EINVAL;
				goto err;
			}
			if (fs != fs1) {
				/* Something was stacked over `file' on the
				 * same mount point. */
				DBG(CXT, ul_debugobj(cxt,
						"umount: %s: %s is mounted "
						"over it on the same point",
						tgt, mnt_fs_get_source(fs1)));
				rc = -EINVAL;
				goto err;
			}
		}
	}

	if (!fs && !loopdev && mnt_context_is_swapmatch(cxt)) {
		/*
		 * Maybe the option is /path/file.img, try to convert to /dev/loopN
		 */
		struct stat st;

		if (mnt_stat_mountpoint(tgt, &st) == 0 && S_ISREG(st.st_mode)) {
			int count;
			struct libmnt_cache *cache = mnt_context_get_cache(cxt);
			const char *bf = cache ? mnt_resolve_path(tgt, cache) : tgt;

			count = loopdev_count_by_backing_file(bf, &loopdev);
			if (count == 1) {
				DBG(CXT, ul_debugobj(cxt,
					"umount: %s --> %s (retry)", tgt, loopdev));
				tgt = loopdev;
				goto try_loopdev;

			} else if (count > 1)
				DBG(CXT, ul_debugobj(cxt,
					"umount: warning: %s is associated "
					"with more than one loopdev", tgt));
		}
	}

	if (pfs)
		*pfs = fs;
	free(loopdev);

	DBG(CXT, ul_debugobj(cxt, "umount fs: %s", fs ? mnt_fs_get_target(fs) :
							"<not found>"));
	return fs ? 0 : 1;
err:
	free(loopdev);
	return rc;
}
Esempio n. 2
0
static int lookup_umount_fs(struct libmnt_context *cxt)
{
	int rc, loopdev = 0;
	const char *tgt;
	struct libmnt_table *mtab = NULL;
	struct libmnt_fs *fs;
	struct libmnt_cache *cache = NULL;
	char *cn_tgt = NULL;

	assert(cxt);
	assert(cxt->fs);

	DBG(CXT, mnt_debug_h(cxt, "umount: lookup FS"));

	tgt = mnt_fs_get_target(cxt->fs);
	if (!tgt) {
		DBG(CXT, mnt_debug_h(cxt, "umount: undefined target"));
		return -EINVAL;
	}

	/*
	 * The mtab file maybe huge and on systems with utab we have to merge
	 * userspace mount options into /proc/self/mountinfo. This all is
	 * expensive. The mtab filter allows to filter out entries, then
	 * mtab and utab are very tiny files.
	 *
	 * *but*... the filter uses mnt_fs_streq_{target,srcpath} functions
	 * where LABEL, UUID or symlinks are to canonicalized. It means that
	 * it's usable only for canonicalized stuff (e.g. kernel mountinfo).
	 */
	if (!cxt->mtab_writable	&& *tgt == '/' &&
	    !mnt_context_is_force(cxt) && !mnt_context_is_lazy(cxt)) {

		struct stat st;

		if (stat(tgt, &st) == 0 && S_ISDIR(st.st_mode)) {
			/* we'll canonicalized /proc/self/mountinfo */
			cache = mnt_context_get_cache(cxt);
			cn_tgt = mnt_resolve_path(tgt, cache);
			if (cn_tgt)
				mnt_context_set_tabfilter(cxt, mtab_filter, cn_tgt);
		}
	}
	rc = mnt_context_get_mtab(cxt, &mtab);

	if (cn_tgt) {
		mnt_context_set_tabfilter(cxt, NULL, NULL);
		if (!cache)
			free(cn_tgt);
	}

	if (rc) {
		DBG(CXT, mnt_debug_h(cxt, "umount: failed to read mtab"));
		return rc;
	}

try_loopdev:
	fs = mnt_table_find_target(mtab, tgt, MNT_ITER_BACKWARD);
	if (!fs && mnt_context_is_swapmatch(cxt)) {
		/*
		 * Maybe the option is source rather than target (sometimes
		 * people use e.g. "umount /dev/sda1")
		 */
		fs = mnt_table_find_source(mtab, tgt, MNT_ITER_BACKWARD);

		if (fs) {
			struct libmnt_fs *fs1 = mnt_table_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 && !loopdev && mnt_context_is_swapmatch(cxt)) {
		/*
		 * Maybe the option is /path/file.img, try to convert to /dev/loopN
		 */
		struct stat st;

		if (stat(tgt, &st) == 0 && S_ISREG(st.st_mode)) {
			char *dev = NULL;
			int count = loopdev_count_by_backing_file(tgt, &dev);

			if (count == 1) {
				DBG(CXT, mnt_debug_h(cxt,
					"umount: %s --> %s (retry)", tgt, dev));
				mnt_fs_set_source(cxt->fs, tgt);
				mnt_fs_set_target(cxt->fs, dev);
				free(dev);
				tgt = mnt_fs_get_target(cxt->fs);

				loopdev = 1;		/* to avoid endless loop */
				goto try_loopdev;

			} else if (count > 1)
				DBG(CXT, mnt_debug_h(cxt,
					"umount: warning: %s is associated "
					"with more than one loopdev", tgt));
		}
	}

	if (!fs) {
		DBG(CXT, mnt_debug_h(cxt, "umount: cannot find %s in mtab", tgt));
		return 0;
	}

	if (fs != cxt->fs) {
		/* copy from mtab to our FS description
		 */
		mnt_fs_set_source(cxt->fs, NULL);
		mnt_fs_set_target(cxt->fs, NULL);

		if (!mnt_copy_fs(cxt->fs, fs)) {
			DBG(CXT, mnt_debug_h(cxt, "umount: failed to copy FS"));
			return -errno;
		}
		DBG(CXT, mnt_debug_h(cxt, "umount: mtab applied"));
	}

	cxt->flags |= MNT_FL_TAB_APPLIED;
	return rc;
}
Esempio n. 3
0
static int lookup_umount_fs(struct libmnt_context *cxt)
{
	int rc, loopdev = 0;
	const char *tgt;
	struct libmnt_table *mtab = NULL;
	struct libmnt_fs *fs;

	assert(cxt);
	assert(cxt->fs);

	DBG(CXT, mnt_debug_h(cxt, "umount: lookup 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;
	}

try_loopdev:
	fs = mnt_table_find_target(mtab, tgt, MNT_ITER_BACKWARD);
	if (!fs) {
		/* maybe the option is source rather than target (mountpoint) */
		fs = mnt_table_find_source(mtab, tgt, MNT_ITER_BACKWARD);

		if (fs) {
			struct libmnt_fs *fs1 = mnt_table_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 && !loopdev) {
		/*
		 * Maybe target is /path/file.img, try to convert to /dev/loopN
		 */
		struct stat st;

		if (stat(tgt, &st) == 0 && S_ISREG(st.st_mode)) {
			char *dev = NULL;
			int count = loopdev_count_by_backing_file(tgt, &dev);

			if (count == 1) {
				DBG(CXT, mnt_debug_h(cxt,
					"umount: %s --> %s (retry)", tgt, dev));
				mnt_fs_set_source(cxt->fs, tgt);
				mnt_fs_set_target(cxt->fs, dev);
				free(dev);
				tgt = mnt_fs_get_target(cxt->fs);

				loopdev = 1;		/* to avoid endless loop */
				goto try_loopdev;

			} else if (count > 1)
				DBG(CXT, mnt_debug_h(cxt,
					"umount: warning: %s is associated "
					"with more than one loodev", tgt));
		}
	}

	if (!fs) {
		DBG(CXT, mnt_debug_h(cxt, "umount: cannot find %s in mtab", tgt));
		return 0;
	}

	if (fs != cxt->fs) {
		/* copy from mtab to our FS description
		 */
		mnt_fs_set_source(cxt->fs, NULL);
		mnt_fs_set_target(cxt->fs, NULL);

		if (!mnt_copy_fs(cxt->fs, fs)) {
			DBG(CXT, mnt_debug_h(cxt, "umount: failed to copy FS"));
			return -errno;
		}
		DBG(CXT, mnt_debug_h(cxt, "umount: mtab applied"));
	}

	cxt->flags |= MNT_FL_TAB_APPLIED;
	return rc;
}