Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Step:FrontRunner
kdump.25799
kdump-Mount-and-device-resolution-using-libmoun...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File kdump-Mount-and-device-resolution-using-libmount-and-lsblk.patch of Package kdump.25799
From: Petr Tesarik <ptesarik@suse.com> Date: Mon, 1 Mar 2021 12:24:52 +0100 Subject: Mount and device resolution using libmount and lsblk References: bsc#1180513 Upstream: merged Git-commit: cdd154fe371bc945b4a06dfbab70c813f2cef3ac Implement parsing of mount tables and resolution of the underlying block devices with lsblk, including special handling of /dev/root. Signed-off-by: Petr Tesarik <ptesarik@suse.com> References: jsc#SLE-13779 --- CMakeLists.txt | 5 kdumptool/CMakeLists.txt | 2 kdumptool/mounts.cc | 415 +++++++++++++++++++++++++++++++++++++++++++++++ kdumptool/mounts.h | 269 ++++++++++++++++++++++++++++++ 4 files changed, 691 insertions(+) create mode 100644 kdumptool/mounts.cc create mode 100644 kdumptool/mounts.h --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -130,6 +130,11 @@ ENDIF(NOT LIBSSL_FOUND) # libblkid pkg_check_modules(BLKID REQUIRED blkid) +# libmount +pkg_check_modules(LIBMOUNT REQUIRED mount) +SET(EXTRA_LIBS ${EXTRA_LIBS} ${LIBMOUNT_LIBRARIES}) +INCLUDE_DIRECTORIES(${LIBMOUNT_INCLUDE_DIRS}) + # # Check for FADUMP # --- a/kdumptool/CMakeLists.txt +++ b/kdumptool/CMakeLists.txt @@ -58,6 +58,8 @@ SET(COMMON_SRC socket.h ledblink.cc ledblink.h + mounts.cc + mounts.h progress.cc progress.h savedump.cc --- /dev/null +++ b/kdumptool/mounts.cc @@ -0,0 +1,415 @@ +/* + * (c) 2014, Petr Tesarik <ptesarik@suse.de>, SUSE LINUX Products GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ + +#include <cctype> +#include <fstream> +#include <iostream> +#include <map> +#include <sstream> +#include <string> + +#include <unistd.h> + +// for makedev() and friends: +#include <sys/sysmacros.h> + +#include "global.h" +#include "debug.h" +#include "mounts.h" +#include "process.h" + +using std::string; +using std::ifstream; +using std::istringstream; +using std::ostringstream; + +//{{{ MountPoint --------------------------------------------------------------- + +// ----------------------------------------------------------------------------- +MountPoint& MountPoint::operator=(MountPoint const& other) +{ + m_fs = other.m_fs; + m_ctarget = other.m_ctarget; + return *this; +} + +// ----------------------------------------------------------------------------- +void MountPoint::setFS(MntFS const& fs) +{ + m_fs = fs; + m_ctarget.clear(); +} + +// ----------------------------------------------------------------------------- +FilePath const& MountPoint::canonicalTarget(void) +{ + if (m_ctarget.empty()) { + FilePath target = mnt_fs_get_target(m_fs); + m_ctarget = target.getCanonicalPath(); + } + return m_ctarget; +} + +//}}} +//{{{ MountTable --------------------------------------------------------------- + +// ----------------------------------------------------------------------------- +MountTable::iterator::iterator(MountTable const& table, int direction) + : m_tb(table.m_tb), m_mp(NULL) +{ + m_it = mnt_new_iter(MNT_ITER_FORWARD); + if (!m_it) + throw KError("Failed to initialize libmount iterator"); +} + +// ----------------------------------------------------------------------------- +MountTable::iterator::iterator(iterator const& other) + : m_tb(other.m_tb), m_mp(other.m_mp) +{ + m_it = mnt_new_iter(other.getDirection()); + if (!m_it) + throw KError("Failed to initialize libmount iterator"); + mnt_table_set_iter(m_tb, m_it, m_mp.fs()); +} + +// ----------------------------------------------------------------------------- +MountTable::iterator::~iterator() +{ + mnt_free_iter(m_it); +} + +// ----------------------------------------------------------------------------- +MountTable::iterator& MountTable::iterator::operator=(iterator const& other) +{ + m_tb = other.m_tb; + m_mp = other.m_mp; + mnt_table_set_iter(m_tb, m_it, m_mp.fs()); + return *this; +} + +// ----------------------------------------------------------------------------- +MountTable::iterator& MountTable::iterator::operator++() +{ + struct libmnt_fs *fs; + if (mnt_table_next_fs(m_tb, m_it, &fs) < 0) + throw KError("Failed to iterate mount table"); + m_mp.setFS(fs); + return *this; +} + +// ----------------------------------------------------------------------------- +MountTable::MountTable(void) + : m_tb(mnt_new_table()) +{ + if (!m_tb) + throw KError("Failed to initialize libmount table"); +} + +// ----------------------------------------------------------------------------- +MountTable::iterator MountTable::find_mount(FilePath const& path) +{ + Debug::debug()->trace("MountTable::find_mount(%s)", path.c_str()); + + FilePath cpath = path.getCanonicalPath(); + size_t bestlen = 0; + iterator it(*this, MNT_ITER_FORWARD); + iterator best = it; + while (++it) { + if (it->isPseudoFS() || it->isSwapArea()) + continue; + + FilePath const& ctarget = it->canonicalTarget(); + if (ctarget.length() >= bestlen && + cpath.compare(0, ctarget.length(), ctarget) == 0) { + best = it; + bestlen = ctarget.length(); + } + } + return best; +} + +//}}} +//{{{ KernelMountTable --------------------------------------------------------- + +const char KernelMountTable::_PATH_PROC_MOUNTS[] = "/proc/mounts"; +const char KernelMountTable::_PATH_PROC_MOUNTINFO[] = "/proc/self/mountinfo"; + +// ----------------------------------------------------------------------------- +KernelMountTable::KernelMountTable(void) + : MountTable() +{ + const char *path = access(_PATH_PROC_MOUNTINFO, R_OK) == 0 + ? _PATH_PROC_MOUNTINFO + : _PATH_PROC_MOUNTS; + + if (mnt_table_parse_file(m_tb, path) != 0) + throw KError("Can't read kernel mount table"); +} + +//}}} +//{{{ FstabMountTable ---------------------------------------------------------- + +// ----------------------------------------------------------------------------- +FstabMountTable::FstabMountTable(void) + : MountTable() +{ + if (mnt_table_parse_fstab(m_tb, NULL) != 0) + throw KError("Can't read fstab"); +} + +//}}} +//{{{ PathMountPoint ----------------------------------------------------------- + +// ----------------------------------------------------------------------------- +PathMountPoint::PathMountPoint(FilePath const& path) + : MountPoint(NULL) +{ + Debug::debug()->trace("PathMountPoint::PathMountPoint(%s)", path.c_str()); + + MountTable::iterator mp_kernel = + KernelMountTable().find_mount(path); + MountTable::iterator mp_fstab = + FstabMountTable().find_mount(path); + MountTable::iterator *best; + + if (!mp_fstab) { + Debug::debug()->dbg("%s: No fstab entry", path.c_str()); + best = &mp_kernel; + } else if (!mp_kernel) { + Debug::debug()->dbg("%s: No kernel entry", path.c_str()); + best = &mp_fstab; + } else { + Debug::debug()->dbg("%s: Kernel entry: %s, fstab entry: %s", + path.c_str(), + mp_kernel->canonicalTarget().c_str(), + mp_fstab->canonicalTarget().c_str()); + + // both exist: choose the longer one, or fstab if same length + if (mp_kernel->canonicalTarget().length() > + mp_fstab->canonicalTarget().length()) { + best = &mp_kernel; + } else { + best = &mp_fstab; + } + } + MountPoint::operator=(**best); + + if (*best) { + Debug::debug()->dbg("Filesystem on %s mounted at %s", + source(), target()); + } else { + Debug::debug()->dbg("No filesystem found!"); + } +} + +//}}} +//{{{ PathResolver ------------------------------------------------------------- + +const char PathResolver::_PATH_DEV_BLOCK_[] = "/dev/block/"; +const char PathResolver::_PATH_DEV_ROOT[] = "/dev/root"; +const char PathResolver::_PATH_PROC_CMDLINE[] = "/proc/cmdline"; + +FilePath PathResolver::m_devroot; + +// ----------------------------------------------------------------------------- +PathResolver::PathResolver() +{ + m_cache = mnt_new_cache(); + if (!m_cache) + throw KError("Cannot allocate file path cache"); +} + +// ----------------------------------------------------------------------------- +PathResolver::~PathResolver() +{ + mnt_free_cache(m_cache); +} + +// ----------------------------------------------------------------------------- +bool PathResolver::_devroot_maj_min(void) +{ + size_t pos = m_devroot.find(':'); + if (pos == string::npos) + return false; + KString devmajor(m_devroot, 0, pos); + if (!devmajor.isNumber()) + return false; + + KString devminor(m_devroot, pos + 1); + pos = devminor.find(':'); + if (pos != string::npos) { + KString rest(devminor, pos + 1); + if (!rest.isNumber()) + return false; + devminor.resize(pos); + } + if (!devminor.isNumber()) + return false; + + ostringstream os; + os << _PATH_DEV_BLOCK_ << devmajor << ':' << devminor; + m_devroot = os.str(); + return true; +} + +// ----------------------------------------------------------------------------- +bool PathResolver::_devroot_hexhex(void) +{ + dev_t dev; + if (!m_devroot.isHexNumber()) + return false; + + istringstream is(m_devroot); + is >> std::hex >> dev; + + ostringstream os; + os << _PATH_DEV_BLOCK_ << major(dev) << ':' << minor(dev); + m_devroot = os.str(); + return true; +} + +// ----------------------------------------------------------------------------- +FilePath& PathResolver::system_root(void) +{ + Debug::debug()->trace("PathResolver::system_root()"); + + if (m_devroot.empty()) { + ifstream fin(_PATH_PROC_CMDLINE); + if (!fin) + throw KError(string("Unable to open ") + _PATH_PROC_CMDLINE + "."); + + const string param = "root="; + while (fin.good()) { + bool in_quote = false; + KString s; + char c; + while (fin.get(c) && !(!in_quote && isspace(c))) { + s += c; + if (c == '"') + in_quote = !in_quote; + } + + // remove surrounding quotes + if (!s.empty() && *s.begin() == '"') { + s.erase(s.begin()); + string::iterator last = s.end(); + if (last != s.begin() && *--last == '"') + s.erase(last); + } + + if (s == "--") + break; + + if (s.startsWith(param)) + m_devroot.assign(s, param.length()); + } + fin.close(); + + if (!m_devroot.empty()) { + Debug::debug()->dbg("Kernel commandline says root=%s", + m_devroot.c_str()); + if (!_devroot_maj_min() && + !_devroot_hexhex()) { + m_devroot = resolve(m_devroot); + } + Debug::debug()->dbg("System root resolved as %s", + m_devroot.c_str()); + } else { + Debug::debug()->dbg("System root cannot be determined"); + m_devroot = _PATH_DEV_ROOT; + } + } + return m_devroot; +} + +// ----------------------------------------------------------------------------- +FilePath PathResolver::resolve(string const& spec) +{ + Debug::debug()->trace("PathResolver::resolve(%s)", spec.c_str()); + + char *path = mnt_resolve_spec(spec.c_str(), m_cache); + if (!path) + throw KError("Cannot resolve path: " + spec); + FilePath ret = path; + if (ret == _PATH_DEV_ROOT) + return system_root(); + return ret; +} + +//}}} +//{{{ FilesystemTypeMap -------------------------------------------------------- + +// ----------------------------------------------------------------------------- +void FilesystemTypeMap::addPath(FilePath const& path) +{ + Debug::debug()->trace("FilesystemTypeMap::addPath(%s)", path.c_str()); + + PathMountPoint mnt(path); + if (mnt) + m_sources.insert(m_resolver.resolve(mnt.source())); +} + +// ----------------------------------------------------------------------------- +StringStringMap& FilesystemTypeMap::devices(void) +{ + Debug::debug()->trace("FilesystemTypeMap::devices()"); + + ProcessFilter p; + + StringVector args; + static const char *const opts[] = { + "--raw", "--noheadings", "--inverse", + "--output", "FSTYPE,PATH", + NULL + }; + for (const char *const *p = opts; *p; ++p) + args.push_back(*p); + args.insert(args.end(), m_sources.begin(), m_sources.end()); + + ostringstream stdoutStream, stderrStream; + p.setStdout(&stdoutStream); + p.setStderr(&stderrStream); + int ret = p.execute("lsblk", args); + if (ret != 0) { + KString error = stderrStream.str(); + throw KError("lsblk failed: " + error.trim()); + } + + KString out = stdoutStream.str(); + size_t pos = 0; + while (pos < out.length()) { + size_t end = out.find_first_of("\r\n", pos); + size_t sep = out.find(' ', pos); + if (sep < end) { + string type = out.substr(pos, sep - pos); + string path = out.substr(sep + 1, end - sep - 1); + m_devices[path] = type; + + Debug::debug()->dbg("Device %s type %s", + path.c_str(), type.c_str()); + } + pos = out.find_first_not_of("\r\n", end); + } + + return m_devices; +} + +//}}} + +// vim: set sw=4 ts=4 fdm=marker et: :collapseFolds=1: --- /dev/null +++ b/kdumptool/mounts.h @@ -0,0 +1,269 @@ +/* + * (c) 2021, Petr Tesarik <ptesarik@suse.de>, SUSE Linux Software Solutions GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301, USA. + */ +#ifndef MOUNTS_H +#define MOUNTS_H + +#include <set> + +#include "global.h" +#include "fileutil.h" + +#include <libmount.h> + +//{{{ MntFS -------------------------------------------------------------------- + +/** + * Refcounting wrapper for struct libmnt_fs* + */ +class MntFS { + struct libmnt_fs *m_fs; + + public: + MntFS(struct libmnt_fs *fs) + : m_fs(fs) + { mnt_ref_fs(m_fs); } + + MntFS(MntFS const& other) + : m_fs(other.m_fs) + { mnt_ref_fs(m_fs); } + + ~MntFS() + { mnt_unref_fs(m_fs); } + + /** + * Typecast to struct libmnt_fs*, so instances of this class + * can be used as arguments to libmount functions. + */ + operator struct libmnt_fs*() const + { return m_fs; } + + /** + * Assign a new value, taking care of rerence counts. + */ + MntFS& operator=(MntFS const& other) + { + mnt_unref_fs(m_fs); + m_fs = other.m_fs; + mnt_ref_fs(m_fs); + return *this; + } +}; + +//}}} + +//{{{ MntTable ----------------------------------------------------------------- + +/* + * Refcounting wrapper for struct libmnt_table* + */ +class MntTable { + struct libmnt_table *m_tb; + + public: + MntTable(struct libmnt_table *tb) + : m_tb(tb) + { mnt_ref_table(m_tb); } + + MntTable(MntTable const& other) + : m_tb(other.m_tb) + { mnt_ref_table(m_tb); } + + ~MntTable() + { mnt_unref_table(m_tb); } + + /** + * Typecast to struct libmnt_table*, so instances of this class + * can be used as arguments to libmount functions. + */ + operator struct libmnt_table*() const + { return m_tb; } + + /** + * Assign a new value, taking care of rerence counts. + */ + MntTable& operator=(MntTable const& other) + { + mnt_unref_table(m_tb); + m_tb = other.m_tb; + mnt_ref_table(m_tb); + return *this; + } +}; + +//}}} + +//{{{ MountPoint --------------------------------------------------------------- + +class MountPoint { + protected: + MntFS m_fs; + + private: + FilePath m_ctarget; + + public: + MountPoint(const MntFS& fs) + : m_fs(fs) + { } + + MountPoint(MountPoint const& other) + : m_fs(other.m_fs), m_ctarget(other.m_ctarget) + { } + + operator bool() const + { return (bool)m_fs; } + + MountPoint& operator=(MountPoint const& other); + + MntFS& fs(void) + { return m_fs; } + + void setFS(MntFS const& fs); + + FilePath const& canonicalTarget(void); + + bool isNetFS(void) + { return mnt_fs_is_netfs(m_fs); } + + bool isPseudoFS(void) + { return mnt_fs_is_pseudofs(m_fs); } + + bool isSwapArea(void) + { return mnt_fs_is_swaparea(m_fs); } + + const char *source(void) + { return mnt_fs_get_source(m_fs); } + + const char *target(void) + { return mnt_fs_get_target(m_fs); } +}; + +//}}} +//{{{ MountTable --------------------------------------------------------------- + +class MountTable { + protected: + MntTable m_tb; + + public: + class iterator { + struct libmnt_iter *m_it; + MntTable m_tb; + MountPoint m_mp; + + public: + iterator(MountTable const& table, int direction); + iterator(iterator const& other); + ~iterator(); + + iterator& operator=(iterator const& other); + + operator bool() const + { return (bool)m_mp; } + + iterator& operator++(); + iterator operator++(int) + { iterator temp = *this; ++(*this); return temp; } + + MountPoint const& operator*() const { return m_mp; } + MountPoint* operator->() { return &m_mp; } + + int getDirection(void) const + { return mnt_iter_get_direction(m_it); } + }; + + MountTable(void); + + iterator find_mount(FilePath const& path); +}; + +//}}} +//{{{ KernelMountTable --------------------------------------------------------- + +class KernelMountTable : public MountTable { + public: + KernelMountTable(void); + + private: + static const char _PATH_PROC_MOUNTS[]; + static const char _PATH_PROC_MOUNTINFO[]; +}; + +//}}} +//{{{ FstabMountTable ---------------------------------------------------------- + +class FstabMountTable : public MountTable { + public: + FstabMountTable(void); +}; + +//}}} +//{{{ PathMountPoint ----------------------------------------------------------- + +class PathMountPoint : public MountPoint { + public: + PathMountPoint(FilePath const& path); + PathMountPoint(PathMountPoint const &other) + : MountPoint(other) + { } +}; + +//}}} +//{{{ PathResolver ------------------------------------------------------------- + +class PathResolver { + protected: + struct libmnt_cache *m_cache; + + public: + PathResolver(); + ~PathResolver(); + + FilePath resolve(std::string const& spec); + FilePath& system_root(void); + + private: + static const char _PATH_DEV_BLOCK_[]; + static const char _PATH_DEV_ROOT[]; + static const char _PATH_PROC_CMDLINE[]; + static FilePath m_devroot; + + bool _devroot_maj_min(void); + bool _devroot_hexhex(void); +}; + +//}}} +//{{{ FilesystemTypeMap -------------------------------------------------------- + +class FilesystemTypeMap { + protected: + PathResolver m_resolver; + std::set<std::string> m_sources; + StringStringMap m_devices; + + public: + void addPath(FilePath const& path); + StringStringMap& devices(void); +}; + +//}}} + +#endif /* MOUNTS_H */ + +// vim: set sw=4 ts=4 fdm=marker et: :collapseFolds=1:
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor