* @spec: path or tag
* @cache: paths cache
*
- * Returns canonicalized path or NULL.
+ * Returns canonicalized path or NULL. The result has to be
+ * deallocated by free() if @cache is NULL.
*/
char *mnt_resolve_spec(const char *spec, mnt_cache *cache)
{
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
+#include <errno.h>
#include <blkid/blkid.h>
#include "nls.h"
}
+/**
+ * mnt_fs_match_target:
+ * @fs: filesystem
+ * @target: mountpoint path
+ * @cache: tags/paths cache or NULL
+ *
+ * Possible are three attempts:
+ * 1) compare @target with @fs->target
+ * 2) realpath(@target) with @fs->target
+ * 3) realpath(@target) with realpath(@fs->target).
+ *
+ * The 2nd and 3rd attempts are not performed when @cache is NULL.
+ *
+ * Returns 1 if @fs target is equal to @target else 0.
+ */
+int mnt_fs_match_target(mnt_fs *fs, const char *target, mnt_cache *cache)
+{
+ int rc = 0;
+
+ if (!fs || !target || !fs->target)
+ return 0;
+
+ /* 1) native paths */
+ rc = !strcmp(target, fs->target);
+
+ if (!rc && cache) {
+ /* 2) - canonicalized and non-canonicalized */
+ char *cn = mnt_resolve_path(target, cache);
+ rc = (cn && strcmp(cn, fs->target) == 0);
+
+ /* 3) - canonicalized and canonicalized */
+ if (!rc && cn) {
+ char *tcn = mnt_resolve_path(fs->target, cache);
+ rc = (tcn && strcmp(cn, tcn) == 0);
+ }
+ }
+
+ return rc;
+}
+
+/**
+ * mnt_fs_match_source:
+ * @fs: filesystem
+ * @source: tag or path (device or so)
+ * @cache: tags/paths cache or NULL
+ *
+ * Possible are four attempts:
+ * 1) compare @source with @fs->source
+ * 2) compare realpath(@source) with @fs->source
+ * 3) compare realpath(@source) with realpath(@fs->source)
+ * 4) compare realpath(@source) with evaluated tag from @fs->source
+ *
+ * The 2nd, 3rd and 4th attempts are not performed when @cache is NULL. The
+ * 2nd and 3rd attempts are not performed if @fs->source is tag.
+ *
+ * Returns 1 if @fs source is equal to @source else 0.
+ */
+int mnt_fs_match_source(mnt_fs *fs, const char *source, mnt_cache *cache)
+{
+ int rc = 0;
+ char *cn;
+ const char *src, *t, *v;
+
+ if (!fs || !source || !fs->source)
+ return 0;
+
+ /* 1) native paths/tags */
+ rc = !strcmp(source, fs->source);
+ if (rc || !cache)
+ return rc;
+
+ if (fs->flags & (MNT_FS_NET | MNT_FS_PSEUDO))
+ return 0;
+
+ cn = mnt_resolve_spec(source, cache);
+ if (!cn)
+ return 0;
+
+ /* 2) canonicalized and native */
+ src = mnt_fs_get_srcpath(fs);
+ if (src)
+ rc = !strcmp(cn, src);
+
+ /* 3) canonicalized and canonicalized */
+ if (src && !rc) {
+ src = mnt_resolve_path(src, cache);
+ rc = !strcmp(cn, src);
+ }
+ if (src && !rc)
+ /* fs->source is path and does not match with @source */
+ return 0;
+
+ if (mnt_fs_get_tag(fs, &t, &v))
+ return 0;
+
+ /* read @source's tags to the cache */
+ if (mnt_cache_read_tags(cache, cn) < 1) {
+ if (errno == EACCES) {
+ /* we don't have permissions to read TAGs from
+ * @source, but can translate @fs tag to devname.
+ *
+ * (because libblkid uses udev symlinks and this is
+ * accessible for non-root uses)
+ */
+ char *x = mnt_resolve_tag(t, v, cache);
+ if (x && !strcmp(x, cn))
+ return 1;
+ }
+ return 0;
+ }
+
+ /* 4) has the @source a tag that matches with tag from @fs ? */
+ if (!mnt_cache_device_has_tag(cache, cn, t, v))
+ return 0;
+
+ return 1;
+}
+
+/**
+ * mnt_fs_match_fstype:
+ * @fs: filesystem
+ * @types: filesystem name or comma delimited list of filesystems
+ *
+ * For more details see mnt_match_fstype().
+ *
+ * Returns 1 if @fs type is matching to @types else 0. The function returns
+ * 0 when types is NULL.
+ */
+int mnt_fs_match_fstype(mnt_fs *fs, const char *types)
+{
+ return mnt_match_fstype(fs->fstype, types);
+}
+
+/**
+ * mnt_fs_match_options:
+ * @fs: filesystem
+ * @options: comma delimited list of options (and nooptions)
+ *
+ * For more details see mnt_match_options().
+ *
+ * Returns 1 if @fs type is matching to @options else 0. The function returns
+ * 0 when types is NULL.
+ */
+int mnt_fs_match_options(mnt_fs *fs, const char *options)
+{
+ return mnt_match_options(fs->optstr, options);
+}
+
/* Unfortunately the classical Unix /etc/mtab and /etc/fstab
do not handle directory names containing spaces.
Here we mangle them, replacing a space by \040.
extern int mnt_fs_get_option(mnt_fs *ent, const char *name,
char **value, size_t *valsz);
+extern int mnt_fs_match_target(mnt_fs *fs, const char *target, mnt_cache *cache);
+extern int mnt_fs_match_source(mnt_fs *fs, const char *source, mnt_cache *cache);
+extern int mnt_fs_match_fstype(mnt_fs *fs, const char *types);
+extern int mnt_fs_match_options(mnt_fs *fs, const char *options);
+
/* mtab/fstab line */
#define MNT_MFILE_PRINTFMT "%s %s %s %s %d %d\n"
extern mnt_fs *mnt_tab_find_tag(mnt_tab *tb, const char *tag,
const char *val, int direction);
extern mnt_fs *mnt_tab_find_source(mnt_tab *tb, const char *source, int direction);
-extern mnt_fs *mnt_tab_find_pair(mnt_tab *tb, const char *srcpath,
- const char *target, int direction);
+
+extern int mnt_tab_find_next_fs(mnt_tab *tb, mnt_iter *itr,
+ int (*match_func)(mnt_fs *, void *), void *userdata,
+ mnt_fs **fs);
+
extern int mnt_tab_fprintf(mnt_tab *tb, FILE *f, const char *fmt);
extern int mnt_tab_update_file(mnt_tab *tb);
int freq; /* fstab[5]: dump frequency in days */
int passno; /* fstab[6]: pass number on parallel fsck */
- int flags; /* MNT_ENTRY_* flags */
+ int flags; /* MNT_FS_* flags */
int lineno; /* line number in the parental file */
};
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
+#include <errno.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
*/
int mnt_tab_next_fs(mnt_tab *tb, mnt_iter *itr, mnt_fs **fs)
{
+ int rc;
+
assert(tb);
assert(itr);
assert(fs);
if (!tb || !itr || !fs)
return -1;
again:
+ rc = 1;
if (!itr->head)
MNT_ITER_INIT(itr, &tb->ents);
if (itr->p != itr->head) {
MNT_ITER_ITERATE(itr, *fs, struct _mnt_fs, ents);
- return 0;
+ rc = 0;
}
/* ignore broken entries */
if (*fs && ((*fs)->flags & MNT_FS_ERROR))
goto again;
+ return rc;
+}
+
+/**
+ * mnt_tab_find_next_fs:
+ * @tb: table
+ * @itr: iterator
+ * @match_func: function returns 1 or 0
+ * @fs: returns pointer to the next matching table entry
+ *
+ * This function allows search in @tb.
+ *
+ * Returns -1 in case of error, 1 at end of table or 0 o success.
+ */
+int mnt_tab_find_next_fs(mnt_tab *tb, mnt_iter *itr,
+ int (*match_func)(mnt_fs *, void *), void *userdata,
+ mnt_fs **fs)
+{
+ if (!tb || !itr || !fs || !match_func)
+ return -1;
+
+ if (!itr->head)
+ MNT_ITER_INIT(itr, &tb->ents);
+
+ do {
+ if (itr->p != itr->head)
+ MNT_ITER_ITERATE(itr, *fs, struct _mnt_fs, ents);
+ else
+ break; /* end */
+
+ if ((*fs)->flags & MNT_FS_ERROR)
+ continue;
+ if (match_func(*fs, userdata))
+ return 0;
+ } while(1);
+
return 1;
}
}
/* evaluated tag */
- if (ntags && mnt_cache_read_tags(tb->cache, cn) > 0) {
+ if (ntags) {
mnt_reset_iter(&itr, direction);
- while(mnt_tab_next_fs(tb, &itr, &fs) == 0) {
- const char *t, *v;
- if (mnt_fs_get_tag(fs, &t, &v))
- continue;
+ if (mnt_cache_read_tags(tb->cache, cn) > 0) {
+ /* @path's TAGs are in the cache */
+ while(mnt_tab_next_fs(tb, &itr, &fs) == 0) {
+ const char *t, *v;
- if (mnt_cache_device_has_tag(tb->cache, cn, t, v))
- return fs;
+ if (mnt_fs_get_tag(fs, &t, &v))
+ continue;
+
+ if (mnt_cache_device_has_tag(tb->cache, cn, t, v))
+ return fs;
+ }
+ } else if (errno == EACCES) {
+ /* @path is unaccessible, try evaluate all TAGs in @tb
+ * by udev symlinks -- this could be expensive on systems
+ * with huge fstab/mtab */
+ while(mnt_tab_next_fs(tb, &itr, &fs) == 0) {
+ const char *t, *v, *x;
+ if (mnt_fs_get_tag(fs, &t, &v))
+ continue;
+ x = mnt_resolve_tag(t, v, tb->cache);
+ if (x && !strcmp(x, cn))
+ return fs;
+ }
}
}
return fs;
}
-/**
- * mnt_tab_find_pair:
- * @tb: tab pointer
- * @srcpath: canonicalized source path (devname or dirname)
- * @target: canonicalized mountpoint
- * @direction: MNT_ITER_{FORWARD,BACKWARD}
- *
- * Returns a tab entry or NULL.
- */
-mnt_fs *mnt_tab_find_pair(mnt_tab *tb, const char *srcpath,
- const char *target, int direction)
-{
- mnt_iter itr;
- mnt_fs *fs;
- int has_tags = -1;
- const char *p;
-
- assert(tb);
- assert(srcpath);
- assert(target);
-
- DBG(DEBUG_TAB, fprintf(stderr,
- "libmount: %s: lookup pair: srcpath(%s) target(%s)\n",
- tb->filename, srcpath, target));
-
- /* native paths */
- mnt_reset_iter(&itr, direction);
- while(mnt_tab_next_fs(tb, &itr, &fs) == 0) {
- if (!fs->target || strcmp(fs->target, target))
- continue;
- p = mnt_fs_get_srcpath(fs);
- if (p && strcmp(p, srcpath) == 0)
- return fs;
- }
-
- if (!tb->cache)
- return NULL;
-
- mnt_reset_iter(&itr, direction);
- while(mnt_tab_next_fs(tb, &itr, &fs) == 0) {
- const char *src;
-
- if (!fs->target)
- continue;
-
- /* canonicalized or non-canonicalied target */
- if (strcmp(fs->target, target)) {
- p = mnt_resolve_path(fs->target, tb->cache);
- if (!p || strcmp(p, target))
- continue;
- }
-
- src = mnt_fs_get_srcpath(fs);
- if (src) {
- /* canonicalized or non-canonicalied srcpath */
- if (strcmp(src, srcpath)) {
- p = mnt_resolve_path(src, tb->cache);
- if (!p || strcmp(p, srcpath))
- continue;
- }
- } else if (has_tags != 0) {
- /* entry source is tag */
- const char *t, *v;
-
- if (mnt_fs_get_tag(fs, &t, &v))
- continue;
- if (has_tags == -1 &&
- mnt_cache_read_tags(tb->cache, srcpath)) {
- has_tags = 0;
- continue;
- }
- has_tags = 1;
- if (!mnt_cache_device_has_tag(tb->cache, srcpath, t, v))
- continue;
- } else
- continue;
-
- return fs;
- }
- return NULL;
-}
/**
* mnt_tab_fprintf: