| # -*- mode: python -*- |
| # modfinder: A simple tool to resolve required modules |
| # Copyright © 2014 Andy Lutomirski |
| # Licensed under the GPLv2, which is available in the virtme distribution |
| # as a file called LICENSE with SHA-256 hash: |
| # 8177f97513213526df2cf6184d8ff986c675afb514d4e68a404010521b880643 |
| |
| """ |
| This is a poor man's module resolver and loader. It does not support any |
| sort of hotplug. Instead it generates a topological order and loads |
| everything. The idea is to require very few modules. |
| """ |
| |
| from typing import List |
| |
| import re |
| import shutil |
| import subprocess |
| import os, os.path |
| import itertools |
| |
| _INSMOD_RE = re.compile('insmod (.*[^ ]) *$') |
| |
| def resolve_dep(modalias, root=None, kver=None, moddir=None): |
| # /usr/sbin might not be in the path, and modprobe is usually in /usr/sbin |
| modprobe = shutil.which('modprobe') or '/usr/sbin/modprobe' |
| args = [modprobe, '--show-depends'] |
| args += ['-C', '/var/empty'] |
| if root is not None: |
| args += ['-d', root] |
| if kver is not None and kver != os.uname().release: |
| # If booting the loaded kernel, skip -S. This helps certain |
| # buggy modprobe versions that don't support -S. |
| args += ['-S', kver] |
| if moddir is not None: |
| args += ['--moddir', moddir] |
| args += ['--', modalias] |
| |
| deps = [] |
| |
| try: |
| with open('/dev/null', 'r+b') as devnull: |
| script = subprocess.check_output(args, stderr=devnull.fileno()).\ |
| decode('utf-8', errors='replace') |
| for line in script.split('\n'): |
| m = _INSMOD_RE.match(line) |
| if m: |
| deps.append(m.group(1)) |
| except subprocess.CalledProcessError: |
| pass # This is most likely because the module is built in. |
| |
| return deps |
| |
| def merge_mods(lists) -> List[str]: |
| found: set = set() |
| mods = [] |
| for mod in itertools.chain(*lists): |
| if mod not in found: |
| found.add(mod) |
| mods.append(mod) |
| return mods |
| |
| def find_modules_from_install(aliases, root=None, kver=None, moddir=None): |
| return merge_mods(resolve_dep(a, root=root, kver=kver, moddir=moddir) |
| for a in aliases) |