#!/usr/bin/python3 # Update the module information used to generate related device IDs import itertools import json import os.path import subprocess import sys def iter_modules(base_dir): def onerror(e): raise e for root, dirs, files in \ os.walk(os.path.join(base_dir, 'kernel'), onerror=onerror): for name in files: if name.endswith('.ko.xz'): yield name[:-6], os.path.join(root, name) elif name.endswith('.ko'): yield name[:-3], os.path.join(root, name) def get_module_info(filename, attr_name): output = subprocess.check_output(['modinfo', '-F', attr_name, filename], text=True) if output == '': return [] return output.rstrip('\n').split('\n') class JSONEncoderWithSet(json.JSONEncoder): def default(self, o): if isinstance(o, set): return sorted(o) return super().default(o) def main(*kernel_ids): if not kernel_ids: kernel_dirs = '/lib/modules/' + os.uname().release else: kernel_dirs = [('/lib/modules/' + kernel_id if '/' not in kernel_id else kernel_id) for kernel_id in kernel_ids] modinfo = {} for name, filename in itertools.chain.from_iterable( iter_modules(kernel_dir) for kernel_dir in kernel_dirs): # We only care about modules that might request firmware firmware = set(get_module_info(filename, 'firmware')) if not firmware: continue # We only care about aliases generated from device IDs, which # start with ":" aliases = set(alias for alias in get_module_info(filename, 'alias') if ':' in alias) if name not in modinfo: modinfo[name] = { 'alias': aliases, 'firmware': firmware, } else: modinfo[name]['alias'] |= aliases modinfo[name]['firmware'] |= firmware with open('debian/modinfo.json', 'w') as f: json.dump(modinfo, f, indent=2, sort_keys=True, cls=JSONEncoderWithSet) if __name__ == '__main__': main(*sys.argv[1:])