+
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
- * Copyright (C) 2008-2010 Karel Zak <kzak@redhat.com>
+ * This file is part of libmount from util-linux project.
+ *
+ * Copyright (C) 2008-2018 Karel Zak <kzak@redhat.com>
*
- * This file may be redistributed under the terms of the
- * GNU Lesser General Public License.
+ * libmount is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
*/
/**
* @tb: tab pointer
*
* 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().
+ * use this function directly -- it's better to use mnt_unref_table().
*
- * The table entries (filesystems) are unrefrenced by mnt_reset_table() and
+ * The table entries (filesystems) are unreferenced by mnt_reset_table() and
* cache by mnt_unref_cache().
*/
void mnt_free_table(struct libmnt_table *tb)
*/
int mnt_table_set_intro_comment(struct libmnt_table *tb, const char *comm)
{
- char *p = NULL;
-
- if (!tb)
- return -EINVAL;
- if (comm) {
- p = strdup(comm);
- if (!p)
- return -ENOMEM;
- }
- free(tb->comm_intro);
- tb->comm_intro = p;
- return 0;
+ return strdup_to_struct_member(tb, comm_intro, comm);
}
/**
*/
int mnt_table_set_trailing_comment(struct libmnt_table *tb, const char *comm)
{
- char *p = NULL;
-
- if (!tb)
- return -EINVAL;
- if (comm) {
- p = strdup(comm);
- if (!p)
- return -ENOMEM;
- }
- free(tb->comm_tail);
- tb->comm_tail = p;
- return 0;
+ return strdup_to_struct_member(tb, comm_tail, comm);
}
/**
* same cache between more threads -- currently the cache does not provide any
* locking method.
*
- * This function increments cache reference counter. It's recomented to use
+ * This function increments cache reference counter. It's recommended to use
* mnt_unref_cache() after mnt_table_set_cache() if you want to keep the cache
* referenced by @tb only.
*
return tb ? tb->cache : NULL;
}
+/**
+ * mnt_table_find_fs:
+ * @tb: tab pointer
+ * @fs: entry to look for
+ *
+ * Checks if @fs is part of table @tb.
+ *
+ * Returns: index of @fs in table, 0 if not found or negative number in case of error.
+ */
+int mnt_table_find_fs(struct libmnt_table *tb, struct libmnt_fs *fs)
+{
+ struct list_head *p;
+ int i = 0;
+
+ if (!tb || !fs)
+ return -EINVAL;
+
+ if (list_empty(&fs->ents))
+ return 0;
+
+ /* Let's use directly list rather than mnt_table_next_fs() as we
+ * compare list entry with fs only.
+ */
+ list_for_each(p, &tb->ents) {
+ ++i;
+ if (list_entry(p, struct libmnt_fs, ents) == fs)
+ return i;
+ }
+
+ return 0;
+}
+
/**
* mnt_table_add_fs:
* @tb: tab pointer
if (!tb || !fs)
return -EINVAL;
+ if (!list_empty(&fs->ents))
+ return -EBUSY;
+
mnt_ref_fs(fs);
list_add_tail(&fs->ents, &tb->ents);
tb->nents++;
return 0;
}
+static int __table_insert_fs(
+ struct libmnt_table *tb, int before,
+ struct libmnt_fs *pos, struct libmnt_fs *fs)
+{
+ struct list_head *head = pos ? &pos->ents : &tb->ents;
+
+ if (before)
+ list_add(&fs->ents, head);
+ else
+ list_add_tail(&fs->ents, head);
+
+ tb->nents++;
+
+ DBG(TAB, ul_debugobj(tb, "insert entry: %s %s",
+ mnt_fs_get_source(fs), mnt_fs_get_target(fs)));
+ return 0;
+}
+
+/**
+ * mnt_table_insert_fs:
+ * @tb: tab pointer
+ * @before: 1 to insert before pos, 0 to insert after pos
+ * @pos: entry to specify position or NULL
+ * @fs: new entry
+ *
+ * Adds a new entry to @tb before or after a specific table entry @pos. If the
+ * @pos is NULL than add the begin of the @tab if @before is 1; or to the tail
+ * of the @tb if @before is 0.
+ *
+ * This function inncrements reference to @fs. Don't forget to use
+ * mnt_unref_fs() after mnt_table_insert_fs() if you want to keep the @fs
+ * referenced by the table only.
+
+ *
+ * Returns: 0 on success or negative number in case of error.
+ */
+int mnt_table_insert_fs(struct libmnt_table *tb, int before,
+ struct libmnt_fs *pos, struct libmnt_fs *fs)
+{
+ if (!tb || !fs)
+ return -EINVAL;
+
+ if (!list_empty(&fs->ents))
+ return -EBUSY;
+
+ if (pos && mnt_table_find_fs(tb, pos) < 1)
+ return -ENOENT;
+
+ mnt_ref_fs(fs);
+ return __table_insert_fs(tb, before, pos, fs);
+}
+
+/**
+ * mnt_table_move_fs:
+ * @src: tab pointer of source table
+ * @dst: tab pointer of destination table
+ * @before: 1 to move before position, 0 to move after position
+ * @pos: entry to specify position or NULL
+ * @fs: entry to move
+ *
+ * Removes @fs from @src table and adds it before/after a specific entry @pos
+ * of @dst table. If the @pos is NULL than add the begin of the @dst if @before
+ * is 1; or to the tail of the @dst if @before is 0.
+ *
+ * The reference counter of @fs is not modified.
+ *
+ * Returns: 0 on success or negative number in case of error.
+ */
+int mnt_table_move_fs(struct libmnt_table *src, struct libmnt_table *dst,
+ int before, struct libmnt_fs *pos, struct libmnt_fs *fs)
+{
+ if (!src || !dst || !fs)
+ return -EINVAL;
+
+ if (mnt_table_find_fs(src, fs) < 1)
+ return -ENOENT;
+
+ if (pos && mnt_table_find_fs(dst, pos) < 1)
+ return -ENOENT;
+
+ /* remove from source */
+ list_del_init(&fs->ents);
+ src->nents--;
+
+ /* insert to the destination */
+ return __table_insert_fs(dst, before, pos, fs);
+}
+
+
/**
* mnt_table_remove_fs:
* @tb: tab pointer
*/
int mnt_table_remove_fs(struct libmnt_table *tb, struct libmnt_fs *fs)
{
- if (!tb || !fs)
+ if (!tb || !fs || mnt_table_find_fs(tb, fs) < 1)
return -EINVAL;
- list_del(&fs->ents);
- INIT_LIST_HEAD(&fs->ents); /* otherwise FS still points to the list */
+ list_del_init(&fs->ents);
mnt_unref_fs(fs);
tb->nents--;
return 0;
}
+static inline struct libmnt_fs *get_parent_fs(struct libmnt_table *tb, struct libmnt_fs *fs)
+{
+ struct libmnt_iter itr;
+ struct libmnt_fs *x;
+ int parent_id = mnt_fs_get_parent_id(fs);
+
+ mnt_reset_iter(&itr, MNT_ITER_FORWARD);
+ while (mnt_table_next_fs(tb, &itr, &x) == 0) {
+ if (mnt_fs_get_id(x) == parent_id)
+ return x;
+ }
+
+ return NULL;
+}
+
/**
* 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).
+ * The function uses the parent ID from the mountinfo file to determine the
+ * root filesystem (the filesystem with the smallest ID with parent ID missing
+ * in the table). 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
*
*root = NULL;
+ /* get smallest possible ID from the table */
mnt_reset_iter(&itr, MNT_ITER_FORWARD);
while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
int id = mnt_fs_get_parent_id(fs);
}
}
+ /* go to the root node by "parent_id -> id" relation */
+ while (*root) {
+ struct libmnt_fs *x = get_parent_fs(tb, *root);
+ if (!x || x == *root)
+ break;
+ DBG(TAB, ul_debugobj(tb, " messy mountinfo, walk to %s", mnt_fs_get_target(x)));
+ *root = x;
+ }
+
return *root ? 0 : -EINVAL;
}
* backward mode iterator).
*
* @MNT_UNIQ_FORWARD: remove later mounted filesystems
- * @MNT_UNIQ_KEEPTREE: keep parent->id relation ship stil valid
+ * @MNT_UNIQ_KEEPTREE: keep parent->id relationship still valid
*
* Returns: negative number in case of error, or 0 o success.
*/
int direction)
{
char *mnt;
+ struct stat st;
if (!tb || !path || !*path)
return NULL;
DBG(TAB, ul_debugobj(tb, "lookup MOUNTPOINT: '%s'", path));
+ if (mnt_stat_mountpoint(path, &st))
+ return NULL;
+
mnt = strdup(path);
if (!mnt)
return NULL;
if (mnt_fs_streq_target(fs, path))
return fs;
}
+
+ /* try absolute path */
+ if (is_relative_path(path) && (cn = absolute_path(path))) {
+ DBG(TAB, ul_debugobj(tb, "lookup absolute TARGET: '%s'", cn));
+ mnt_reset_iter(&itr, direction);
+ while (mnt_table_next_fs(tb, &itr, &fs) == 0) {
+ if (mnt_fs_streq_target(fs, cn)) {
+ free(cn);
+ return fs;
+ }
+ }
+ free(cn);
+ }
+
if (!tb->cache || !(cn = mnt_resolve_path(path, tb->cache)))
return NULL;
return fs;
}
- /* non-canonicaled path in struct libmnt_table
+ /* non-canonical path in struct libmnt_table
* -- note that mountpoint in /proc/self/mountinfo is already
* canonicalized by the kernel
*/
* The 2nd, 3rd and 4th iterations are not performed when the @tb cache is not
* set (see mnt_table_set_cache()).
*
+ * For btrfs returns tab entry for default id.
+ *
* Note that NULL is a valid source path; it will be replaced with "none". The
* "none" is used in /proc/{mounts,self/mountinfo} for pseudo filesystems.
*
/* native paths */
mnt_reset_iter(&itr, direction);
+
while(mnt_table_next_fs(tb, &itr, &fs) == 0) {
- if (mnt_fs_streq_srcpath(fs, path))
+
+ if (mnt_fs_streq_srcpath(fs, path)) {
+#ifdef HAVE_BTRFS_SUPPORT
+ if (fs->fstype && !strcmp(fs->fstype, "btrfs")) {
+ uint64_t default_id = btrfs_get_default_subvol_id(mnt_fs_get_target(fs));
+ char *val;
+ size_t len;
+
+ if (default_id == UINT64_MAX)
+ DBG(TAB, ul_debug("not found btrfs volume setting"));
+
+ else if (mnt_fs_get_option(fs, "subvolid", &val, &len) == 0) {
+ uint64_t subvol_id;
+
+ if (mnt_parse_offset(val, len, &subvol_id)) {
+ DBG(TAB, ul_debugobj(tb, "failed to parse subvolid="));
+ continue;
+ }
+ if (subvol_id != default_id)
+ continue;
+ }
+ }
+#endif /* HAVE_BTRFS_SUPPORT */
return fs;
+ }
if (mnt_fs_get_tag(fs, NULL, NULL) == 0)
ntags++;
}
return res;
}
+#ifdef HAVE_BTRFS_SUPPORT
+static int get_btrfs_fs_root(struct libmnt_table *tb, struct libmnt_fs *fs, char **root)
+{
+ char *vol = NULL, *p;
+ size_t sz, volsz = 0;
+
+ DBG(BTRFS, ul_debug("lookup for btrfs FS root"));
+ *root = NULL;
+
+ if (mnt_fs_get_option(fs, "subvolid", &vol, &volsz) == 0) {
+ char *target;
+ struct libmnt_fs *f;
+ char subvolidstr[sizeof(stringify_value(UINT64_MAX))];
+
+ DBG(BTRFS, ul_debug(" found subvolid=%s, checking", vol));
+
+ assert (volsz + 1 < sizeof(stringify_value(UINT64_MAX)));
+ memcpy(subvolidstr, vol, volsz);
+ subvolidstr[volsz] = '\0';
+
+ target = mnt_resolve_target(mnt_fs_get_target(fs), tb->cache);
+ if (!target)
+ goto err;
+
+ DBG(BTRFS, ul_debug(" trying target=%s subvolid=%s", target, subvolidstr));
+ f = mnt_table_find_target_with_option(tb, target,
+ "subvolid", subvolidstr,
+ MNT_ITER_BACKWARD);
+ if (!tb->cache)
+ free(target);
+ if (!f)
+ goto not_found;
+
+ /* Instead of set of BACKREF queries constructing subvol path
+ * corresponding to a particular subvolid, use the one in
+ * mountinfo. Kernel keeps subvol path up to date.
+ */
+ if (mnt_fs_get_option(f, "subvol", &vol, &volsz) != 0)
+ goto not_found;
+
+ } else if (mnt_fs_get_option(fs, "subvol", &vol, &volsz) != 0) {
+ /* If fstab entry does not contain "subvol", we have to
+ * check, whether btrfs has default subvolume defined.
+ */
+ uint64_t default_id;
+ char *target;
+ struct libmnt_fs *f;
+ char default_id_str[sizeof(stringify_value(UINT64_MAX))];
+
+ DBG(BTRFS, ul_debug(" subvolid/subvol not found, checking default"));
+
+ default_id = btrfs_get_default_subvol_id(mnt_fs_get_target(fs));
+ if (default_id == UINT64_MAX)
+ goto not_found;
+
+ /* Volume has default subvolume. Check if it matches to
+ * the one in mountinfo.
+ *
+ * Only kernel >= 4.2 reports subvolid. On older
+ * kernels, there is no reasonable way to detect which
+ * subvolume was mounted.
+ */
+ target = mnt_resolve_target(mnt_fs_get_target(fs), tb->cache);
+ if (!target)
+ goto err;
+
+ snprintf(default_id_str, sizeof(default_id_str), "%llu",
+ (unsigned long long int) default_id);
+
+ DBG(BTRFS, ul_debug(" trying target=%s default subvolid=%s",
+ target, default_id_str));
+
+ f = mnt_table_find_target_with_option(tb, target,
+ "subvolid", default_id_str,
+ MNT_ITER_BACKWARD);
+ if (!tb->cache)
+ free(target);
+ if (!f)
+ goto not_found;
+
+ /* Instead of set of BACKREF queries constructing
+ * subvol path, use the one in mountinfo. Kernel does
+ * the evaluation for us.
+ */
+ DBG(BTRFS, ul_debug("setting FS root: btrfs default subvolid = %s",
+ default_id_str));
+
+ if (mnt_fs_get_option(f, "subvol", &vol, &volsz) != 0)
+ goto not_found;
+ }
+
+ DBG(BTRFS, ul_debug(" using subvol=%s", vol));
+ sz = volsz;
+ if (*vol != '/')
+ sz++;
+ *root = malloc(sz + 1);
+ if (!*root)
+ goto err;
+ p = *root;
+ if (*vol != '/')
+ *p++ = '/';
+ memcpy(p, vol, volsz);
+ *(*root + sz) = '\0';
+ return 0;
+
+not_found:
+ DBG(BTRFS, ul_debug(" not found btrfs volume setting"));
+ return 1;
+err:
+ DBG(BTRFS, ul_debug(" error on btrfs volume setting evaluation"));
+ return errno ? -errno : -1;
+}
+#endif /* HAVE_BTRFS_SUPPORT */
+
+static const char *get_cifs_unc_subdir_path (const char *unc)
+{
+ /*
+ * 1 or more slash: %*[/]
+ * 1 or more non-slash: %*[^/]
+ * number of byte read: %n
+ */
+ int share_end = 0;
+ int r = sscanf(unc, "%*[/]%*[^/]%*[/]%*[^/]%n", &share_end);
+ if (r == EOF || share_end == 0)
+ return NULL;
+ return unc + share_end;
+}
+
/*
* tb: /proc/self/mountinfo
* fs: filesystem
*
* For btrfs subvolumes this function returns NULL, but @fsroot properly set.
*
+ * If @tb is NULL then defaults to '/'.
+ *
* Returns: entry from @tb that will be used as a source for @fs if the @fs is
* bindmount.
*
{
char *root = NULL;
const char *mnt = NULL;
- const char *fstype;
struct libmnt_fs *src_fs = NULL;
assert(fs);
DBG(TAB, ul_debug("lookup fs-root for '%s'", mnt_fs_get_source(fs)));
- fstype = mnt_fs_get_fstype(fs);
-
if (tb && (mountflags & MS_BIND)) {
const char *src, *src_root;
char *xsrc = NULL;
/*
* btrfs-subvolume mount -- get subvolume name and use it as a root-fs path
*/
- else if (fstype && (!strcmp(fstype, "btrfs") || !strcmp(fstype, "auto"))) {
- char *vol = NULL, *p;
- size_t sz, volsz = 0;
-
- DBG(BTRFS, ul_debug("lookup for btrfs FS root"));
-
- if (mnt_fs_get_option(fs, "subvolid", &vol, &volsz) != 0) {
- if (mnt_fs_get_option(fs, "subvol", &vol, &volsz) != 0) {
- /* If fstab entry does not contain "subvol", we
- * have to check, whether btrfs has default
- * subvolume defined.
- */
- uint64_t default_id;
- char *target;
- struct libmnt_fs *f;
- char default_id_str[sizeof(stringify_value(UINT64_MAX))];
-
- DBG(BTRFS, ul_debug(" subvolid/subvol not set, checking default"));
-
- default_id = btrfs_get_default_subvol_id(mnt_fs_get_target(fs));
- if (default_id == UINT64_MAX)
- goto dflt;
-
- /* Volume has default subvolume. Check if it
- * matches to the one in mountinfo.
- *
- * Only kernel >= 4.2 reports subvolid. On older
- * kernels, there is no reasonable way to detect
- * which subvolume was mounted.
- */
- target = mnt_resolve_target(mnt_fs_get_target(fs), tb->cache);
- if (!target)
- goto err;
-
- snprintf(default_id_str, sizeof(default_id_str), "%llu",
- (unsigned long long int) default_id);
-
- DBG(BTRFS, ul_debug(" tring target=%s default subvolid=%s", target, default_id_str));
- f = mnt_table_find_target_with_option(tb, target,
- "subvolid", default_id_str,
- MNT_ITER_BACKWARD);
- if (!tb->cache)
- free(target);
- if (!f)
- goto dflt;
-
- /* Instead of set of BACKREF queries constructing
- * subvol path, use the one in mountinfo. Kernel
- * does the evaluation for us. */
- DBG(BTRFS, ul_debug("setting FS root: btrfs default subvolid = %s", default_id_str));
- if (mnt_fs_get_option(f, "subvol", &vol, &volsz))
- goto dflt;
- } else
- DBG(BTRFS, ul_debug(" found subvol=%s", vol));
- } else {
- char *target;
- struct libmnt_fs *f;
- char subvolidstr[sizeof(stringify_value(UINT64_MAX))];
-
- DBG(BTRFS, ul_debug(" found subvolid=%s, checking", vol));
-
- assert (volsz + 1 < sizeof(stringify_value(UINT64_MAX)));
- memcpy(subvolidstr, vol, volsz);
- subvolidstr[volsz] = '\0';
-
- target = mnt_resolve_target(mnt_fs_get_target(fs), tb->cache);
- if (!target)
- goto err;
-
- DBG(BTRFS, ul_debug(" tring target=%s subvolid=%s", target, subvolidstr));
- f = mnt_table_find_target_with_option(tb, target,
- "subvolid", subvolidstr,
- MNT_ITER_BACKWARD);
- if (!tb->cache)
- free(target);
-
- if (!f)
- goto dflt;
-
- /* Instead of set of BACKREF queries constructing
- * subvol path corresponding to a particular subvolid,
- * use the one in mountinfo. Kernel keeps subvol path
- * up to date.
- */
- if (mnt_fs_get_option(f, "subvol", &vol, &volsz))
- goto dflt;
-
- DBG(BTRFS, ul_debug(" found subvol=%s", vol));
- }
-
- sz = volsz;
- if (*vol != '/')
- sz++;
- root = malloc(sz + 1);
- if (!root)
+ else if (tb && fs->fstype &&
+ (!strcmp(fs->fstype, "btrfs") || !strcmp(fs->fstype, "auto"))) {
+ if (get_btrfs_fs_root(tb, fs, &root) < 0)
goto err;
- p = root;
- if (*vol != '/')
- *p++ = '/';
- memcpy(p, vol, volsz);
- *(root + sz) = '\0';
}
#endif /* HAVE_BTRFS_SUPPORT */
struct libmnt_fs *fs;
char *root = NULL;
+ char *src2 = NULL;
const char *src = NULL, *tgt = NULL;
char *xtgt = NULL;
int rc = 0;
dev_t devno = 0;
- DBG(FS, ul_debugobj(fstab_fs, "is FS mounted? [target=%s]",
- mnt_fs_get_target(fstab_fs)));
+ DBG(FS, ul_debugobj(fstab_fs, "mnt_table_is_fs_mounted: target=%s, source=%s",
+ mnt_fs_get_target(fstab_fs),
+ mnt_fs_get_source(fstab_fs)));
if (mnt_fs_is_swaparea(fstab_fs) || mnt_table_is_empty(tb)) {
DBG(FS, ul_debugobj(fstab_fs, "- ignore (swap or no data)"));
struct libmnt_fs *rootfs;
int flags = 0;
- if (mnt_fs_get_option(fstab_fs, "bind", NULL, NULL) == 0)
+ if (mnt_fs_get_option(fstab_fs, "bind", NULL, NULL) == 0 ||
+ mnt_fs_get_option(fstab_fs, "rbind", NULL, NULL) == 0)
flags = MS_BIND;
rootfs = mnt_table_get_fs_root(tb, fstab_fs, flags, &root);
- if (rootfs)
+ if (rootfs) {
+ const char *fstype = mnt_fs_get_fstype(rootfs);
+
src = mnt_fs_get_srcpath(rootfs);
+ if (fstype && strncmp(fstype, "nfs", 3) == 0 && root) {
+ /* NFS stores the root at the end of the source */
+ src = src2 = strappend(src, root);
+ free(root);
+ root = NULL;
+ }
+ }
}
if (!src)
}
mnt_reset_iter(&itr, MNT_ITER_FORWARD);
- DBG(FS, ul_debugobj(fstab_fs, "is mounted: src=%s, tgt=%s, root=%s", src, tgt, root));
+ DBG(FS, ul_debugobj(fstab_fs, "mnt_table_is_fs_mounted: src=%s, tgt=%s, root=%s", src, tgt, root));
while (mnt_table_next_fs(tb, &itr, &fs) == 0) {
uint64_t offset = 0;
char *val;
size_t len;
- int flags;
+ int flags = 0;
- if (!mnt_fs_is_kernel(fs) ||
- !mnt_fs_get_srcpath(fs) ||
+ if (!mnt_fs_get_srcpath(fs) ||
!startswith(mnt_fs_get_srcpath(fs), "/dev/loop"))
continue; /* does not look like loopdev */
- if (mnt_fs_get_option(fstab_fs, "offset", &val, &len) == 0 &&
- mnt_parse_offset(val, len, &offset)) {
- DBG(FS, ul_debugobj(fstab_fs, "failed to parse offset="));
- continue;
- } else
+ if (mnt_fs_get_option(fstab_fs, "offset", &val, &len) == 0) {
+ if (mnt_parse_offset(val, len, &offset)) {
+ DBG(FS, ul_debugobj(fstab_fs, "failed to parse offset="));
+ continue;
+ }
flags = LOOPDEV_FL_OFFSET;
+ }
+ DBG(FS, ul_debugobj(fs, "checking for loop: src=%s", mnt_fs_get_srcpath(fs)));
#if __linux__
- if (loopdev_is_used(mnt_fs_get_srcpath(fs), src, offset, flags))
- break;
+ if (!loopdev_is_used(mnt_fs_get_srcpath(fs), src, offset, 0, flags))
+ continue;
+
+ DBG(FS, ul_debugobj(fs, "used loop"));
#endif
}
if (root) {
- const char *r = mnt_fs_get_root(fs);
- if (!r || strcmp(r, root) != 0)
- continue;
+ const char *fstype = mnt_fs_get_fstype(fs);
+
+ if (fstype && strcmp(fstype, "cifs") == 0) {
+ const char *unc_subdir = get_cifs_unc_subdir_path(src);
+ const char *path_on_fs = mnt_fs_get_root(fs);
+ if (!unc_subdir || !path_on_fs || !streq_paths(unc_subdir, path_on_fs))
+ continue;
+ } else {
+ const char *r = mnt_fs_get_root(fs);
+ if (!r || strcmp(r, root) != 0)
+ continue;
+ }
}
/*
free(root);
DBG(TAB, ul_debugobj(tb, "mnt_table_is_fs_mounted: %s [rc=%d]", src, rc));
+ free(src2);
return rc;
}
return 1; /* all errors are recoverable -- this is the default */
}
-struct libmnt_table *create_table(const char *file, int comments)
+static struct libmnt_table *create_table(const char *file, int comments)
{
struct libmnt_table *tb;
return NULL;
}
-int test_copy_fs(struct libmnt_test *ts, int argc, char *argv[])
+static int test_copy_fs(struct libmnt_test *ts, int argc, char *argv[])
{
struct libmnt_table *tb;
struct libmnt_fs *fs;
return rc;
}
-int test_parse(struct libmnt_test *ts, int argc, char *argv[])
+static int test_parse(struct libmnt_test *ts, int argc, char *argv[])
{
struct libmnt_table *tb = NULL;
struct libmnt_iter *itr = NULL;
return rc;
}
-int test_find(struct libmnt_test *ts, int argc, char *argv[], int dr)
+static int test_find_idx(struct libmnt_test *ts, int argc, char *argv[])
+{
+ struct libmnt_table *tb;
+ struct libmnt_fs *fs = NULL;
+ struct libmnt_cache *mpc = NULL;
+ const char *file, *what;
+ int rc = -1;
+
+ if (argc != 3) {
+ fprintf(stderr, "try --help\n");
+ return -EINVAL;
+ }
+
+ file = argv[1], what = argv[2];
+
+ tb = create_table(file, FALSE);
+ if (!tb)
+ goto done;
+
+ /* create a cache for canonicalized paths */
+ mpc = mnt_new_cache();
+ if (!mpc)
+ goto done;
+ mnt_table_set_cache(tb, mpc);
+ mnt_unref_cache(mpc);
+
+ fs = mnt_table_find_target(tb, what, MNT_ITER_BACKWARD);
+
+ if (!fs)
+ fprintf(stderr, "%s: not found '%s'\n", file, what);
+ else {
+ int idx = mnt_table_find_fs(tb, fs);
+
+ if (idx < 1)
+ fprintf(stderr, "%s: not found '%s' fs pointer", file, what);
+ else {
+ printf("%s index is %d\n", what, idx);
+ rc = 0;
+ }
+ }
+done:
+ mnt_unref_table(tb);
+ return rc;
+}
+
+static int test_find(struct libmnt_test *ts, int argc, char *argv[], int dr)
{
struct libmnt_table *tb;
struct libmnt_fs *fs = NULL;
return rc;
}
-int test_find_bw(struct libmnt_test *ts, int argc, char *argv[])
+static int test_find_bw(struct libmnt_test *ts, int argc, char *argv[])
{
return test_find(ts, argc, argv, MNT_ITER_BACKWARD);
}
-int test_find_fw(struct libmnt_test *ts, int argc, char *argv[])
+static int test_find_fw(struct libmnt_test *ts, int argc, char *argv[])
{
return test_find(ts, argc, argv, MNT_ITER_FORWARD);
}
-int test_find_pair(struct libmnt_test *ts, int argc, char *argv[])
+static int test_find_pair(struct libmnt_test *ts, int argc, char *argv[])
{
struct libmnt_table *tb;
struct libmnt_fs *fs;
return rc;
}
-int test_find_mountpoint(struct libmnt_test *ts, int argc, char *argv[])
+static int test_find_mountpoint(struct libmnt_test *ts, int argc, char *argv[])
{
struct libmnt_table *tb;
struct libmnt_fs *fs;
struct libmnt_fs *fs;
struct libmnt_iter *itr = NULL;
struct libmnt_cache *mpc = NULL;
- int rc;
+ int writable = 0;
+ const char *path = NULL;
+
+ if (mnt_has_regular_mtab(&path, &writable) == 1 && writable == 0)
+ tb = mnt_new_table_from_file(path);
+ else
+ tb = mnt_new_table_from_file("/proc/self/mountinfo");
- tb = mnt_new_table_from_file("/proc/self/mountinfo");
if (!tb) {
fprintf(stderr, "failed to parse mountinfo\n");
return -1;
mnt_table_set_cache(tb, mpc);
mnt_unref_cache(mpc);
- while(mnt_table_next_fs(fstab, itr, &fs) == 0) {
+ while (mnt_table_next_fs(fstab, itr, &fs) == 0) {
if (mnt_table_is_fs_mounted(tb, fs))
printf("%s already mounted on %s\n",
mnt_fs_get_source(fs),
mnt_fs_get_target(fs));
}
- rc = 0;
done:
mnt_unref_table(tb);
mnt_unref_table(fstab);
mnt_free_iter(itr);
- return rc;
+ return 0;
}
/* returns 0 if @a and @b targets are the same */
{ "--find-backward", test_find_bw, "<file> <source|target> <string>" },
{ "--uniq-target", test_uniq, "<file>" },
{ "--find-pair", test_find_pair, "<file> <source> <target>" },
+ { "--find-fs", test_find_idx, "<file> <target>" },
{ "--find-mountpoint", test_find_mountpoint, "<path>" },
{ "--copy-fs", test_copy_fs, "<file> copy root FS from the file" },
- { "--is-mounted", test_is_mounted, "<fstab> check what from <file> are already mounted" },
+ { "--is-mounted", test_is_mounted, "<fstab> check what from fstab is already mounted" },
{ NULL }
};