#!/usr/bin/env python3 # Copyright 2025 sysmocom - s.f.m.c. GmbH # SPDX-License-Identifier: GPL-2.0-or-later import argparse import copy import fnmatch import os import shutil import string import subprocess import sys args = None def parse_arguments(): global args parser = argparse.ArgumentParser( description="Install debug packages for all installed Osmocom packages and dependencies" ) parser.add_argument( "-y", "--yes", action="store_true", help="run non-interactively", ) args = parser.parse_args() def check_package_manager(): rel = "/etc/os-release" if not os.path.exists(rel): print(f"ERROR: {rel} does not exist") sys.exit(1) with open(rel) as f: for line in f: if "ID=debian" in line or "ID_LIKE=debian" in line: return print("ERROR: only 'apt' is supported by this script") sys.exit(1) def check_requirements(): if not shutil.which("apt-rdepends"): print("ERROR: please install apt-rdepends first:") print(" apt install apt-rdepends") sys.exit(1) def get_installed_osmocom_packages(): """Get installed Osmocom packages by parsing 'dpkg -l' output. Lines with installed packages look like this: 'ii libosmocore22:amd64 ...'""" ret = set() p = subprocess.run(["dpkg", "-l"], capture_output=True, text=True, check=True) lines = p.stdout.split("\n") patterns = [ "gapk*", "libasn1c*", "libgtpnl*", "libosmo*", "libsmpp34*", "osmo-*", ] for line in lines: if not line.startswith("ii "): continue package = line.split(" ", 4)[2].split(":", 1)[0] for pattern in patterns: if fnmatch.fnmatch(package, pattern): ret.add(package) break return ret def get_recursive_dependencies(pkgs): """Iterate over apt-rdepends output, it looks like: osmo-mgw Depends: libc6 (>= 2.34) Depends: libosmoabis13""" ret = copy.copy(pkgs) p = subprocess.run(["apt-rdepends"] + list(pkgs), capture_output=True, text=True, check=True) lines = p.stdout.split("\n") for line in lines: if not line.startswith(" Depends: "): continue ret.add(line.strip().split(" ", 3)[1]) return ret def get_debug_pkgs(): p = subprocess.run("apt-cache pkgnames | grep -- -dbg", shell=True, text=True, capture_output=True) return p.stdout.split("\n") def get_debug_pkgs_relevant(debug_pkgs, pkgs_with_deps): ret = [] for pkg in pkgs_with_deps: names = [f"{pkg}-dbg", f"{pkg}-dbgsym"] pkg_nodigits = pkg.rstrip(string.digits) if pkg != pkg_nodigits: names += [f"{pkg_nodigits}-dbg", f"{pkg_nodigits}-dbgsym"] for name in names: if name in debug_pkgs: ret += [name] break return ret def install_packages(pkgs): cmd = [] if os.geteuid() != 0: cmd += ["sudo"] cmd += ["apt", "install"] if args.yes: cmd += ["-y"] cmd += pkgs print(f"+ {cmd}") p = subprocess.run(cmd) sys.exit(p.returncode) def main(): parse_arguments() check_package_manager() check_requirements() print("Getting installed Osmocom packages...") pkgs = get_installed_osmocom_packages() print("Getting dependencies of installed Osmocom packages...") pkgs_with_deps = get_recursive_dependencies(pkgs) print("Getting available debug packages...") debug_pkgs = get_debug_pkgs() print("Getting relevant debug packages...") debug_pkgs_relevant = get_debug_pkgs_relevant(debug_pkgs, pkgs_with_deps) debug_pkgs_relevant = sorted(list(debug_pkgs_relevant)) print("Running apt install...") install_packages(debug_pkgs_relevant) if __name__ == "__main__": main()