Пример #1
0
/**
 * mnt_table_get_root_fs:
 * @tb: mountinfo file (/proc/self/mountinfo)
 * @root: returns pointer to the root filesystem (/)
 *
 * The function uses parent ID from mountinfo file to determine root filesystem
 * (the filesystem with the smallest ID). The function is designed mostly for
 * applications where is necessary to sort mountpoints by IDs to get the tree
 * of the mountpoints (e.g. findmnt default output).
 *
 * If you're not sure than use
 *
 *	mnt_table_find_target(tb, "/", MNT_ITER_BACKWARD);
 *
 * this is more robust and usable for arbitrary tab file (including fstab).
 *
 * Returns: 0 on success or less then zero case of error.
 */
int mnt_table_get_root_fs(struct libmnt_table *tb, struct libmnt_fs **root)
{
	struct libmnt_iter itr;
	struct libmnt_fs *fs;
	int root_id = 0;

	assert(tb);
	assert(root);

	if (!tb || !root)
		return -EINVAL;

	DBG(TAB, mnt_debug_h(tb, "lookup root fs"));

	mnt_reset_iter(&itr, MNT_ITER_FORWARD);
	while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
		int id = mnt_fs_get_parent_id(fs);
		if (!id)
			break;		/* @tab is not mountinfo file? */

		if (!*root || id < root_id) {
			*root = fs;
			root_id = id;
		}
	}

	return root_id ? 0 : -EINVAL;
}
Пример #2
0
/**
 * mnt_table_get_root_fs:
 * @tb: mountinfo file (/proc/self/mountinfo)
 * @root: returns pointer to the root filesystem (/)
 *
 * The function uses the parent ID from the mountinfo file to determine the root filesystem
 * (the filesystem with the smallest ID). The function is designed mostly for
 * applications where it is necessary to sort mountpoints by IDs to get the tree
 * of the mountpoints (e.g. findmnt default output).
 *
 * If you're not sure, then use
 *
 *	mnt_table_find_target(tb, "/", MNT_ITER_BACKWARD);
 *
 * this is more robust and usable for arbitrary tab files (including fstab).
 *
 * Returns: 0 on success or negative number in case of error.
 */
int mnt_table_get_root_fs(struct libmnt_table *tb, struct libmnt_fs **root)
{
	struct libmnt_iter itr;
	struct libmnt_fs *fs;
	int root_id = 0;

	assert(tb);
	assert(root);

	if (!tb || !root || !is_mountinfo(tb))
		return -EINVAL;

	DBG(TAB, ul_debugobj(tb, "lookup root fs"));

	*root = NULL;

	mnt_reset_iter(&itr, MNT_ITER_FORWARD);
	while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
		int id = mnt_fs_get_parent_id(fs);

		if (!*root || id < root_id) {
			*root = fs;
			root_id = id;
		}
	}

	return *root ? 0 : -EINVAL;
}
Пример #3
0
/**
 * mnt_table_parse_mtab:
 * @tb: table
 * @filename: overwrites default (/etc/mtab or $LIBMOUNT_MTAB) or NULL
 *
 * This function parses /etc/mtab or /proc/self/mountinfo +
 * /run/mount/utabs or /proc/mounts.
 *
 * See also mnt_table_set_parser_errcb().
 *
 * Returns: 0 on success or negative number in case of error.
 */
int mnt_table_parse_mtab(struct libmnt_table *tb, const char *filename)
{
	int rc;
	const char *utab = NULL;
	struct libmnt_table *u_tb;

	assert(tb);

	if (mnt_has_regular_mtab(&filename, NULL)) {

		DBG(TAB, mnt_debug_h(tb, "force %s usage", filename));

		rc = mnt_table_parse_file(tb, filename);
		if (!rc)
			return 0;
		filename = NULL;	/* failed */
	}

	/*
	 * useless /etc/mtab
	 * -- read kernel information from /proc/self/mountinfo
	 */
	tb->fmt = MNT_FMT_MOUNTINFO;
	rc = mnt_table_parse_file(tb, _PATH_PROC_MOUNTINFO);
	if (rc) {
		/* hmm, old kernel? ...try /proc/mounts */
		tb->fmt = MNT_FMT_MTAB;
		return mnt_table_parse_file(tb, _PATH_PROC_MOUNTS);
	}

	if (mnt_table_get_nents(tb) == 0)
		return 0;			/* empty, ignore utab */
	/*
	 * try to read the user specific information from /run/mount/utabs
	 */
	utab = mnt_get_utab_path();
	if (!utab || is_file_empty(utab))
		return 0;

	u_tb = mnt_new_table();
	if (!u_tb)
		return -ENOMEM;

	u_tb->fmt = MNT_FMT_UTAB;
	mnt_table_set_parser_fltrcb(u_tb, tb->fltrcb, tb->fltrcb_data);

	if (mnt_table_parse_file(u_tb, utab) == 0) {
		struct libmnt_fs *u_fs;
		struct libmnt_iter itr;

		mnt_reset_iter(&itr, MNT_ITER_BACKWARD);

		/*  merge user options into mountinfo from the kernel */
		while(mnt_table_next_fs(u_tb, &itr, &u_fs) == 0)
			mnt_table_merge_user_fs(tb, u_fs);
	}

	mnt_unref_table(u_tb);
	return 0;
}
Пример #4
0
static int update_table(struct libmnt_update *upd, struct libmnt_table *tb)
{
	FILE *f;
	int rc, fd;
	char *uq = NULL;

	if (!tb || !upd->filename)
		return -EINVAL;

	DBG(UPDATE, mnt_debug_h(upd, "%s: updating", upd->filename));

	fd = mnt_open_uniq_filename(upd->filename, &uq);
	if (fd < 0)
		return fd;	/* error */

	f = fdopen(fd, "w");
	if (f) {
		struct stat st;
		struct libmnt_iter itr;
		struct libmnt_fs *fs;
		int fd;

		mnt_reset_iter(&itr, MNT_ITER_FORWARD);
		while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
			if (upd->userspace_only)
				rc = fprintf_utab_fs(f, fs);
			else
				rc = fprintf_mtab_fs(f, fs);
			if (rc) {
				DBG(UPDATE, mnt_debug_h(upd,
					"%s: write entry failed: %m", uq));
				goto leave;
			}
		}

		if (fflush(f) != 0) {
			rc = -errno;
			DBG(UPDATE, mnt_debug_h(upd, "%s: fflush failed: %m", uq));
			goto leave;
		}

		fd = fileno(f);
		rc = fchmod(fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) ? -errno : 0;

		if (!rc && stat(upd->filename, &st) == 0)
			/* Copy uid/gid from the present file before renaming. */
			rc = fchown(fd, st.st_uid, st.st_gid) ? -errno : 0;

		fclose(f);
		rc = rename(uq, upd->filename) ? -errno : 0;
	} else {
		rc = -errno;
		close(fd);
	}

leave:
	unlink(uq);	/* be paranoid */
	free(uq);
	return rc;
}
Пример #5
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;
}
Пример #6
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;
}
Пример #7
0
/**
 * mnt_table_next_child_fs:
 * @tb: mountinfo file (/proc/self/mountinfo)
 * @itr: iterator
 * @parent: parental FS
 * @chld: returns the next child filesystem
 *
 * Note that filesystems are returned in the order how was mounted (according to
 * IDs in /proc/self/mountinfo).
 *
 * Returns: 0 on success, negative number in case of error or 1 at end of list.
 */
int mnt_table_next_child_fs(struct libmnt_table *tb, struct libmnt_iter *itr,
			struct libmnt_fs *parent, struct libmnt_fs **chld)
{
	struct libmnt_fs *fs;
	int parent_id, lastchld_id = 0, chld_id = 0;

	if (!tb || !itr || !parent)
		return -EINVAL;

	DBG(TAB, mnt_debug_h(tb, "lookup next child of '%s'",
				mnt_fs_get_target(parent)));

	parent_id = mnt_fs_get_id(parent);
	if (!parent_id)
		return -EINVAL;

	/* get ID of the previously returned child */
	if (itr->head && itr->p != itr->head) {
		MNT_ITER_ITERATE(itr, fs, struct libmnt_fs, ents);
		lastchld_id = mnt_fs_get_id(fs);
	}

	*chld = NULL;

	mnt_reset_iter(itr, MNT_ITER_FORWARD);
	while(mnt_table_next_fs(tb, itr, &fs) == 0) {
		int id;

		if (mnt_fs_get_parent_id(fs) != parent_id)
			continue;

		id = mnt_fs_get_id(fs);

		/* avoid infinite loop. This only happens in rare cases
		 * such as in early userspace when the rootfs is its own parent */
		if (id == parent_id)
			continue;

		if ((!lastchld_id || id > lastchld_id) &&
		    (!*chld || id < chld_id)) {
			*chld = fs;
			chld_id = id;
		}
	}

	if (!chld_id)
		return 1;	/* end of iterator */

	/* set the iterator to the @chld for the next call */
	mnt_table_set_iter(tb, itr, *chld);

	return 0;
}
Пример #8
0
/**
 * mnt_table_parse_mtab:
 * @tb: table
 * @filename: overwrites default (/etc/mtab or $LIBMOUNT_MTAB) or NULL
 *
 * This function parses /etc/mtab or /proc/self/mountinfo +
 * /run/mount/utabs or /proc/mounts.
 *
 * See also mnt_table_set_parser_errcb().
 *
 * Returns: 0 on success or negative number in case of error.
 */
int mnt_table_parse_mtab(struct libmnt_table *tb, const char *filename)
{
	int rc;
	const char *utab = NULL;

	if (mnt_has_regular_mtab(&filename, NULL)) {

		DBG(TAB, mnt_debug_h(tb, "force %s usage", filename));

		rc = mnt_table_parse_file(tb, filename);
		if (!rc)
			return 0;
		filename = NULL;	/* failed */
	}

	/*
	 * useless /etc/mtab
	 * -- read kernel information from /proc/self/mountinfo
	 */
	tb->fmt = MNT_FMT_MOUNTINFO;
	rc = mnt_table_parse_file(tb, _PATH_PROC_MOUNTINFO);
	if (rc) {
		/* hmm, old kernel? ...try /proc/mounts */
		tb->fmt = MNT_FMT_MTAB;
		return mnt_table_parse_file(tb, _PATH_PROC_MOUNTS);
	}

	/*
	 * try to read user specific information from /run/mount/utabs
	 */
	utab = mnt_get_utab_path();
	if (utab) {
		struct libmnt_table *u_tb = __mnt_new_table_from_file(utab, MNT_FMT_UTAB);

		if (u_tb) {
			struct libmnt_fs *u_fs;
			struct libmnt_iter itr;

			mnt_reset_iter(&itr, MNT_ITER_BACKWARD);

			/*  merge user options into mountinfo from kernel */
			while(mnt_table_next_fs(u_tb, &itr, &u_fs) == 0)
				mnt_table_merge_user_fs(tb, u_fs);

			mnt_free_table(u_tb);
		}
	}
	return 0;
}
Пример #9
0
/*
 * This function uses @uf to found corresponding record in @tb, then the record
 * from @tb is updated (user specific mount options are added).
 *
 * Note that @uf must contain only user specific mount options instead of
 * VFS options (note that FS options are ignored).
 *
 * Returns modified filesystem (from @tb) or NULL.
 */
static struct libmnt_fs *mnt_table_merge_user_fs(struct libmnt_table *tb, struct libmnt_fs *uf)
{
	struct libmnt_fs *fs;
	struct libmnt_iter itr;
	const char *optstr, *src, *target, *root, *attrs;

	assert(tb);
	assert(uf);
	if (!tb || !uf)
		return NULL;

	DBG(TAB, mnt_debug_h(tb, "merging user fs"));

	src = mnt_fs_get_srcpath(uf);
	target = mnt_fs_get_target(uf);
	optstr = mnt_fs_get_user_options(uf);
	attrs = mnt_fs_get_attributes(uf);
	root = mnt_fs_get_root(uf);

	if (!src || !target || !root || (!attrs && !optstr))
		return NULL;

	mnt_reset_iter(&itr, MNT_ITER_BACKWARD);

	while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
		const char *s = mnt_fs_get_srcpath(fs),
			   *t = mnt_fs_get_target(fs),
			   *r = mnt_fs_get_root(fs);

		if (fs->flags & MNT_FS_MERGED)
			continue;

		if (s && t && r && !strcmp(t, target) &&
		    !strcmp(s, src) && !strcmp(r, root))
			break;
	}

	if (fs) {
		DBG(TAB, mnt_debug_h(tb, "found fs -- appending user optstr"));
		mnt_fs_append_options(fs, optstr);
		mnt_fs_append_attributes(fs, attrs);
		mnt_fs_set_bindsrc(fs, mnt_fs_get_bindsrc(uf));
		fs->flags |= MNT_FS_MERGED;

		DBG(TAB, mnt_debug_h(tb, "found fs:"));
		DBG(TAB, mnt_fs_print_debug(fs, stderr));
	}
	return fs;
}
Пример #10
0
/*
 * This function works like mnt_resolve_tag(), but it's able to read UUiD/LABEL
 * from regular swap files too (according to entries in /proc/swaps). Note that
 * mnt_resolve_tag() and mnt_resolve_spec() works with system visible block
 * devices only.
 */
static char *swapoff_resolve_tag(const char *name, const char *value,
				 struct libmnt_cache *cache)
{
	char *path;
	struct libmnt_table *tb;
	struct libmnt_iter *itr;
	struct libmnt_fs *fs;

	/* this is usual case for block devices (and it's really fast as it uses
	 * udev /dev/disk/by-* symlinks by default */
	path = mnt_resolve_tag(name, value, cache);
	if (path)
		return path;

	/* try regular files from /proc/swaps */
	tb = get_swaps();
	if (!tb)
		return NULL;

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

	while (tb && mnt_table_next_fs(tb, itr, &fs) == 0) {
		blkid_probe pr = NULL;
		const char *src = mnt_fs_get_source(fs);
		const char *type = mnt_fs_get_swaptype(fs);
		const char *data = NULL;

		if (!src || !type || strcmp(type, "file") != 0)
			continue;
		pr = get_swap_prober(src);
		if (!pr)
			continue;
		blkid_probe_lookup_value(pr, name, &data, NULL);
		if (data && strcmp(data, value) == 0)
			path = xstrdup(src);
		blkid_free_probe(pr);
		if (path)
			break;
	}

	mnt_free_iter(itr);
	return path;
}
Пример #11
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;
}
Пример #12
0
/**
 * mnt_resolve_target:
 * @path: "native" path, a potential mount point
 * @cache: cache for results or NULL.
 *
 * Like mnt_resolve_path(), unless @cache is not NULL and
 * mnt_cache_set_targets(cache, mtab) was called: if @path is found in the
 * cached @mtab and the matching entry was provided by the kernel, assume that
 * @path is already canonicalized. By avoiding a call to realpath(2) on
 * known mount points, there is a lower risk of stepping on a stale mount
 * point, which can result in an application freeze. This is also faster in
 * general, as stat(2) on a mount point is slower than on a regular file.
 *
 * Returns: absolute path or NULL in case of error. The result has to be
 * deallocated by free() if @cache is NULL.
 */
char *mnt_resolve_target(const char *path, struct libmnt_cache *cache)
{
	char *p = NULL;

	/*DBG(CACHE, ul_debugobj(cache, "resolving target %s", path));*/

	if (!cache || !cache->mtab)
		return mnt_resolve_path(path, cache);

	p = (char *) cache_find_path(cache, path);
	if (p)
		return p;
	else {
		struct libmnt_iter itr;
		struct libmnt_fs *fs = NULL;

		mnt_reset_iter(&itr, MNT_ITER_BACKWARD);
		while (mnt_table_next_fs(cache->mtab, &itr, &fs) == 0) {

			if (!mnt_fs_is_kernel(fs)
                            || mnt_fs_is_swaparea(fs)
                            || !mnt_fs_streq_target(fs, path))
				continue;

			p = strdup(path);
			if (!p)
				return NULL;	/* ENOMEM */

			if (cache_add_entry(cache, p, p, MNT_CACHE_ISPATH)) {
				free(p);
				return NULL;	/* ENOMEM */
			}
			break;
		}
	}

	if (!p)
		p = canonicalize_path_and_cache(path, cache);
	return p;
}
Пример #13
0
/* Check if there is something important in the utab file. The parsed utab is
 * stored in context->utab and deallocated by mnt_free_context().
 *
 * This function exists to avoid (if possible) /proc/self/mountinfo usage, so
 * don't use thigs like mnt_resolve_target(), mnt_context_get_mtab() etc here.
 * See lookup_umount_fs() for more details.
 */
static int has_utab_entry(struct libmnt_context *cxt, const char *target)
{
	struct libmnt_cache *cache = NULL;
	struct libmnt_fs *fs;
	struct libmnt_iter itr;
	char *cn = NULL;
	int rc = 0;

	assert(cxt);

	if (!cxt->utab) {
		const char *path = mnt_get_utab_path();

		if (!path || is_file_empty(path))
			return 0;
		cxt->utab = mnt_new_table();
		if (!cxt->utab)
			return 0;
		cxt->utab->fmt = MNT_FMT_UTAB;
		if (mnt_table_parse_file(cxt->utab, path))
			return 0;
	}

	/* paths in utab are canonicalized */
	cache = mnt_context_get_cache(cxt);
	cn = mnt_resolve_path(target, cache);
	mnt_reset_iter(&itr, MNT_ITER_BACKWARD);

	while (mnt_table_next_fs(cxt->utab, &itr, &fs) == 0) {
		if (mnt_fs_streq_target(fs, cn)) {
			rc = 1;
			break;
		}
	}

	if (!cache)
		free(cn);

	return rc;
}
Пример #14
0
/**
 * mnt_context_next_mount:
 * @cxt: context
 * @itr: iterator
 * @fs: returns the current filesystem
 * @mntrc: returns the return code from mnt_context_mount()
 * @ignored: returns 1 for not matching and 2 for already mounted filesystems
 *
 * This function tries to mount the next filesystem from fstab (as returned by
 * mnt_context_get_fstab()). See also mnt_context_set_fstab().
 *
 * You can filter out filesystems by:
 *	mnt_context_set_options_pattern() to simulate mount -a -O pattern
 *	mnt_context_set_fstype_pattern()  to simulate mount -a -t pattern
 *
 * If the filesystem is already mounted or does not match defined criteria,
 * then the mnt_context_next_mount() function returns zero, but the @ignored is
 * non-zero. Note that the root filesystem and filesystems with "noauto" option
 * are always ignored.
 *
 * If mount(2) syscall or mount.type helper failed, then the
 * mnt_context_next_mount() function returns zero, but the @mntrc is non-zero.
 * Use also mnt_context_get_status() to check if the filesystem was
 * successfully mounted.
 *
 * Returns: 0 on success,
 *         <0 in case of error (!= mount(2) errors)
 *          1 at the end of the list.
 */
int mnt_context_next_mount(struct libmnt_context *cxt,
			   struct libmnt_iter *itr,
			   struct libmnt_fs **fs,
			   int *mntrc,
			   int *ignored)
{
	struct libmnt_table *fstab, *mtab;
	const char *o, *tgt;
	int rc, mounted = 0;

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

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

	mtab = cxt->mtab;
	cxt->mtab = NULL;		/* do not reset mtab */
	mnt_reset_context(cxt);
	cxt->mtab = mtab;

	rc = mnt_context_get_fstab(cxt, &fstab);
	if (rc)
		return rc;

	rc = mnt_table_next_fs(fstab, itr, fs);
	if (rc != 0)
		return rc;	/* more filesystems (or error) */

	o = mnt_fs_get_user_options(*fs);
	tgt = mnt_fs_get_target(*fs);

	DBG(CXT, mnt_debug_h(cxt, "next-mount: trying %s", tgt));

	/*  ignore swap */
	if (mnt_fs_is_swaparea(*fs) ||

	/* ignore root filesystem */
	   (tgt && (strcmp(tgt, "/") == 0 || strcmp(tgt, "root") == 0)) ||

	/* ignore noauto filesystems */
	   (o && mnt_optstr_get_option(o, "noauto", NULL, NULL) == 0) ||

	/* ignore filesystems not match with options patterns */
	   (cxt->fstype_pattern && !mnt_fs_match_fstype(*fs,
					cxt->fstype_pattern)) ||

	/* ignore filesystems not match with type patterns */
	   (cxt->optstr_pattern && !mnt_fs_match_options(*fs,
					cxt->optstr_pattern))) {
		if (ignored)
			*ignored = 1;
		DBG(CXT, mnt_debug_h(cxt, "next-mount: not-match "
				"[fstype: %s, t-pattern: %s, options: %s, O-pattern: %s]",
				mnt_fs_get_fstype(*fs),
				cxt->fstype_pattern,
				mnt_fs_get_options(*fs),
				cxt->optstr_pattern));
		return 0;
	}

	/* ignore already mounted filesystems */
	rc = mnt_context_is_fs_mounted(cxt, *fs, &mounted);
	if (rc)
		return rc;
	if (mounted) {
		if (ignored)
			*ignored = 2;
		return 0;
	}

	if (mnt_context_is_fork(cxt)) {
		rc = mnt_fork_context(cxt);
		if (rc)
			return rc;		/* fork error */

		if (mnt_context_is_parent(cxt)) {
			return 0;		/* parent */
		}
	}

	/* child or non-forked */

	rc = mnt_context_set_fs(cxt, *fs);
	if (!rc) {
		rc = mnt_context_mount(cxt);
		if (mntrc)
			*mntrc = rc;
	}

	if (mnt_context_is_child(cxt)) {
		DBG(CXT, mnt_debug_h(cxt, "next-mount: child exit [rc=%d]", rc));
		DBG_FLUSH;
		exit(rc);
	}
	return 0;
}
Пример #15
0
/* default filename is /proc/self/mountinfo
 */
int __mnt_table_parse_mtab(struct libmnt_table *tb, const char *filename,
			   struct libmnt_table *u_tb)
{
	int rc = 0, priv_utab = 0;

	assert(tb);

	if (filename)
		DBG(TAB, ul_debugobj(tb, "%s reuested as mtab", filename));

#ifdef USE_LIBMOUNT_SUPPORT_MTAB
	if (mnt_has_regular_mtab(&filename, NULL)) {

		DBG(TAB, ul_debugobj(tb, "force mtab usage [filename=%s]", filename));

		rc = mnt_table_parse_file(tb, filename);

		/*
		 * If @filename forces us to read from /proc then also read
		 * utab file to merge userspace mount options.
		 */
		if (rc == 0 && is_mountinfo(tb))
			goto read_utab;

		if (!rc)
			return 0;
		filename = NULL;	/* failed */
	} else
		filename = NULL;	/* mtab useless */
#endif

	if (!filename || strcmp(filename, _PATH_PROC_MOUNTINFO) == 0) {
		filename = _PATH_PROC_MOUNTINFO;
		tb->fmt = MNT_FMT_MOUNTINFO;
		DBG(TAB, ul_debugobj(tb, "mtab parse: #1 read mountinfo"));
	} else
		tb->fmt = MNT_FMT_GUESS;

	rc = mnt_table_parse_file(tb, filename);
	if (rc) {
		/* hmm, old kernel? ...try /proc/mounts */
		tb->fmt = MNT_FMT_MTAB;
		return mnt_table_parse_file(tb, _PATH_PROC_MOUNTS);
	}

	if (!is_mountinfo(tb))
		return 0;
#ifdef USE_LIBMOUNT_SUPPORT_MTAB
read_utab:
#endif
	DBG(TAB, ul_debugobj(tb, "mtab parse: #2 read utab"));

	if (mnt_table_get_nents(tb) == 0)
		return 0;			/* empty, ignore utab */
	/*
	 * try to read the user specific information from /run/mount/utabs
	 */
	if (!u_tb) {
		const char *utab = mnt_get_utab_path();

		if (!utab || is_file_empty(utab))
			return 0;

		u_tb = mnt_new_table();
		if (!u_tb)
			return -ENOMEM;

		u_tb->fmt = MNT_FMT_UTAB;
		mnt_table_set_parser_fltrcb(u_tb, tb->fltrcb, tb->fltrcb_data);

		rc = mnt_table_parse_file(u_tb, utab);
		priv_utab = 1;
	}

	DBG(TAB, ul_debugobj(tb, "mtab parse: #3 merge utab"));

	if (rc == 0) {
		struct libmnt_fs *u_fs;
		struct libmnt_iter itr;

		mnt_reset_iter(&itr, MNT_ITER_BACKWARD);

		/*  merge user options into mountinfo from the kernel */
		while(mnt_table_next_fs(u_tb, &itr, &u_fs) == 0)
			mnt_table_merge_user_fs(tb, u_fs);
	}


	if (priv_utab)
		mnt_unref_table(u_tb);
	return 0;
}