From: Karel Zak Date: Wed, 1 Feb 2017 15:12:55 +0000 (+0100) Subject: libmount: make rootfs lookup by parent-id more robust X-Git-Tag: v2.29.2~15 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4bb57955ec930e281d52a39619c5768e20f4b4a0;p=thirdparty%2Futil-linux.git libmount: make rootfs lookup by parent-id more robust The root FS id really does not have to be the smallest one. [kzak@redhat.com: - backported to stable branch without reg.test] Reported-by: Michal Soltys Signed-off-by: Karel Zak --- diff --git a/libmount/src/tab.c b/libmount/src/tab.c index 85fd427b54..0eeefe76d6 100644 --- a/libmount/src/tab.c +++ b/libmount/src/tab.c @@ -438,15 +438,31 @@ int mnt_table_remove_fs(struct libmnt_table *tb, struct libmnt_fs *fs) 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 * @@ -469,6 +485,7 @@ int mnt_table_get_root_fs(struct libmnt_table *tb, struct libmnt_fs **root) *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); @@ -479,6 +496,15 @@ int mnt_table_get_root_fs(struct libmnt_table *tb, struct libmnt_fs **root) } } + /* 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; }