blob: 1b4c864a630ec6dfdfadc4045bd8dd8bc08acb1d [file] [log] [blame]
Patrick Williams92b42cb2022-09-03 06:53:57 -05001#
2# Copyright OpenEmbedded Contributors
3#
4# SPDX-License-Identifier: MIT
5#
6
7pkg_postinst:modules () {
8if [ -z "$D" ]; then
9 depmod -a ${KERNEL_VERSION}
10else
11 # image.bbclass will call depmodwrapper after everything is installed,
12 # no need to do it here as well
13 :
14fi
15}
16
17pkg_postrm:modules () {
18if [ -z "$D" ]; then
19 depmod -a ${KERNEL_VERSION}
20else
21 depmodwrapper -a -b $D ${KERNEL_VERSION}
22fi
23}
24
25autoload_postinst_fragment() {
26if [ x"$D" = "x" ]; then
27 modprobe %s || true
28fi
29}
30
31PACKAGE_WRITE_DEPS += "kmod-native depmodwrapper-cross"
32
33do_install:append() {
34 install -d ${D}${sysconfdir}/modules-load.d/ ${D}${sysconfdir}/modprobe.d/
35}
36
37KERNEL_SPLIT_MODULES ?= "1"
38PACKAGESPLITFUNCS:prepend = "split_kernel_module_packages "
39
40KERNEL_MODULES_META_PACKAGE ?= "${@ d.getVar("KERNEL_PACKAGE_NAME") or "kernel" }-modules"
41
42KERNEL_MODULE_PACKAGE_PREFIX ?= ""
43KERNEL_MODULE_PACKAGE_SUFFIX ?= "-${KERNEL_VERSION}"
44KERNEL_MODULE_PROVIDE_VIRTUAL ?= "1"
45
46python split_kernel_module_packages () {
47 import re
48
49 modinfoexp = re.compile("([^=]+)=(.*)")
50
51 def extract_modinfo(file):
52 import tempfile, subprocess
53 tempfile.tempdir = d.getVar("WORKDIR")
54 compressed = re.match( r'.*\.(gz|xz|zst)$', file)
55 tf = tempfile.mkstemp()
56 tmpfile = tf[1]
57 if compressed:
58 tmpkofile = tmpfile + ".ko"
59 if compressed.group(1) == 'gz':
60 cmd = "gunzip -dc %s > %s" % (file, tmpkofile)
61 subprocess.check_call(cmd, shell=True)
62 elif compressed.group(1) == 'xz':
63 cmd = "xz -dc %s > %s" % (file, tmpkofile)
64 subprocess.check_call(cmd, shell=True)
65 elif compressed.group(1) == 'zst':
66 cmd = "zstd -dc %s > %s" % (file, tmpkofile)
67 subprocess.check_call(cmd, shell=True)
68 else:
69 msg = "Cannot decompress '%s'" % file
70 raise msg
71 cmd = "%sobjcopy -j .modinfo -O binary %s %s" % (d.getVar("HOST_PREFIX") or "", tmpkofile, tmpfile)
72 else:
73 cmd = "%sobjcopy -j .modinfo -O binary %s %s" % (d.getVar("HOST_PREFIX") or "", file, tmpfile)
74 subprocess.check_call(cmd, shell=True)
75 # errors='replace': Some old kernel versions contain invalid utf-8 characters in mod descriptions (like 0xf6, 'รถ')
76 f = open(tmpfile, errors='replace')
77 l = f.read().split("\000")
78 f.close()
79 os.close(tf[0])
80 os.unlink(tmpfile)
81 if compressed:
82 os.unlink(tmpkofile)
83 vals = {}
84 for i in l:
85 m = modinfoexp.match(i)
86 if not m:
87 continue
88 vals[m.group(1)] = m.group(2)
89 return vals
90
91 def frob_metadata(file, pkg, pattern, format, basename):
92 vals = extract_modinfo(file)
93
94 dvar = d.getVar('PKGD')
95
96 # If autoloading is requested, output /etc/modules-load.d/<name>.conf and append
97 # appropriate modprobe commands to the postinst
98 autoloadlist = (d.getVar("KERNEL_MODULE_AUTOLOAD") or "").split()
99 autoload = d.getVar('module_autoload_%s' % basename)
100 if autoload and autoload == basename:
101 bb.warn("module_autoload_%s was replaced by KERNEL_MODULE_AUTOLOAD for cases where basename == module name, please drop it" % basename)
102 if autoload and basename not in autoloadlist:
103 bb.warn("module_autoload_%s is defined but '%s' isn't included in KERNEL_MODULE_AUTOLOAD, please add it there" % (basename, basename))
104 if basename in autoloadlist:
105 name = '%s/etc/modules-load.d/%s.conf' % (dvar, basename)
106 f = open(name, 'w')
107 if autoload:
108 for m in autoload.split():
109 f.write('%s\n' % m)
110 else:
111 f.write('%s\n' % basename)
112 f.close()
113 postinst = d.getVar('pkg_postinst:%s' % pkg)
114 if not postinst:
115 bb.fatal("pkg_postinst:%s not defined" % pkg)
116 postinst += d.getVar('autoload_postinst_fragment') % (autoload or basename)
117 d.setVar('pkg_postinst:%s' % pkg, postinst)
118
119 # Write out any modconf fragment
120 modconflist = (d.getVar("KERNEL_MODULE_PROBECONF") or "").split()
121 modconf = d.getVar('module_conf_%s' % basename)
122 if modconf and basename in modconflist:
123 name = '%s/etc/modprobe.d/%s.conf' % (dvar, basename)
124 f = open(name, 'w')
125 f.write("%s\n" % modconf)
126 f.close()
127 elif modconf:
128 bb.error("Please ensure module %s is listed in KERNEL_MODULE_PROBECONF since module_conf_%s is set" % (basename, basename))
129
130 files = d.getVar('FILES:%s' % pkg)
131 files = "%s /etc/modules-load.d/%s.conf /etc/modprobe.d/%s.conf" % (files, basename, basename)
132 d.setVar('FILES:%s' % pkg, files)
133
134 conffiles = d.getVar('CONFFILES:%s' % pkg)
135 conffiles = "%s /etc/modules-load.d/%s.conf /etc/modprobe.d/%s.conf" % (conffiles, basename, basename)
136 d.setVar('CONFFILES:%s' % pkg, conffiles)
137
138 if "description" in vals:
139 old_desc = d.getVar('DESCRIPTION:' + pkg) or ""
140 d.setVar('DESCRIPTION:' + pkg, old_desc + "; " + vals["description"])
141
142 rdepends = bb.utils.explode_dep_versions2(d.getVar('RDEPENDS:' + pkg) or "")
143 modinfo_deps = []
144 if "depends" in vals and vals["depends"] != "":
145 for dep in vals["depends"].split(","):
146 on = legitimize_package_name(dep)
147 dependency_pkg = format % on
148 modinfo_deps.append(dependency_pkg)
149 for dep in modinfo_deps:
150 if not dep in rdepends:
151 rdepends[dep] = []
152 d.setVar('RDEPENDS:' + pkg, bb.utils.join_deps(rdepends, commasep=False))
153
154 # Avoid automatic -dev recommendations for modules ending with -dev.
155 d.setVarFlag('RRECOMMENDS:' + pkg, 'nodeprrecs', 1)
156
157 # Provide virtual package without postfix
158 providevirt = d.getVar('KERNEL_MODULE_PROVIDE_VIRTUAL')
159 if providevirt == "1":
160 postfix = format.split('%s')[1]
161 d.setVar('RPROVIDES:' + pkg, pkg.replace(postfix, ''))
162
163 kernel_package_name = d.getVar("KERNEL_PACKAGE_NAME") or "kernel"
164 kernel_version = d.getVar("KERNEL_VERSION")
165
166 metapkg = d.getVar('KERNEL_MODULES_META_PACKAGE')
167 splitmods = d.getVar('KERNEL_SPLIT_MODULES')
168 postinst = d.getVar('pkg_postinst:modules')
169 postrm = d.getVar('pkg_postrm:modules')
170
171 if splitmods != '1':
172 etcdir = d.getVar('sysconfdir')
173 d.appendVar('FILES:' + metapkg, '%s/modules-load.d/ %s/modprobe.d/ %s/modules/' % (etcdir, etcdir, d.getVar("nonarch_base_libdir")))
174 d.appendVar('pkg_postinst:%s' % metapkg, postinst)
175 d.prependVar('pkg_postrm:%s' % metapkg, postrm);
176 return
177
178 module_regex = r'^(.*)\.k?o(?:\.(gz|xz|zst))?$'
179
180 module_pattern_prefix = d.getVar('KERNEL_MODULE_PACKAGE_PREFIX')
181 module_pattern_suffix = d.getVar('KERNEL_MODULE_PACKAGE_SUFFIX')
182 module_pattern = module_pattern_prefix + kernel_package_name + '-module-%s' + module_pattern_suffix
183
184 modules = do_split_packages(d, root='${nonarch_base_libdir}/modules', file_regex=module_regex, output_pattern=module_pattern, description='%s kernel module', postinst=postinst, postrm=postrm, recursive=True, hook=frob_metadata, extra_depends='%s-%s' % (kernel_package_name, kernel_version))
185 if modules:
186 d.appendVar('RDEPENDS:' + metapkg, ' '+' '.join(modules))
187
188 # If modules-load.d and modprobe.d are empty at this point, remove them to
189 # avoid warnings. removedirs only raises an OSError if an empty
190 # directory cannot be removed.
191 dvar = d.getVar('PKGD')
192 for dir in ["%s/etc/modprobe.d" % (dvar), "%s/etc/modules-load.d" % (dvar), "%s/etc" % (dvar)]:
193 if len(os.listdir(dir)) == 0:
194 os.rmdir(dir)
195}
196
197do_package[vardeps] += '${@" ".join(map(lambda s: "module_conf_" + s, (d.getVar("KERNEL_MODULE_PROBECONF") or "").split()))}'