summaryrefslogtreecommitdiff
path: root/libmount/src/tab.c
diff options
context:
space:
mode:
Diffstat (limited to 'libmount/src/tab.c')
-rw-r--r--libmount/src/tab.c538
1 files changed, 432 insertions, 106 deletions
diff --git a/libmount/src/tab.c b/libmount/src/tab.c
index 11a297814..b023504ad 100644
--- a/libmount/src/tab.c
+++ b/libmount/src/tab.c
@@ -11,9 +11,9 @@
* @short_description: container for entries from fstab, mtab or mountinfo
*
* Note that mnt_table_find_* functions are mount(8) compatible. These functions
- * try to find an entry in more iterations where the first attempt is always
+ * try to find an entry in more iterations, where the first attempt is always
* based on comparison with unmodified (non-canonicalized or un-evaluated)
- * paths or tags. For example fstab with two entries:
+ * paths or tags. For example a fstab with two entries:
* <informalexample>
* <programlisting>
* LABEL=foo /foo auto rw
@@ -39,7 +39,7 @@
* mnt_table_find_source(tb, "UUID=anyuuid", &fs);
* </programlisting>
* </informalexample>
- * will returns the first entry (if UUID matches with the device).
+ * will return the first entry (if UUID matches with the device).
*/
#include <blkid.h>
@@ -47,6 +47,8 @@
#include "strutils.h"
#include "loopdev.h"
+static int is_mountinfo(struct libmnt_table *tb);
+
/**
* mnt_new_table:
*
@@ -66,7 +68,7 @@ struct libmnt_table *mnt_new_table(void)
return NULL;
DBG(TAB, mnt_debug_h(tb, "alloc"));
-
+ tb->refcount = 1;
INIT_LIST_HEAD(&tb->ents);
return tb;
}
@@ -75,7 +77,8 @@ struct libmnt_table *mnt_new_table(void)
* mnt_reset_table:
* @tb: tab pointer
*
- * Dealocates all entries (filesystems) from the table
+ * Removes all entries (filesystems) from the table. The filesystems with zero
+ * reference count will be deallocated.
*
* Returns: 0 on success or negative number in case of error.
*/
@@ -89,7 +92,7 @@ int mnt_reset_table(struct libmnt_table *tb)
while (!list_empty(&tb->ents)) {
struct libmnt_fs *fs = list_entry(tb->ents.next,
struct libmnt_fs, ents);
- mnt_free_fs(fs);
+ mnt_table_remove_fs(tb, fs);
}
tb->nents = 0;
@@ -97,10 +100,46 @@ int mnt_reset_table(struct libmnt_table *tb)
}
/**
+ * mnt_ref_table:
+ * @tb: table pointer
+ *
+ * Increments reference counter.
+ */
+void mnt_ref_table(struct libmnt_table *tb)
+{
+ if (tb) {
+ tb->refcount++;
+ /*DBG(FS, mnt_debug_h(tb, "ref=%d", tb->refcount));*/
+ }
+}
+
+/**
+ * mnt_unref_table:
+ * @tb: table pointer
+ *
+ * De-increments reference counter, on zero the @tb is automatically
+ * deallocated by mnt_free_table().
+ */
+void mnt_unref_table(struct libmnt_table *tb)
+{
+ if (tb) {
+ tb->refcount--;
+ /*DBG(FS, mnt_debug_h(tb, "unref=%d", tb->refcount));*/
+ if (tb->refcount <= 0)
+ mnt_free_table(tb);
+ }
+}
+
+
+/**
* mnt_free_table:
* @tb: tab pointer
*
- * Deallocates tab struct and all entries.
+ * Deallocates the table. This function does not care about reference count. Don't
+ * use this function directly -- it's better to use use mnt_unref_table().
+ *
+ * The table entries (filesystems) are unrefrenced by mnt_reset_table() and
+ * cache by mnt_unref_cache().
*/
void mnt_free_table(struct libmnt_table *tb)
{
@@ -109,7 +148,12 @@ void mnt_free_table(struct libmnt_table *tb)
mnt_reset_table(tb);
+ WARN_REFCOUNT(TAB, tb, tb->refcount);
DBG(TAB, mnt_debug_h(tb, "free"));
+
+ mnt_unref_cache(tb->cache);
+ free(tb->comm_intro);
+ free(tb->comm_tail);
free(tb);
}
@@ -117,26 +161,228 @@ void mnt_free_table(struct libmnt_table *tb)
* mnt_table_get_nents:
* @tb: pointer to tab
*
- * Returns: number of valid entries in tab.
+ * Returns: number of entries in table.
*/
int mnt_table_get_nents(struct libmnt_table *tb)
{
- assert(tb);
return tb ? tb->nents : 0;
}
/**
+ * mnt_table_is_empty:
+ * @tb: pointer to tab
+ *
+ * Returns: 1 if the table is without filesystems, or 0.
+ */
+int mnt_table_is_empty(struct libmnt_table *tb)
+{
+ assert(tb);
+ return tb == NULL || list_empty(&tb->ents) ? 1 : 0;
+}
+
+/**
+ * mnt_table_set_userdata:
+ * @tb: pointer to tab
+ * @data: pointer to user data
+ *
+ * Sets pointer to the private user data.
+ *
+ * Returns: 0 on success or negative number in case of error.
+ */
+int mnt_table_set_userdata(struct libmnt_table *tb, void *data)
+{
+ assert(tb);
+ if (!tb)
+ return -EINVAL;
+
+ tb->userdata = data;
+ return 0;
+}
+
+/**
+ * mnt_table_get_userdata:
+ * @tb: pointer to tab
+ *
+ * Returns: pointer to user's data.
+ */
+void *mnt_table_get_userdata(struct libmnt_table *tb)
+{
+ assert(tb);
+ return tb ? tb->userdata : NULL;
+}
+
+/**
+ * mnt_table_enable_comments:
+ * @tb: pointer to tab
+ * @enable: TRUE or FALSE
+ *
+ * Enables parsing of comments.
+ *
+ * The initial (intro) file comment is accessible by
+ * mnt_table_get_intro_comment(). The intro and the comment of the first fstab
+ * entry has to be separated by blank line. The filesystem comments are
+ * accessible by mnt_fs_get_comment(). The trailing fstab comment is accessible
+ * by mnt_table_get_trailing_comment().
+ *
+ * <informalexample>
+ * <programlisting>
+ * #
+ * # Intro comment
+ * #
+ *
+ * # this comments belongs to the first fs
+ * LABEL=foo /mnt/foo auto defaults 1 2
+ * # this comments belongs to the second fs
+ * LABEL=bar /mnt/bar auto defaults 1 2
+ * # tailing comment
+ * </programlisting>
+ * </informalexample>
+ */
+void mnt_table_enable_comments(struct libmnt_table *tb, int enable)
+{
+ assert(tb);
+ if (tb)
+ tb->comms = enable;
+}
+
+/**
+ * mnt_table_with_comments:
+ * @tb: pointer to table
+ *
+ * Returns: 1 if comments parsing is enabled, or 0.
+ */
+int mnt_table_with_comments(struct libmnt_table *tb)
+{
+ assert(tb);
+ return tb ? tb->comms : 0;
+}
+
+/**
+ * mnt_table_get_intro_comment:
+ * @tb: pointer to tab
+ *
+ * Returns: initial comment in tb
+ */
+const char *mnt_table_get_intro_comment(struct libmnt_table *tb)
+{
+ assert(tb);
+ return tb ? tb->comm_intro : NULL;
+}
+
+/**
+ * mnt_table_set_into_comment:
+ * @tb: pointer to tab
+ * @comm: comment or NULL
+ *
+ * Sets the initial comment in tb.
+ *
+ * Returns: 0 on success or negative number in case of error.
+ */
+int mnt_table_set_intro_comment(struct libmnt_table *tb, const char *comm)
+{
+ char *p = NULL;
+
+ assert(tb);
+ if (!tb)
+ return -EINVAL;
+ if (comm) {
+ p = strdup(comm);
+ if (!p)
+ return -ENOMEM;
+ }
+ free(tb->comm_intro);
+ tb->comm_intro = p;
+ return 0;
+}
+
+/**
+ * mnt_table_append_into_comment:
+ * @tb: pointer to tab
+ * @comm: comment of NULL
+ *
+ * Appends the initial comment in tb.
+ *
+ * Returns: 0 on success or negative number in case of error.
+ */
+int mnt_table_append_intro_comment(struct libmnt_table *tb, const char *comm)
+{
+ assert(tb);
+ if (!tb)
+ return -EINVAL;
+ return append_string(&tb->comm_intro, comm);
+}
+
+/**
+ * mnt_table_get_trailing_comment:
+ * @tb: pointer to tab
+ *
+ * Returns: table trailing comment
+ */
+const char *mnt_table_get_trailing_comment(struct libmnt_table *tb)
+{
+ assert(tb);
+ return tb ? tb->comm_tail : NULL;
+}
+
+/**
+ * mnt_table_set_trailing_comment
+ * @tb: pointer to tab
+ * @comm: comment string
+ *
+ * Sets the trailing comment in table.
+ *
+ * Returns: 0 on success or negative number in case of error.
+ */
+int mnt_table_set_trailing_comment(struct libmnt_table *tb, const char *comm)
+{
+ char *p = NULL;
+
+ assert(tb);
+ if (!tb)
+ return -EINVAL;
+ if (comm) {
+ p = strdup(comm);
+ if (!p)
+ return -ENOMEM;
+ }
+ free(tb->comm_tail);
+ tb->comm_tail = p;
+ return 0;
+}
+
+/**
+ * mnt_table_append_trailing_comment:
+ * @tb: pointer to tab
+ * @comm: comment of NULL
+ *
+ * Appends to the trailing table comment.
+ *
+ * Returns: 0 on success or negative number in case of error.
+ */
+int mnt_table_append_trailing_comment(struct libmnt_table *tb, const char *comm)
+{
+ assert(tb);
+ if (!tb)
+ return -EINVAL;
+ return append_string(&tb->comm_tail, comm);
+}
+
+/**
* mnt_table_set_cache:
* @tb: pointer to tab
* @mpc: pointer to struct libmnt_cache instance
*
- * Setups a cache for canonicalized paths and evaluated tags (LABEL/UUID). The
+ * Sets up a cache for canonicalized paths and evaluated tags (LABEL/UUID). The
* cache is recommended for mnt_table_find_*() functions.
*
* The cache could be shared between more tabs. Be careful when you share the
* same cache between more threads -- currently the cache does not provide any
* locking method.
*
+ * This function increments cache refrence counter. It's recomented to use
+ * mnt_unref_cache() after mnt_table_set_cache() if you want to keep the cache
+ * referenced by @tb only.
+ *
* See also mnt_new_cache().
*
* Returns: 0 on success or negative number in case of error.
@@ -146,6 +392,9 @@ int mnt_table_set_cache(struct libmnt_table *tb, struct libmnt_cache *mpc)
assert(tb);
if (!tb)
return -EINVAL;
+
+ mnt_ref_cache(mpc); /* new */
+ mnt_unref_cache(tb->cache); /* old */
tb->cache = mpc;
return 0;
}
@@ -167,7 +416,9 @@ struct libmnt_cache *mnt_table_get_cache(struct libmnt_table *tb)
* @tb: tab pointer
* @fs: new entry
*
- * Adds a new entry to tab.
+ * Adds a new entry to tab and increment @fs reference counter. Don't forget to
+ * use mnt_unref_fs() after mnt_table_add_fs() you want to keep the @fs
+ * referenced by the table only.
*
* Returns: 0 on success or negative number in case of error.
*/
@@ -179,11 +430,12 @@ int mnt_table_add_fs(struct libmnt_table *tb, struct libmnt_fs *fs)
if (!tb || !fs)
return -EINVAL;
+ mnt_ref_fs(fs);
list_add_tail(&fs->ents, &tb->ents);
+ tb->nents++;
DBG(TAB, mnt_debug_h(tb, "add entry: %s %s",
mnt_fs_get_source(fs), mnt_fs_get_target(fs)));
- tb->nents++;
return 0;
}
@@ -192,6 +444,10 @@ int mnt_table_add_fs(struct libmnt_table *tb, struct libmnt_fs *fs)
* @tb: tab pointer
* @fs: new entry
*
+ * Removes the @fs from the table and de-increment reference counter of the @fs. The
+ * filesystem with zero reference counter will be deallocated. Don't forget to use
+ * mnt_ref_fs() before call mnt_table_remove_fs() if you want to use @fs later.
+ *
* Returns: 0 on success or negative number in case of error.
*/
int mnt_table_remove_fs(struct libmnt_table *tb, struct libmnt_fs *fs)
@@ -201,7 +457,11 @@ int mnt_table_remove_fs(struct libmnt_table *tb, struct libmnt_fs *fs)
if (!tb || !fs)
return -EINVAL;
+
list_del(&fs->ents);
+ INIT_LIST_HEAD(&fs->ents); /* otherwise FS still points to the list */
+
+ mnt_unref_fs(fs);
tb->nents--;
return 0;
}
@@ -211,18 +471,18 @@ int mnt_table_remove_fs(struct libmnt_table *tb, struct libmnt_fs *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 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 is necessary to sort mountpoints by IDs to get the tree
+ * 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 than use
+ * If you're not sure, then use
*
* mnt_table_find_target(tb, "/", MNT_ITER_BACKWARD);
*
- * this is more robust and usable for arbitrary tab file (including fstab).
+ * this is more robust and usable for arbitrary tab files (including fstab).
*
- * Returns: 0 on success or less then zero case of error.
+ * 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)
{
@@ -233,16 +493,16 @@ int mnt_table_get_root_fs(struct libmnt_table *tb, struct libmnt_fs **root)
assert(tb);
assert(root);
- if (!tb || !root)
+ if (!tb || !root || !is_mountinfo(tb))
return -EINVAL;
DBG(TAB, mnt_debug_h(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 (!id)
- break; /* @tab is not mountinfo file? */
if (!*root || id < root_id) {
*root = fs;
@@ -250,7 +510,7 @@ int mnt_table_get_root_fs(struct libmnt_table *tb, struct libmnt_fs **root)
}
}
- return root_id ? 0 : -EINVAL;
+ return *root ? 0 : -EINVAL;
}
/**
@@ -260,10 +520,10 @@ int mnt_table_get_root_fs(struct libmnt_table *tb, struct libmnt_fs **root)
* @parent: parental FS
* @chld: returns the next child filesystem
*
- * Note that filesystems are returned in the order how was mounted (according to
+ * Note that filesystems are returned in the order of mounting (according to
* IDs in /proc/self/mountinfo).
*
- * Returns: 0 on success, negative number in case of error or 1 at end of list.
+ * Returns: 0 on success, negative number in case of error or 1 at the 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)
@@ -271,15 +531,13 @@ int mnt_table_next_child_fs(struct libmnt_table *tb, struct libmnt_iter *itr,
struct libmnt_fs *fs;
int parent_id, lastchld_id = 0, chld_id = 0;
- if (!tb || !itr || !parent)
+ if (!tb || !itr || !parent || !is_mountinfo(tb))
return -EINVAL;
- DBG(TAB, mnt_debug_h(tb, "lookup next child of %s",
+ 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) {
@@ -298,7 +556,7 @@ int mnt_table_next_child_fs(struct libmnt_table *tb, struct libmnt_iter *itr,
id = mnt_fs_get_id(fs);
- /* avoid infinite loop. This only happens in rare cases
+ /* avoid an 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;
@@ -310,7 +568,7 @@ int mnt_table_next_child_fs(struct libmnt_table *tb, struct libmnt_iter *itr,
}
}
- if (!chld_id)
+ if (!*chld)
return 1; /* end of iterator */
/* set the iterator to the @chld for the next call */
@@ -325,7 +583,7 @@ int mnt_table_next_child_fs(struct libmnt_table *tb, struct libmnt_iter *itr,
* @itr: iterator
* @fs: returns the next tab entry
*
- * Returns: 0 on success, negative number in case of error or 1 at end of list.
+ * Returns: 0 on success, negative number in case of error or 1 at the end of list.
*
* Example:
* <informalexample>
@@ -334,11 +592,10 @@ int mnt_table_next_child_fs(struct libmnt_table *tb, struct libmnt_iter *itr,
* const char *dir = mnt_fs_get_target(fs);
* printf("mount point: %s\n", dir);
* }
- * mnt_free_table(fi);
* </programlisting>
* </informalexample>
*
- * lists all mountpoints from fstab in backward order.
+ * lists all mountpoints from fstab in reverse order.
*/
int mnt_table_next_fs(struct libmnt_table *tb, struct libmnt_iter *itr, struct libmnt_fs **fs)
{
@@ -363,14 +620,54 @@ int mnt_table_next_fs(struct libmnt_table *tb, struct libmnt_iter *itr, struct l
}
/**
+ * mnt_table_first_fs:
+ * @tb: tab pointer
+ * @fs: returns the first tab entry
+ *
+ * Returns: 0 on success, negative number in case of error or 1 at the end of list.
+ */
+int mnt_table_first_fs(struct libmnt_table *tb, struct libmnt_fs **fs)
+{
+ assert(tb);
+ assert(fs);
+
+ if (!tb || !fs)
+ return -EINVAL;
+ if (list_empty(&tb->ents))
+ return 1;
+ *fs = list_first_entry(&tb->ents, struct libmnt_fs, ents);
+ return 0;
+}
+
+/**
+ * mnt_table_last_fs:
+ * @tb: tab pointer
+ * @fs: returns the last tab entry
+ *
+ * Returns: 0 on success, negative number in case of error or 1 at the end of list.
+ */
+int mnt_table_last_fs(struct libmnt_table *tb, struct libmnt_fs **fs)
+{
+ assert(tb);
+ assert(fs);
+
+ if (!tb || !fs)
+ return -EINVAL;
+ if (list_empty(&tb->ents))
+ return 1;
+ *fs = list_last_entry(&tb->ents, struct libmnt_fs, ents);
+ return 0;
+}
+
+/**
* mnt_table_find_next_fs:
* @tb: table
* @itr: iterator
- * @match_func: function returns 1 or 0
+ * @match_func: function returning 1 or 0
* @userdata: extra data for match_func
* @fs: returns pointer to the next matching table entry
*
- * This function allows search in @tb.
+ * This function allows searching in @tb.
*
* Returns: negative number in case of error, 1 at end of table or 0 o success.
*/
@@ -431,7 +728,7 @@ int mnt_table_set_iter(struct libmnt_table *tb, struct libmnt_iter *itr, struct
* @path: directory
* @direction: MNT_ITER_{FORWARD,BACKWARD}
*
- * Same like mnt_get_mountpoint(), but this function does not rely on
+ * Same as mnt_get_mountpoint(), except this function does not rely on
* st_dev numbers.
*
* Returns: a tab entry or NULL.
@@ -442,12 +739,12 @@ struct libmnt_fs *mnt_table_find_mountpoint(struct libmnt_table *tb,
{
char *mnt;
- if (!tb || !path)
+ if (!tb || !path || !*path)
return NULL;
if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
return NULL;
- DBG(TAB, mnt_debug_h(tb, "lookup MOUNTPOINT: %s", path));
+ DBG(TAB, mnt_debug_h(tb, "lookup MOUNTPOINT: '%s'", path));
mnt = strdup(path);
if (!mnt)
@@ -478,10 +775,10 @@ struct libmnt_fs *mnt_table_find_mountpoint(struct libmnt_table *tb,
* @path: mountpoint directory
* @direction: MNT_ITER_{FORWARD,BACKWARD}
*
- * Try to lookup an entry in given tab, possible are three iterations, first
- * with @path, second with realpath(@path) and third with realpath(@path)
+ * Try to lookup an entry in the given tab, three iterations are possible, the first
+ * with @path, the second with realpath(@path) and the third with realpath(@path)
* against realpath(fs->target). The 2nd and 3rd iterations are not performed
- * when @tb cache is not set (see mnt_table_set_cache()).
+ * when the @tb cache is not set (see mnt_table_set_cache()).
*
* Returns: a tab entry or NULL.
*/
@@ -494,12 +791,12 @@ struct libmnt_fs *mnt_table_find_target(struct libmnt_table *tb, const char *pat
assert(tb);
assert(path);
- if (!tb || !path)
+ if (!tb || !path || !*path)
return NULL;
if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
return NULL;
- DBG(TAB, mnt_debug_h(tb, "lookup TARGET: %s", path));
+ DBG(TAB, mnt_debug_h(tb, "lookup TARGET: '%s'", path));
/* native @target */
mnt_reset_iter(&itr, direction);
@@ -510,6 +807,8 @@ struct libmnt_fs *mnt_table_find_target(struct libmnt_table *tb, const char *pat
if (!tb->cache || !(cn = mnt_resolve_path(path, tb->cache)))
return NULL;
+ DBG(TAB, mnt_debug_h(tb, "lookup canonical TARGET: '%s'", cn));
+
/* canonicalized paths in struct libmnt_table */
mnt_reset_iter(&itr, direction);
while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
@@ -519,7 +818,7 @@ struct libmnt_fs *mnt_table_find_target(struct libmnt_table *tb, const char *pat
/* non-canonicaled path in struct libmnt_table
* -- note that mountpoint in /proc/self/mountinfo is already
- * canonicalized by kernel
+ * canonicalized by the kernel
*/
mnt_reset_iter(&itr, direction);
while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
@@ -545,11 +844,11 @@ struct libmnt_fs *mnt_table_find_target(struct libmnt_table *tb, const char *pat
* @path: source path (devname or dirname) or NULL
* @direction: MNT_ITER_{FORWARD,BACKWARD}
*
- * Try to lookup an entry in given tab, possible are four iterations, first
- * with @path, second with realpath(@path), third with tags (LABEL, UUID, ..)
- * from @path and fourth with realpath(@path) against realpath(entry->srcpath).
+ * Try to lookup an entry in the given tab, four iterations are possible, the first
+ * with @path, the second with realpath(@path), the third with tags (LABEL, UUID, ..)
+ * from @path and the fourth with realpath(@path) against realpath(entry->srcpath).
*
- * The 2nd, 3rd and 4th iterations are not performed when @tb cache is not
+ * The 2nd, 3rd and 4th iterations are not performed when the @tb cache is not
* set (see mnt_table_set_cache()).
*
* Note that NULL is a valid source path; it will be replaced with "none". The
@@ -561,17 +860,17 @@ struct libmnt_fs *mnt_table_find_srcpath(struct libmnt_table *tb, const char *pa
{
struct libmnt_iter itr;
struct libmnt_fs *fs = NULL;
- int ntags = 0;
+ int ntags = 0, nents;
char *cn;
const char *p;
assert(tb);
- if (!tb || !path)
+ if (!tb || !path || !*path)
return NULL;
if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
return NULL;
- DBG(TAB, mnt_debug_h(tb, "lookup srcpath: %s", path));
+ DBG(TAB, mnt_debug_h(tb, "lookup SRCPATH: '%s'", path));
/* native paths */
mnt_reset_iter(&itr, direction);
@@ -585,8 +884,12 @@ struct libmnt_fs *mnt_table_find_srcpath(struct libmnt_table *tb, const char *pa
if (!path || !tb->cache || !(cn = mnt_resolve_path(path, tb->cache)))
return NULL;
+ DBG(TAB, mnt_debug_h(tb, "lookup canonical SRCPATH: '%s'", cn));
+
+ nents = mnt_table_get_nents(tb);
+
/* canonicalized paths in struct libmnt_table */
- if (ntags < mnt_table_get_nents(tb)) {
+ if (ntags < nents) {
mnt_reset_iter(&itr, direction);
while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
if (mnt_fs_streq_srcpath(fs, cn))
@@ -612,9 +915,9 @@ struct libmnt_fs *mnt_table_find_srcpath(struct libmnt_table *tb, const char *pa
return fs;
}
} else if (rc < 0 && errno == EACCES) {
- /* @path is unaccessible, try evaluate all TAGs in @tb
+ /* @path is inaccessible, try evaluating all TAGs in @tb
* by udev symlinks -- this could be expensive on systems
- * with huge fstab/mtab */
+ * with a huge fstab/mtab */
while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
const char *t, *v, *x;
if (mnt_fs_get_tag(fs, &t, &v))
@@ -629,7 +932,7 @@ struct libmnt_fs *mnt_table_find_srcpath(struct libmnt_table *tb, const char *pa
}
/* non-canonicalized paths in struct libmnt_table */
- if (ntags <= mnt_table_get_nents(tb)) {
+ if (ntags <= nents) {
mnt_reset_iter(&itr, direction);
while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
if (mnt_fs_is_netfs(fs) || mnt_fs_is_pseudofs(fs))
@@ -655,9 +958,9 @@ struct libmnt_fs *mnt_table_find_srcpath(struct libmnt_table *tb, const char *pa
* @val: tag value
* @direction: MNT_ITER_{FORWARD,BACKWARD}
*
- * Try to lookup an entry in given tab, first attempt is lookup by @tag and
+ * Try to lookup an entry in the given tab, the first attempt is to lookup by @tag and
* @val, for the second attempt the tag is evaluated (converted to the device
- * name) and mnt_table_find_srcpath() is preformed. The second attempt is not
+ * name) and mnt_table_find_srcpath() is performed. The second attempt is not
* performed when @tb cache is not set (see mnt_table_set_cache()).
* Returns: a tab entry or NULL.
@@ -672,7 +975,7 @@ struct libmnt_fs *mnt_table_find_tag(struct libmnt_table *tb, const char *tag,
assert(tag);
assert(val);
- if (!tb || !tag || !val)
+ if (!tb || !tag || !*tag || !val)
return NULL;
if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
return NULL;
@@ -703,16 +1006,17 @@ struct libmnt_fs *mnt_table_find_tag(struct libmnt_table *tb, const char *tag,
* @source: TAG or path
* @direction: MNT_ITER_{FORWARD,BACKWARD}
*
- * This is high-level API for mnt_table_find_{srcpath,tag}. You needn't to care
- * about @source format (device, LABEL, UUID, ...). This function parses @source
- * and calls mnt_table_find_tag() or mnt_table_find_srcpath().
+ * This is a high-level API for mnt_table_find_{srcpath,tag}. You needn't care
+ * about the @source format (device, LABEL, UUID, ...). This function parses
+ * the @source and calls mnt_table_find_tag() or mnt_table_find_srcpath().
*
* Returns: a tab entry or NULL.
*/
struct libmnt_fs *mnt_table_find_source(struct libmnt_table *tb,
const char *source, int direction)
{
- struct libmnt_fs *fs = NULL;
+ struct libmnt_fs *fs;
+ char *t = NULL, *v = NULL;
assert(tb);
@@ -721,20 +1025,15 @@ struct libmnt_fs *mnt_table_find_source(struct libmnt_table *tb,
if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
return NULL;
- DBG(TAB, mnt_debug_h(tb, "lookup SOURCE: %s", source));
-
- if (source && strchr(source, '=')) {
- char *tag, *val;
+ DBG(TAB, mnt_debug_h(tb, "lookup SOURCE: '%s'", source));
- if (blkid_parse_tag_string(source, &tag, &val) == 0) {
-
- fs = mnt_table_find_tag(tb, tag, val, direction);
-
- free(tag);
- free(val);
- }
- } else
+ if (blkid_parse_tag_string(source, &t, &v) || !mnt_valid_tagname(t))
fs = mnt_table_find_srcpath(tb, source, direction);
+ else
+ fs = mnt_table_find_tag(tb, t, v, direction);
+
+ free(t);
+ free(v);
return fs;
}
@@ -747,7 +1046,7 @@ struct libmnt_fs *mnt_table_find_source(struct libmnt_table *tb,
* @direction: MNT_ITER_{FORWARD,BACKWARD}
*
* This function is implemented by mnt_fs_match_source() and
- * mnt_fs_match_target() functions. It means that this is more expensive that
+ * mnt_fs_match_target() functions. It means that this is more expensive than
* others mnt_table_find_* function, because every @tab entry is fully evaluated.
*
* Returns: a tab entry or NULL.
@@ -761,7 +1060,7 @@ struct libmnt_fs *mnt_table_find_pair(struct libmnt_table *tb, const char *sourc
assert(tb);
assert(target);
- if (!tb || !target)
+ if (!tb || !target || !*target || !source || !*source)
return NULL;
if (direction != MNT_ITER_FORWARD && direction != MNT_ITER_BACKWARD)
return NULL;
@@ -785,7 +1084,7 @@ struct libmnt_fs *mnt_table_find_pair(struct libmnt_table *tb, const char *sourc
* @devno: device number
* @direction: MNT_ITER_{FORWARD,BACKWARD}
*
- * Note that zero could be valid device number for root pseudo filesystem (e.g.
+ * Note that zero could be a valid device number for the root pseudo filesystem (e.g.
* tmpfs).
*
* Returns: a tab entry or NULL.
@@ -819,7 +1118,7 @@ struct libmnt_fs *mnt_table_find_devno(struct libmnt_table *tb,
* tb: /proc/self/mountinfo
* fs: filesystem
* mountflags: MS_BIND or 0
- * fsroot: fs-root that will be probably used in the mountinfo file
+ * fsroot: fs-root that will probably be used in the mountinfo file
* for @fs after mount(2)
*
* For btrfs subvolumes this function returns NULL, but @fsroot properly set.
@@ -841,7 +1140,7 @@ struct libmnt_fs *mnt_table_get_fs_root(struct libmnt_table *tb,
assert(fs);
assert(fsroot);
- DBG(TAB, mnt_debug("lookup fs-root for %s", mnt_fs_get_source(fs)));
+ DBG(TAB, mnt_debug("lookup fs-root for '%s'", mnt_fs_get_source(fs)));
fstype = mnt_fs_get_fstype(fs);
@@ -945,20 +1244,20 @@ static int is_mountinfo(struct libmnt_table *tb)
}
/**
- * mnt_table_is_mounted:
+ * mnt_table_is_fs__mounted:
* @tb: /proc/self/mountinfo file
* @fstab_fs: /etc/fstab entry
*
* Checks if the @fstab_fs entry is already in the @tb table. The "swap" is
- * ignored. This function explicitly compares source, target and root of the
+ * ignored. This function explicitly compares the source, target and root of the
* filesystems.
*
* Note that source and target are canonicalized only if a cache for @tb is
* defined (see mnt_table_set_cache()). The target canonicalization may
- * triggers automount on autofs mountpoints!
+ * trigger automount on autofs mountpoints!
*
* Don't use it if you want to know if a device is mounted, just use
- * mnt_table_find_source() for the device.
+ * mnt_table_find_source() on the device.
*
* This function is designed mostly for "mount -a".
*
@@ -973,6 +1272,7 @@ int mnt_table_is_fs_mounted(struct libmnt_table *tb, struct libmnt_fs *fstab_fs)
const char *src = NULL, *tgt = NULL;
char *xtgt = NULL;
int rc = 0;
+ dev_t devno = 0;
assert(tb);
assert(fstab_fs);
@@ -980,7 +1280,7 @@ int mnt_table_is_fs_mounted(struct libmnt_table *tb, struct libmnt_fs *fstab_fs)
DBG(FS, mnt_debug_h(fstab_fs, "is FS mounted? [target=%s]",
mnt_fs_get_target(fstab_fs)));
- if (mnt_fs_is_swaparea(fstab_fs) || mnt_table_get_nents(tb) == 0) {
+ if (mnt_fs_is_swaparea(fstab_fs) || mnt_table_is_empty(tb)) {
DBG(FS, mnt_debug_h(fstab_fs, "- ignore (swap or no data)"));
return 0;
}
@@ -1004,6 +1304,14 @@ int mnt_table_is_fs_mounted(struct libmnt_table *tb, struct libmnt_fs *fstab_fs)
if (src && tb->cache && !mnt_fs_is_pseudofs(fstab_fs))
src = mnt_resolve_spec(src, tb->cache);
+ if (src && root) {
+ struct stat st;
+
+ devno = mnt_fs_get_devno(fstab_fs);
+ if (!devno && stat(src, &st) == 0 && S_ISBLK(st.st_mode))
+ devno = st.st_rdev;
+ }
+
tgt = mnt_fs_get_target(fstab_fs);
if (!tgt || !src) {
@@ -1014,7 +1322,12 @@ int mnt_table_is_fs_mounted(struct libmnt_table *tb, struct libmnt_fs *fstab_fs)
while (mnt_table_next_fs(tb, &itr, &fs) == 0) {
- if (!mnt_fs_streq_srcpath(fs, src)) {
+ int eq = mnt_fs_streq_srcpath(fs, src);
+
+ if (!eq && devno && mnt_fs_get_devno(fs) == devno)
+ eq = 1;
+
+ if (!eq) {
/* The source does not match. Maybe the source is a loop
* device backing file.
*/
@@ -1046,7 +1359,7 @@ int mnt_table_is_fs_mounted(struct libmnt_table *tb, struct libmnt_fs *fstab_fs)
}
/*
- * Compare target, try to minimize number of situations when we
+ * Compare target, try to minimize the number of situations when we
* need to canonicalize the path to avoid readlink() on
* mountpoints.
*/
@@ -1076,10 +1389,10 @@ static int parser_errcb(struct libmnt_table *tb, const char *filename, int line)
{
fprintf(stderr, "%s:%d: parse error\n", filename, line);
- return 1; /* all errors are recoverable -- this is default */
+ return 1; /* all errors are recoverable -- this is the default */
}
-struct libmnt_table *create_table(const char *file)
+struct libmnt_table *create_table(const char *file, int comments)
{
struct libmnt_table *tb;
@@ -1089,6 +1402,7 @@ struct libmnt_table *create_table(const char *file)
if (!tb)
goto err;
+ mnt_table_enable_comments(tb, comments);
mnt_table_set_parser_errcb(tb, parser_errcb);
if (mnt_table_parse_file(tb, file) != 0)
@@ -1096,7 +1410,7 @@ struct libmnt_table *create_table(const char *file)
return tb;
err:
fprintf(stderr, "%s: parsing failed\n", file);
- mnt_free_table(tb);
+ mnt_unref_table(tb);
return NULL;
}
@@ -1106,7 +1420,7 @@ int test_copy_fs(struct libmnt_test *ts, int argc, char *argv[])
struct libmnt_fs *fs;
int rc = -1;
- tb = create_table(argv[1]);
+ tb = create_table(argv[1], FALSE);
if (!tb)
return -1;
@@ -1123,10 +1437,10 @@ int test_copy_fs(struct libmnt_test *ts, int argc, char *argv[])
printf("COPY:\n");
mnt_fs_print_debug(fs, stdout);
- mnt_free_fs(fs);
+ mnt_unref_fs(fs);
rc = 0;
done:
- mnt_free_table(tb);
+ mnt_unref_table(tb);
return rc;
}
@@ -1136,8 +1450,12 @@ int test_parse(struct libmnt_test *ts, int argc, char *argv[])
struct libmnt_iter *itr = NULL;
struct libmnt_fs *fs;
int rc = -1;
+ int parse_comments = FALSE;
- tb = create_table(argv[1]);
+ if (argc == 3 && !strcmp(argv[2], "--comments"))
+ parse_comments = TRUE;
+
+ tb = create_table(argv[1], parse_comments);
if (!tb)
return -1;
@@ -1145,12 +1463,20 @@ int test_parse(struct libmnt_test *ts, int argc, char *argv[])
if (!itr)
goto done;
+ if (mnt_table_get_intro_comment(tb))
+ fprintf(stdout, "Initial comment:\n\"%s\"\n",
+ mnt_table_get_intro_comment(tb));
+
while(mnt_table_next_fs(tb, itr, &fs) == 0)
mnt_fs_print_debug(fs, stdout);
+
+ if (mnt_table_get_trailing_comment(tb))
+ fprintf(stdout, "Trailing comment:\n\"%s\"\n",
+ mnt_table_get_trailing_comment(tb));
rc = 0;
done:
mnt_free_iter(itr);
- mnt_free_table(tb);
+ mnt_unref_table(tb);
return rc;
}
@@ -1169,7 +1495,7 @@ int test_find(struct libmnt_test *ts, int argc, char *argv[], int dr)
file = argv[1], find = argv[2], what = argv[3];
- tb = create_table(file);
+ tb = create_table(file, FALSE);
if (!tb)
goto done;
@@ -1178,6 +1504,7 @@ int test_find(struct libmnt_test *ts, int argc, char *argv[], int dr)
if (!mpc)
goto done;
mnt_table_set_cache(tb, mpc);
+ mnt_unref_cache(mpc);
if (strcasecmp(find, "source") == 0)
fs = mnt_table_find_source(tb, what, dr);
@@ -1191,8 +1518,7 @@ int test_find(struct libmnt_test *ts, int argc, char *argv[], int dr)
rc = 0;
}
done:
- mnt_free_table(tb);
- mnt_free_cache(mpc);
+ mnt_unref_table(tb);
return rc;
}
@@ -1213,13 +1539,14 @@ int test_find_pair(struct libmnt_test *ts, int argc, char *argv[])
struct libmnt_cache *mpc = NULL;
int rc = -1;
- tb = create_table(argv[1]);
+ tb = create_table(argv[1], FALSE);
if (!tb)
return -1;
mpc = mnt_new_cache();
if (!mpc)
goto done;
mnt_table_set_cache(tb, mpc);
+ mnt_unref_cache(mpc);
fs = mnt_table_find_pair(tb, argv[2], argv[3], MNT_ITER_FORWARD);
if (!fs)
@@ -1228,8 +1555,7 @@ int test_find_pair(struct libmnt_test *ts, int argc, char *argv[])
mnt_fs_print_debug(fs, stdout);
rc = 0;
done:
- mnt_free_table(tb);
- mnt_free_cache(mpc);
+ mnt_unref_table(tb);
return rc;
}
@@ -1247,6 +1573,7 @@ int test_find_mountpoint(struct libmnt_test *ts, int argc, char *argv[])
if (!mpc)
goto done;
mnt_table_set_cache(tb, mpc);
+ mnt_unref_cache(mpc);
fs = mnt_table_find_mountpoint(tb, argv[1], MNT_ITER_BACKWARD);
if (!fs)
@@ -1255,8 +1582,7 @@ int test_find_mountpoint(struct libmnt_test *ts, int argc, char *argv[])
mnt_fs_print_debug(fs, stdout);
rc = 0;
done:
- mnt_free_table(tb);
- mnt_free_cache(mpc);
+ mnt_unref_table(tb);
return rc;
}
@@ -1274,7 +1600,7 @@ static int test_is_mounted(struct libmnt_test *ts, int argc, char *argv[])
return -1;
}
- fstab = create_table(argv[1]);
+ fstab = create_table(argv[1], FALSE);
if (!fstab)
goto done;
@@ -1286,6 +1612,7 @@ static int test_is_mounted(struct libmnt_test *ts, int argc, char *argv[])
if (!mpc)
goto done;
mnt_table_set_cache(tb, mpc);
+ mnt_unref_cache(mpc);
while(mnt_table_next_fs(fstab, itr, &fs) == 0) {
if (mnt_table_is_fs_mounted(tb, fs))
@@ -1300,9 +1627,8 @@ static int test_is_mounted(struct libmnt_test *ts, int argc, char *argv[])
rc = 0;
done:
- mnt_free_table(tb);
- mnt_free_table(fstab);
- mnt_free_cache(mpc);
+ mnt_unref_table(tb);
+ mnt_unref_table(fstab);
mnt_free_iter(itr);
return rc;
}
@@ -1310,7 +1636,7 @@ done:
int main(int argc, char *argv[])
{
struct libmnt_test tss[] = {
- { "--parse", test_parse, "<file> parse and print tab" },
+ { "--parse", test_parse, "<file> [--comments] parse and print tab" },
{ "--find-forward", test_find_fw, "<file> <source|target> <string>" },
{ "--find-backward", test_find_bw, "<file> <source|target> <string>" },
{ "--find-pair", test_find_pair, "<file> <source> <target>" },