示例#1
0
/**
 * mnt_context_next_umount:
 * @cxt: context
 * @itr: iterator
 * @fs: returns the current filesystem
 * @mntrc: returns the return code from mnt_context_umount()
 * @ignored: returns 1 for not matching
 *
 * This function tries to umount the next filesystem from mtab (as returned by
 * mnt_context_get_mtab()).
 *
 * You can filter out filesystems by:
 *	mnt_context_set_options_pattern() to simulate umount -a -O pattern
 *	mnt_context_set_fstype_pattern()  to simulate umount -a -t pattern
 *
 * If the filesystem is not mounted or does not match the defined criteria,
 * then the function mnt_context_next_umount() returns zero, but the @ignored is
 * non-zero. Note that the root filesystem is always ignored.
 *
 * If umount(2) syscall or umount.type helper failed, then the
 * mnt_context_next_umount() function returns zero, but the @mntrc is non-zero.
 * Use also mnt_context_get_status() to check if the filesystem was
 * successfully umounted.
 *
 * Returns: 0 on success,
 *         <0 in case of error (!= umount(2) errors)
 *          1 at the end of the list.
 */
int mnt_context_next_umount(struct libmnt_context *cxt,
			   struct libmnt_iter *itr,
			   struct libmnt_fs **fs,
			   int *mntrc,
			   int *ignored)
{
	struct libmnt_table *mtab;
	const char *tgt;
	int rc;

	if (ignored)
		*ignored = 0;
	if (mntrc)
		*mntrc = 0;

	if (!cxt || !fs || !itr)
		return -EINVAL;

	rc = mnt_context_get_mtab(cxt, &mtab);
	cxt->mtab = NULL;		/* do not reset mtab */
	mnt_reset_context(cxt);
	cxt->mtab = mtab;

	if (rc)
		return rc;

	do {
		rc = mnt_table_next_fs(mtab, itr, fs);
		if (rc != 0)
			return rc;	/* no more filesystems (or error) */

		tgt = mnt_fs_get_target(*fs);
	} while (!tgt);

	DBG(CXT, ul_debugobj(cxt, "next-umount: trying %s [fstype: %s, t-pattern: %s, options: %s, O-pattern: %s]", tgt,
				 mnt_fs_get_fstype(*fs), cxt->fstype_pattern, mnt_fs_get_options(*fs), cxt->optstr_pattern));

	/* ignore filesystems which don't match options patterns */
	if ((cxt->fstype_pattern && !mnt_fs_match_fstype(*fs,
					cxt->fstype_pattern)) ||

	/* ignore filesystems which don't match type patterns */
	   (cxt->optstr_pattern && !mnt_fs_match_options(*fs,
					cxt->optstr_pattern))) {
		if (ignored)
			*ignored = 1;

		DBG(CXT, ul_debugobj(cxt, "next-umount: not-match"));
		return 0;
	}

	rc = mnt_context_set_fs(cxt, *fs);
	if (rc)
		return rc;
	rc = mnt_context_umount(cxt);
	if (mntrc)
		*mntrc = rc;
	return 0;
}
示例#2
0
/* Check, if there already exists a mounted loop device on the mountpoint node
 * with the same parameters.
 */
static int is_mounted_same_loopfile(struct libmnt_context *cxt,
				    const char *target,
				    const char *backing_file,
				    uint64_t offset)
{
	struct libmnt_table *tb;
	struct libmnt_iter itr;
	struct libmnt_fs *fs;
	struct libmnt_cache *cache;

	assert(cxt);
	assert(cxt->fs);
	assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));

	if (!target || !backing_file || mnt_context_get_mtab(cxt, &tb))
		return 0;

	DBG(CXT, mnt_debug_h(cxt, "checking if %s mounted on %s",
				backing_file, target));

	cache = mnt_context_get_cache(cxt);
	mnt_reset_iter(&itr, MNT_ITER_BACKWARD);

	/* Search for mountpoint node in mtab, procceed if any of these has the
	 * loop option set or the device is a loop device
	 */
	while (mnt_table_next_fs(tb, &itr, &fs) == 0) {
		const char *src = mnt_fs_get_source(fs);
		const char *opts = mnt_fs_get_user_options(fs);
		char *val;
		size_t len;
		int res = 0;

		if (!src || !mnt_fs_match_target(fs, target, cache))
			continue;

		if (strncmp(src, "/dev/loop", 9) == 0) {
			res = loopdev_is_used((char *) src, backing_file,
					offset, LOOPDEV_FL_OFFSET);

		} else if (opts && (cxt->user_mountflags & MNT_MS_LOOP) &&
		    mnt_optstr_get_option(opts, "loop", &val, &len) == 0 && val) {

			val = strndup(val, len);
			res = loopdev_is_used((char *) val, backing_file,
					offset, LOOPDEV_FL_OFFSET);
			free(val);
		}

		if (res) {
			DBG(CXT, mnt_debug_h(cxt, "%s already mounted", backing_file));
			return 1;
		}
	}

	return 0;
}
示例#3
0
static int get_debugfs(char **path)
{
	struct libmnt_context *cxt;
	struct libmnt_table *tb;
	struct libmnt_iter *itr = NULL;
	struct libmnt_fs *fs;
	int found = 0, ret;

	cxt = mnt_new_context();
	if (!cxt)
		err(EXIT_FAILURE, "libmount context allocation failed");

	itr = mnt_new_iter(MNT_ITER_FORWARD);
	if (!itr)
		err(EXIT_FAILURE, "failed to initialize libmount iterator");

	if (mnt_context_get_mtab(cxt, &tb))
		err(EXIT_FAILURE, "failed to read mtab");

	while (mnt_table_next_fs(tb, itr, &fs) == 0) {
		const char *type = mnt_fs_get_fstype(fs);

		if (!strcmp(type, "debugfs")) {
			found = 1;
			break;
		}
	}
	if (found) {
		ret = asprintf(path, "%s/gpio", mnt_fs_get_target(fs));
		if (ret < 0)
			err(EXIT_FAILURE, "failed to format string");
	}

	mnt_free_iter(itr);
	mnt_free_context(cxt);

	if (!found)
		return -1;

	return 0;
}
示例#4
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;
}
示例#5
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;
}
示例#6
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;
}