From 3fca8422b154e047055ed938e81005ea6129d86a Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Mon, 1 Mar 2010 22:29:38 +0100 Subject: [PATCH] libmount: add fstab/mtab/mountinfo lookup routines Signed-off-by: Karel Zak --- shlibs/mount/src/cache.c | 3 +- shlibs/mount/src/fs.c | 149 +++++++++++++++++++++++++++++++++++ shlibs/mount/src/mount.h.in | 12 ++- shlibs/mount/src/mountP.h | 2 +- shlibs/mount/src/tab.c | 153 +++++++++++++++--------------------- 5 files changed, 226 insertions(+), 93 deletions(-) diff --git a/shlibs/mount/src/cache.c b/shlibs/mount/src/cache.c index 18cf9fad..b9d89f43 100644 --- a/shlibs/mount/src/cache.c +++ b/shlibs/mount/src/cache.c @@ -408,7 +408,8 @@ error: * @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) { diff --git a/shlibs/mount/src/fs.c b/shlibs/mount/src/fs.c index 0e12052d..01c2d027 100644 --- a/shlibs/mount/src/fs.c +++ b/shlibs/mount/src/fs.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include "nls.h" @@ -415,6 +416,154 @@ int mnt_fs_get_option(mnt_fs *fs, const char *name, } +/** + * 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. diff --git a/shlibs/mount/src/mount.h.in b/shlibs/mount/src/mount.h.in index 6bea2a17..04bbee96 100644 --- a/shlibs/mount/src/mount.h.in +++ b/shlibs/mount/src/mount.h.in @@ -230,6 +230,11 @@ extern int mnt_fs_set_passno(mnt_fs *ent, int passno); 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" @@ -269,8 +274,11 @@ extern mnt_fs *mnt_tab_find_srcpath(mnt_tab *tb, const char *path, int direction 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); diff --git a/shlibs/mount/src/mountP.h b/shlibs/mount/src/mountP.h index f08f435a..3ba3205f 100644 --- a/shlibs/mount/src/mountP.h +++ b/shlibs/mount/src/mountP.h @@ -152,7 +152,7 @@ struct _mnt_fs { 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 */ }; diff --git a/shlibs/mount/src/tab.c b/shlibs/mount/src/tab.c index fd929313..bfd3a6e1 100644 --- a/shlibs/mount/src/tab.c +++ b/shlibs/mount/src/tab.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -232,6 +233,8 @@ int mnt_tab_remove_fs(mnt_tab *tb, mnt_fs *fs) */ int mnt_tab_next_fs(mnt_tab *tb, mnt_iter *itr, mnt_fs **fs) { + int rc; + assert(tb); assert(itr); assert(fs); @@ -239,17 +242,54 @@ int mnt_tab_next_fs(mnt_tab *tb, mnt_iter *itr, mnt_fs **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; } @@ -386,16 +426,32 @@ mnt_fs *mnt_tab_find_srcpath(mnt_tab *tb, const char *path, int direction) } /* 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; + } } } @@ -503,87 +559,6 @@ mnt_fs *mnt_tab_find_source(mnt_tab *tb, const char *source, int direction) 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: -- 2.39.5