コード例 #1
0
ファイル: tab_parse.c プロジェクト: Kynde/util-linux
/**
 * mnt_table_parse_stream:
 * @tb: tab pointer
 * @f: file stream
 * @filename: filename used for debug and error messages
 *
 * Returns: 0 on success, negative number in case of error.
 */
int mnt_table_parse_stream(struct libmnt_table *tb, FILE *f, const char *filename)
{
	int nlines = 0;
	int rc = -1;
	int flags = 0;
	pid_t tid = -1;

	assert(tb);
	assert(f);
	assert(filename);

	DBG(TAB, mnt_debug_h(tb, "%s: start parsing [entries=%d, filter=%s]",
				filename, mnt_table_get_nents(tb),
				tb->fltrcb ? "yes" : "not"));

	/* necessary for /proc/mounts only, the /proc/self/mountinfo
	 * parser sets the flag properly
	 */
	if (filename && strcmp(filename, _PATH_PROC_MOUNTS) == 0)
		flags = MNT_FS_KERNEL;

	while (!feof(f)) {
		struct libmnt_fs *fs = mnt_new_fs();

		if (!fs)
			goto err;

		rc = mnt_table_parse_next(tb, f, fs, filename, &nlines);

		if (!rc && tb->fltrcb && tb->fltrcb(fs, tb->fltrcb_data))
			rc = 1;	/* filtered out by callback... */

		if (!rc) {
			rc = mnt_table_add_fs(tb, fs);
			fs->flags |= flags;

			if (rc == 0 && tb->fmt == MNT_FMT_MOUNTINFO)
				rc = kernel_fs_postparse(tb, fs, &tid, filename);
		}
		mnt_unref_fs(fs);

		if (rc) {
			if (rc == 1)
				continue;	/* recoverable error */
			if (feof(f))
				break;
			goto err;		/* fatal error */
		}
	}

	DBG(TAB, mnt_debug_h(tb, "%s: stop parsing (%d entries)",
				filename, mnt_table_get_nents(tb)));
	return 0;
err:
	DBG(TAB, mnt_debug_h(tb, "%s: parse error (rc=%d)", filename, rc));
	return rc;
}
コード例 #2
0
ファイル: tab_parse.c プロジェクト: CSRedRat/util-linux
/**
 * mnt_table_parse_stream:
 * @tb: tab pointer
 * @f: file stream
 * @filename: filename used for debug and error messages
 *
 * Returns: 0 on success, negative number in case of error.
 */
int mnt_table_parse_stream(struct libmnt_table *tb, FILE *f, const char *filename)
{
	int nlines = 0;
	int rc = -1;
	int flags = 0;
	pid_t tid = -1;

	assert(tb);
	assert(f);
	assert(filename);

	DBG(TAB, mnt_debug_h(tb, "%s: start parsing (%d entries)",
				filename, mnt_table_get_nents(tb)));

	/* necessary for /proc/mounts only, the /proc/self/mountinfo
	 * parser sets the flag properly
	 */
	if (filename && strcmp(filename, _PATH_PROC_MOUNTS) == 0)
		flags = MNT_FS_KERNEL;

	while (!feof(f)) {
		struct libmnt_fs *fs = mnt_new_fs();

		if (!fs)
			goto err;

		rc = mnt_table_parse_next(tb, f, fs, filename, &nlines);
		if (!rc) {
			rc = mnt_table_add_fs(tb, fs);
			fs->flags |= flags;
			if (tb->fmt == MNT_FMT_MOUNTINFO && filename) {
				if (tid == -1)
					tid = path_to_tid(filename);
				fs->tid = tid;
			}
		}
		if (rc) {
			mnt_free_fs(fs);
			if (rc == 1)
				continue;	/* recoverable error */
			if (feof(f))
				break;
			goto err;		/* fatal error */
		}
	}

	DBG(TAB, mnt_debug_h(tb, "%s: stop parsing (%d entries)",
				filename, mnt_table_get_nents(tb)));
	return 0;
err:
	DBG(TAB, mnt_debug_h(tb, "%s: parse error (rc=%d)", filename, rc));
	return rc;
}
コード例 #3
0
ファイル: tab_parse.c プロジェクト: Kynde/util-linux
static int append_comment(struct libmnt_table *tb,
			  struct libmnt_fs *fs,
			  const char *comm,
			  int eof)
{
	int rc, intro = mnt_table_get_nents(tb) == 0;

	if (intro && is_terminated_by_blank(mnt_table_get_intro_comment(tb)))
		intro = 0;

	DBG(TAB, mnt_debug_h(tb, "appending %s comment",
			intro ? "intro" :
			eof ? "trailing" : "fs"));
	if (intro)
		rc = mnt_table_append_intro_comment(tb, comm);
	else if (eof) {
		rc = mnt_table_set_trailing_comment(tb,
				mnt_fs_get_comment(fs));
		if (!rc)
			rc = mnt_table_append_trailing_comment(tb, comm);
		if (!rc)
			rc = mnt_fs_set_comment(fs, NULL);
	} else
		rc = mnt_fs_append_comment(fs, comm);
	return rc;
}
コード例 #4
0
ファイル: tab_parse.c プロジェクト: Kynde/util-linux
/**
 * 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;
}
コード例 #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
ファイル: tab_parse.c プロジェクト: helloworld010/util-linux
/**
 * mnt_table_parse_stream:
 * @tb: tab pointer
 * @f: file stream
 * @filename: filename used for debug and error messages
 *
 * Returns: 0 on success, negative number in case of error.
 */
int mnt_table_parse_stream(struct libmnt_table *tb, FILE *f, const char *filename)
{
	int rc = -1;
	int flags = 0;
	pid_t tid = -1;
	struct libmnt_fs *fs = NULL;
	struct libmnt_parser pa = { .line = 0 };

	assert(tb);
	assert(f);
	assert(filename);

	DBG(TAB, ul_debugobj(tb, "%s: start parsing [entries=%d, filter=%s]",
				filename, mnt_table_get_nents(tb),
				tb->fltrcb ? "yes" : "not"));

	pa.filename = filename;
	pa.f = f;

	/* necessary for /proc/mounts only, the /proc/self/mountinfo
	 * parser sets the flag properly
	 */
	if (filename && strcmp(filename, _PATH_PROC_MOUNTS) == 0)
		flags = MNT_FS_KERNEL;

	while (!feof(f)) {
		if (!fs) {
			fs = mnt_new_fs();
			if (!fs)
				goto err;
		}

		rc = mnt_table_parse_next(&pa, tb, fs);

		if (!rc && tb->fltrcb && tb->fltrcb(fs, tb->fltrcb_data))
			rc = 1;	/* filtered out by callback... */

		if (!rc) {
			rc = mnt_table_add_fs(tb, fs);
			fs->flags |= flags;

			if (rc == 0 && tb->fmt == MNT_FMT_MOUNTINFO) {
				rc = kernel_fs_postparse(tb, fs, &tid, filename);
				if (rc)
					mnt_table_remove_fs(tb, fs);
			}
		}

		if (rc) {
			if (rc > 0) {
				mnt_reset_fs(fs);
				assert(fs->refcount == 1);
				continue;	/* recoverable error, reuse fs*/
			}

			mnt_unref_fs(fs);
			if (feof(f))
				break;
			goto err;		/* fatal error */
		}
		mnt_unref_fs(fs);
		fs = NULL;
	}

	DBG(TAB, ul_debugobj(tb, "%s: stop parsing (%d entries)",
				filename, mnt_table_get_nents(tb)));
	parser_cleanup(&pa);
	return 0;
err:
	DBG(TAB, ul_debugobj(tb, "%s: parse error (rc=%d)", filename, rc));
	parser_cleanup(&pa);
	return rc;
}

/**
 * mnt_table_parse_file:
 * @tb: tab pointer
 * @filename: file
 *
 * Parses the whole table (e.g. /etc/fstab) and appends new records to the @tab.
 *
 * The libmount parser ignores broken (syntax error) lines, these lines are
 * reported to the caller by the errcb() function (see mnt_table_set_parser_errcb()).
 *
 * Returns: 0 on success, negative number in case of error.
 */
int mnt_table_parse_file(struct libmnt_table *tb, const char *filename)
{
	FILE *f;
	int rc;

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

	f = fopen(filename, "r" UL_CLOEXECSTR);
	if (f) {
		rc = mnt_table_parse_stream(tb, f, filename);
		fclose(f);
	} else
		rc = -errno;

	DBG(TAB, ul_debugobj(tb, "parsing done [filename=%s, rc=%d]", filename, rc));
	return rc;
}
コード例 #7
0
ファイル: tab_parse.c プロジェクト: helloworld010/util-linux
/* 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;
}