summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xinspect.py11
-rw-r--r--tools/__init__.py2
-rw-r--r--tools/inspect_apps.py67
-rw-r--r--tools/inspect_os.py4
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"
]
@@ -100,6 +102,71 @@ def list_applications_deb(path):
@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.