From c8d64e153413042f79d21c04b2b82365ae2714d4 Mon Sep 17 00:00:00 2001 From: Mürsel Türk Date: Thu, 8 Sep 2022 22:30:54 +0200 Subject: Add support for arch-based distros --- inspect.py | 11 ++++++--- tools/__init__.py | 2 -- tools/inspect_apps.py | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++ tools/inspect_os.py | 4 +++ 4 files changed, 79 insertions(+), 5 deletions(-) diff --git a/inspect.py b/inspect.py index d5f41d4..c73f87e 100755 --- a/inspect.py +++ b/inspect.py @@ -8,6 +8,7 @@ import sys from tools import libvslvm, lklfuse, nbdfuse, subfiles, unmount, rmdir from tools.inspect_apps import ( list_applications_deb, + list_applications_pacman, list_applications_rpm, list_applications_windows ) @@ -18,6 +19,7 @@ fmt = "{asctime}, {name}:{lineno}:{funcName}(), {levelname}, {message}" logging.basicConfig(level=logging.DEBUG, format=fmt, style="{") DEB = re.compile(r"^(Debian|Ubuntu|Linux\sMint|LMDE).*$") +PACMAN = re.compile(r"^(Arch|Manjaro).*$") RPM = re.compile(r"^(CentOS|AlmaLinux|Scientific|Rocky|Oracle|openSUSE|Fedora).*$") # noqa WIN = re.compile(r"^(Microsoft|Windows).*$") @@ -62,12 +64,15 @@ def main(vmdk_path): if os_info: break + os_name = os_info.get("name", "") for fspath, _ in fs_mps: - if DEB.match(os_info["name"]): + if DEB.match(os_name): apps = list_applications_deb(fspath) - elif RPM.match(os_info["name"]): + elif PACMAN.match(os_name): + apps = list_applications_pacman(fspath) + elif RPM.match(os_name): apps = list_applications_rpm(fspath) - elif WIN.match(os_info["name"]): + elif WIN.match(os_name): apps = list_applications_windows(fspath) if apps: break diff --git a/tools/__init__.py b/tools/__init__.py index d97a80a..374823f 100644 --- a/tools/__init__.py +++ b/tools/__init__.py @@ -78,7 +78,6 @@ def rmdir(path): return True -@log def subdirs(path): """Yield directory names under given path using os.scandir. @@ -91,7 +90,6 @@ def subdirs(path): yield entry.name -@log def subfiles(path): """Yield file names under given path using os.scandir. diff --git a/tools/inspect_apps.py b/tools/inspect_apps.py index 58f0f0f..6c814d2 100644 --- a/tools/inspect_apps.py +++ b/tools/inspect_apps.py @@ -1,11 +1,13 @@ import logging import os +import re import tempfile from . import log, subdirs __all__ = [ "list_applications_deb", + "list_applications_pacman", "list_applications_rpm", "list_applications_windows" ] @@ -99,6 +101,71 @@ def list_applications_deb(path): return pkgs +@log +def list_applications_pacman(path): + """Find all packages installed on a arch-based linux distribution. + + See also: + https://wiki.archlinux.org/title/pacman + + Args: + path (str): Path to the mounted filesystem. + + Returns: + List of packages. For example: + [{'name': 'python', 'version': '3.10.6-1'}, ...] + """ + pacman_db = None + + locations = [ + "var/lib/pacman/local", + "lib/pacman/local" # separated /var partition + ] + + for location in locations: + db = os.path.join(path, location) + if os.path.exists(db): + pacman_db = db + break + + # Just in case the system is using btrfs. + if pacman_db is None: + for dir in subdirs(path): + new_path = os.path.join(path, dir) + for location in locations: + db = os.path.join(new_path, location) + if os.path.exists(db): + pacman_db = db + break + if pacman_db is not None: + break + + if pacman_db is None: + L.debug("pacman database not found") + return [] + + pkgs = [] + for dir in subdirs(pacman_db): + desc = os.path.join(pacman_db, dir, "desc") + kv = {} + with open(desc) as f: + sections = re.split(r"\n(?=%[A-Z]+%)", f.read()) + for section in sections: + section = section.strip() + if lines := section.split("\n"): + k = lines[0].strip("%") + n = len(lines) + v = "" if n < 2 else lines[1:] if n > 2 else lines[1] + kv[k] = v + if (name := kv.get("NAME", "")) and (version := kv.get("VERSION", "")): + pkgs.append({ + "name": name, + "version": version + }) + + return pkgs + + @log def list_applications_rpm(path): """Find all packages installed on a rpm-based linux distribution. diff --git a/tools/inspect_os.py b/tools/inspect_os.py index ed4ee45..9848c2e 100644 --- a/tools/inspect_os.py +++ b/tools/inspect_os.py @@ -72,6 +72,10 @@ def get_linux_os_info(path): kv[k] = v name = kv.get("NAME", "") version = kv.get("VERSION", kv.get("VERSION_ID", "")) + # Arch-based distros have neither VERSION nor VERSION_ID. + # These are using a rolling release model. + if not version: + version = kv.get("BUILD_ID", "") elif "system-release" in release_files: # RedHat (RHEL) provides the redhat-release file. However, it does not # seem to be reliable for determining which operating system it is. -- cgit v1.2.3-55-g7522