Takashi Iwai
6d5f1a9f23
- Move documents and license texts into the proper section - Remove spurious non-firmware files - Restructure the packaging for reducing the storage footprint (bsc#1143959): the firmware files are split into several subpackages, so that user doesn't need to install unnecessary files. Each package has supplements entries that are generated from the static list (that was created from the current and old TW kernel binaries). There is a catch-all package, kernel-firmware-all, and this provides/obsoletes the former kernel-firmware package. And each firmware file is compressed in XZ format for the new kernel (5.3 or later). For the systems with older kernels, we still provide the old'n'good kernel-firmware.rpm, containing everything in the raw format, too. This kernel-firmware.rpm will be obsoleted once when kernel-firmware-all above is installed. The build of both flavors are done in the multibuild. Without the flavor, the raw kernel-firmware.rpm and ucode-amd.rpm are built, while the new kernel firmware packages are built in "compressed" flavor (-M compressed). OBS-URL: https://build.opensuse.org/request/show/723804 OBS-URL: https://build.opensuse.org/package/show/Kernel:HEAD/kernel-firmware?expand=0&rev=266
160 lines
5.9 KiB
Python
160 lines
5.9 KiB
Python
#!/usr/bin/python3
|
|
|
|
import sys, string, os, re, subprocess, tempfile, fnmatch
|
|
|
|
class FWTopics(object):
|
|
def __init__(self):
|
|
self.topics = {}
|
|
self.firmwares = {}
|
|
self.aliases = {}
|
|
self.modules = {}
|
|
self.modmap = {}
|
|
self.dirty = False
|
|
self.read_topics()
|
|
|
|
def kernel_binary_rpm(self, file):
|
|
file = os.path.basename(file)
|
|
if not fnmatch.fnmatch(file, 'kernel*.rpm'):
|
|
return False
|
|
blacklist = ( '*.noarch.rpm', '*.src.rpm', '*.nosrc.rpm',
|
|
'*-debuginfo*', '*-debugsource*',
|
|
'*-devel-*', '*-hmac-*',
|
|
'kernel-docs*', 'kernel-syms-*' )
|
|
for p in blacklist:
|
|
if fnmatch.fnmatch(file, p):
|
|
return False
|
|
return True
|
|
|
|
def modinfo(self, ko, attr):
|
|
return subprocess.check_output(['/usr/sbin/modinfo', '-F', attr, ko]).decode('utf-8').split('\n')
|
|
|
|
def canon_module(self, name):
|
|
return re.sub('-', '_', name)
|
|
|
|
def read_topics(self):
|
|
with open('topics.list', 'r') as f:
|
|
for t in f.read().split('\n'):
|
|
t.rstrip()
|
|
if t == '':
|
|
continue
|
|
if re.match('#', t):
|
|
continue
|
|
l = t.split()
|
|
first = re.sub(r':$', '', l.pop(0))
|
|
topic = l.pop(0)
|
|
self.topics[first] = topic
|
|
if l == []:
|
|
m = self.canon_module(first)
|
|
self.modules[first] = [ m ]
|
|
self.modmap[m] = topic
|
|
else:
|
|
self.modules[first] = []
|
|
for m in l:
|
|
m = self.canon_module(m)
|
|
self.modules[first].append(m)
|
|
self.modmap[m] = topic
|
|
# print(first, topic, self.modules[first])
|
|
|
|
def read_aliases(self):
|
|
with open('aliases.list', 'r') as f:
|
|
for t in f.read().split('\n'):
|
|
t.rstrip()
|
|
if t == '':
|
|
continue
|
|
l = t.split()
|
|
module = re.sub(r':$', '', l.pop(0))
|
|
if self.aliases.get(module) == None:
|
|
self.aliases[module] = []
|
|
self.aliases[module].append(l.pop(0))
|
|
|
|
def write_aliases(self):
|
|
if self.dirty:
|
|
print('updating aliases...')
|
|
with open('aliases.list', 'w') as f:
|
|
for t in sorted(self.aliases.keys()):
|
|
for m in sorted(self.aliases[t]):
|
|
f.write(t + ': ' + m + '\n')
|
|
self.dirty = False
|
|
|
|
def parse_whence(self, file):
|
|
with open(file, 'r') as f:
|
|
for t in f.read().split('\n'):
|
|
t.rstrip()
|
|
if t == '':
|
|
continue
|
|
if re.match('----', t):
|
|
first = None
|
|
elif re.match('Driver:', t):
|
|
t = re.sub(r'^Driver: *', '', t)
|
|
first = t.split()[0]
|
|
first = re.sub(r':.*$', '', first)
|
|
if self.topics.get(first) == None:
|
|
print('No matching topic entry for:', t)
|
|
first = None
|
|
elif re.match(r'File:', t):
|
|
if first == None:
|
|
continue
|
|
t = re.sub(r'^File: *', '', t)
|
|
t = re.sub('"', '', t)
|
|
self.firmwares[t] = first
|
|
elif re.match(r'Link:', t):
|
|
if first == None:
|
|
continue
|
|
t = re.sub(r'^Link: *', '', t)
|
|
t = re.sub(r' ->.*$', '', t)
|
|
t = re.sub('"', '', t)
|
|
self.firmwares[t] = first
|
|
|
|
def check_module(self):
|
|
def __check_module(ko, name):
|
|
for f in self.modinfo(ko, 'firmware'):
|
|
if f == '':
|
|
continue
|
|
first = self.firmwares.get(f)
|
|
if first != None:
|
|
if self.topics[first] == 'SKIP':
|
|
continue
|
|
if not name in self.modules[first]:
|
|
print('Module', name, 'is missing for', first)
|
|
print(' firmware:', f)
|
|
return __check_module
|
|
|
|
def update_alias(self):
|
|
def __update_alias(ko, name):
|
|
if self.modmap.get(name) != None and self.modmap[name] != 'SKIP':
|
|
for f in self.modinfo(ko, 'alias'):
|
|
if f == '':
|
|
continue
|
|
if self.aliases.get(name) == None:
|
|
self.aliases[name] = []
|
|
if not f in self.aliases[name]:
|
|
self.aliases[name].append(f)
|
|
self.dirty = True
|
|
print('adding alias', name, f)
|
|
return __update_alias
|
|
|
|
def scan_firmware_dir(self, dir, proc):
|
|
for root, dirs, files in os.walk(dir):
|
|
for p in files:
|
|
ko = os.path.join(root, p)
|
|
name = re.sub(r'\.xz$', '', p)
|
|
if not fnmatch.fnmatch(name, '*.ko'):
|
|
continue
|
|
name = re.sub(r'\.ko$', '', name)
|
|
name = self.canon_module(name)
|
|
proc(ko, name)
|
|
|
|
def scan_firmware_rpm(self, rpm, proc):
|
|
if not self.kernel_binary_rpm(rpm):
|
|
return
|
|
with tempfile.TemporaryDirectory() as dir:
|
|
subprocess.call('rpm2cpio ' + rpm + ' | cpio -i --make-directories -D ' + dir,
|
|
shell=True)
|
|
self.scan_firmware_dir(dir, proc)
|
|
|
|
def scan_firmware(self, arg, proc):
|
|
if os.path.isdir(arg):
|
|
self.scan_firmware_dir(arg, proc)
|
|
else:
|
|
self.scan_firmware_rpm(arg, proc)
|