blob: 891d3a8421840b1cbbd958168c6fce44a74d6376 [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001# BB Class inspired by ebuild.sh
2#
3# This class will test files after installation for certain
4# security issues and other kind of issues.
5#
6# Checks we do:
7# -Check the ownership and permissions
8# -Check the RUNTIME path for the $TMPDIR
9# -Check if .la files wrongly point to workdir
10# -Check if .pc files wrongly point to workdir
11# -Check if packages contains .debug directories or .so files
12# where they should be in -dev or -dbg
13# -Check if config.log contains traces to broken autoconf tests
14# -Check invalid characters (non-utf8) on some package metadata
15# -Ensure that binaries in base_[bindir|sbindir|libdir] do not link
16# into exec_prefix
17# -Check that scripts in base_[bindir|sbindir|libdir] do not reference
18# files under exec_prefix
Brad Bishopd7bf8c12018-02-25 22:55:05 -050019# -Check if the package name is upper case
Patrick Williamsc124f4f2015-09-15 14:41:29 -050020
Patrick Williamsc124f4f2015-09-15 14:41:29 -050021QA_SANE = "True"
22
23# Elect whether a given type of error is a warning or error, they may
24# have been set by other files.
25WARN_QA ?= "ldflags useless-rpaths rpaths staticdev libdir xorg-driver-abi \
26 textrel already-stripped incompatible-license files-invalid \
27 installed-vs-shipped compile-host-path install-host-path \
Brad Bishop15ae2502019-06-18 21:44:24 -040028 pn-overrides infodir build-deps src-uri-bad \
Patrick Williamsc124f4f2015-09-15 14:41:29 -050029 unknown-configure-option symlink-to-sysroot multilib \
Brad Bishopd89cb5f2019-04-10 09:02:41 -040030 invalid-packageconfig host-user-contaminated uppercase-pn patch-fuzz \
Patrick Williamsc124f4f2015-09-15 14:41:29 -050031 "
32ERROR_QA ?= "dev-so debug-deps dev-deps debug-files arch pkgconfig la \
33 perms dep-cmp pkgvarcheck perm-config perm-line perm-link \
34 split-strip packages-list pkgv-undefined var-undefined \
35 version-going-backwards expanded-d invalid-chars \
Brad Bishop19323692019-04-05 15:28:33 -040036 license-checksum dev-elf file-rdeps configure-unsafe \
37 configure-gettext \
Patrick Williamsc124f4f2015-09-15 14:41:29 -050038 "
Brad Bishopd7bf8c12018-02-25 22:55:05 -050039# Add usrmerge QA check based on distro feature
40ERROR_QA_append = "${@bb.utils.contains('DISTRO_FEATURES', 'usrmerge', ' usrmerge', '', d)}"
41
Patrick Williamsc124f4f2015-09-15 14:41:29 -050042FAKEROOT_QA = "host-user-contaminated"
43FAKEROOT_QA[doc] = "QA tests which need to run under fakeroot. If any \
44enabled tests are listed here, the do_package_qa task will run under fakeroot."
45
46ALL_QA = "${WARN_QA} ${ERROR_QA}"
47
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050048UNKNOWN_CONFIGURE_WHITELIST ?= "--enable-nls --disable-nls --disable-silent-rules --disable-dependency-tracking --with-libtool-sysroot --disable-static"
Patrick Williamsc124f4f2015-09-15 14:41:29 -050049
Patrick Williamsc0f7c042017-02-23 20:41:17 -060050def package_qa_clean_path(path, d, pkg=None):
51 """
52 Remove redundant paths from the path for display. If pkg isn't set then
53 TMPDIR is stripped, otherwise PKGDEST/pkg is stripped.
54 """
55 if pkg:
Brad Bishop6e60e8b2018-02-01 10:27:11 -050056 path = path.replace(os.path.join(d.getVar("PKGDEST"), pkg), "/")
57 return path.replace(d.getVar("TMPDIR"), "/").replace("//", "/")
Patrick Williamsc124f4f2015-09-15 14:41:29 -050058
59def package_qa_write_error(type, error, d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -050060 logfile = d.getVar('QA_LOGFILE')
Patrick Williamsc124f4f2015-09-15 14:41:29 -050061 if logfile:
Brad Bishop6e60e8b2018-02-01 10:27:11 -050062 p = d.getVar('P')
Patrick Williamsc0f7c042017-02-23 20:41:17 -060063 with open(logfile, "a+") as f:
64 f.write("%s: %s [%s]\n" % (p, error, type))
Patrick Williamsc124f4f2015-09-15 14:41:29 -050065
66def package_qa_handle_error(error_class, error_msg, d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -050067 if error_class in (d.getVar("ERROR_QA") or "").split():
Brad Bishopd7bf8c12018-02-25 22:55:05 -050068 package_qa_write_error(error_class, error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050069 bb.error("QA Issue: %s [%s]" % (error_msg, error_class))
70 d.setVar("QA_SANE", False)
71 return False
Brad Bishop6e60e8b2018-02-01 10:27:11 -050072 elif error_class in (d.getVar("WARN_QA") or "").split():
Brad Bishopd7bf8c12018-02-25 22:55:05 -050073 package_qa_write_error(error_class, error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050074 bb.warn("QA Issue: %s [%s]" % (error_msg, error_class))
75 else:
76 bb.note("QA Issue: %s [%s]" % (error_msg, error_class))
77 return True
78
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050079def package_qa_add_message(messages, section, new_msg):
80 if section not in messages:
81 messages[section] = new_msg
82 else:
83 messages[section] = messages[section] + "\n" + new_msg
84
Patrick Williamsc124f4f2015-09-15 14:41:29 -050085QAPATHTEST[libexec] = "package_qa_check_libexec"
86def package_qa_check_libexec(path,name, d, elf, messages):
87
88 # Skip the case where the default is explicitly /usr/libexec
Brad Bishop6e60e8b2018-02-01 10:27:11 -050089 libexec = d.getVar('libexecdir')
Patrick Williamsc124f4f2015-09-15 14:41:29 -050090 if libexec == "/usr/libexec":
91 return True
92
93 if 'libexec' in path.split(os.path.sep):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050094 package_qa_add_message(messages, "libexec", "%s: %s is using libexec please relocate to %s" % (name, package_qa_clean_path(path, d), libexec))
Patrick Williamsc124f4f2015-09-15 14:41:29 -050095 return False
96
97 return True
98
99QAPATHTEST[rpaths] = "package_qa_check_rpath"
100def package_qa_check_rpath(file,name, d, elf, messages):
101 """
102 Check for dangerous RPATHs
103 """
104 if not elf:
105 return
106
107 if os.path.islink(file):
108 return
109
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500110 bad_dirs = [d.getVar('BASE_WORKDIR'), d.getVar('STAGING_DIR_TARGET')]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500111
112 phdrs = elf.run_objdump("-p", d)
113
114 import re
Brad Bishop977dc1a2019-02-06 16:01:43 -0500115 rpath_re = re.compile(r"\s+RPATH\s+(.*)")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500116 for line in phdrs.split("\n"):
117 m = rpath_re.match(line)
118 if m:
119 rpath = m.group(1)
120 for dir in bad_dirs:
121 if dir in rpath:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500122 package_qa_add_message(messages, "rpaths", "package %s contains bad RPATH %s in file %s" % (name, rpath, file))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500123
124QAPATHTEST[useless-rpaths] = "package_qa_check_useless_rpaths"
125def package_qa_check_useless_rpaths(file, name, d, elf, messages):
126 """
127 Check for RPATHs that are useless but not dangerous
128 """
129 def rpath_eq(a, b):
130 return os.path.normpath(a) == os.path.normpath(b)
131
132 if not elf:
133 return
134
135 if os.path.islink(file):
136 return
137
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500138 libdir = d.getVar("libdir")
139 base_libdir = d.getVar("base_libdir")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500140
141 phdrs = elf.run_objdump("-p", d)
142
143 import re
Brad Bishop977dc1a2019-02-06 16:01:43 -0500144 rpath_re = re.compile(r"\s+RPATH\s+(.*)")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500145 for line in phdrs.split("\n"):
146 m = rpath_re.match(line)
147 if m:
148 rpath = m.group(1)
149 if rpath_eq(rpath, libdir) or rpath_eq(rpath, base_libdir):
150 # The dynamic linker searches both these places anyway. There is no point in
151 # looking there again.
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500152 package_qa_add_message(messages, "useless-rpaths", "%s: %s contains probably-redundant RPATH %s" % (name, package_qa_clean_path(file, d), rpath))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500153
154QAPATHTEST[dev-so] = "package_qa_check_dev"
155def package_qa_check_dev(path, name, d, elf, messages):
156 """
157 Check for ".so" library symlinks in non-dev packages
158 """
159
160 if not name.endswith("-dev") and not name.endswith("-dbg") and not name.endswith("-ptest") and not name.startswith("nativesdk-") and path.endswith(".so") and os.path.islink(path):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500161 package_qa_add_message(messages, "dev-so", "non -dev/-dbg/nativesdk- package contains symlink .so: %s path '%s'" % \
162 (name, package_qa_clean_path(path,d)))
163
164QAPATHTEST[dev-elf] = "package_qa_check_dev_elf"
165def package_qa_check_dev_elf(path, name, d, elf, messages):
166 """
167 Check that -dev doesn't contain real shared libraries. The test has to
168 check that the file is not a link and is an ELF object as some recipes
169 install link-time .so files that are linker scripts.
170 """
171 if name.endswith("-dev") and path.endswith(".so") and not os.path.islink(path) and elf:
172 package_qa_add_message(messages, "dev-elf", "-dev package contains non-symlink .so: %s path '%s'" % \
173 (name, package_qa_clean_path(path,d)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500174
175QAPATHTEST[staticdev] = "package_qa_check_staticdev"
176def package_qa_check_staticdev(path, name, d, elf, messages):
177 """
178 Check for ".a" library in non-staticdev packages
179 There are a number of exceptions to this rule, -pic packages can contain
180 static libraries, the _nonshared.a belong with their -dev packages and
181 libgcc.a, libgcov.a will be skipped in their packages
182 """
183
184 if not name.endswith("-pic") and not name.endswith("-staticdev") and not name.endswith("-ptest") and path.endswith(".a") and not path.endswith("_nonshared.a"):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500185 package_qa_add_message(messages, "staticdev", "non -staticdev package contains static .a library: %s path '%s'" % \
186 (name, package_qa_clean_path(path,d)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500187
188def package_qa_check_libdir(d):
189 """
190 Check for wrong library installation paths. For instance, catch
191 recipes installing /lib/bar.so when ${base_libdir}="lib32" or
192 installing in /usr/lib64 when ${libdir}="/usr/lib"
193 """
194 import re
195
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500196 pkgdest = d.getVar('PKGDEST')
197 base_libdir = d.getVar("base_libdir") + os.sep
198 libdir = d.getVar("libdir") + os.sep
199 libexecdir = d.getVar("libexecdir") + os.sep
200 exec_prefix = d.getVar("exec_prefix") + os.sep
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500201
202 messages = []
203
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500204 # The re's are purposely fuzzy, as some there are some .so.x.y.z files
205 # that don't follow the standard naming convention. It checks later
206 # that they are actual ELF files
Brad Bishop977dc1a2019-02-06 16:01:43 -0500207 lib_re = re.compile(r"^/lib.+\.so(\..+)?$")
208 exec_re = re.compile(r"^%s.*/lib.+\.so(\..+)?$" % exec_prefix)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500209
210 for root, dirs, files in os.walk(pkgdest):
211 if root == pkgdest:
212 # Skip subdirectories for any packages with libdir in INSANE_SKIP
213 skippackages = []
214 for package in dirs:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500215 if 'libdir' in (d.getVar('INSANE_SKIP_' + package) or "").split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500216 bb.note("Package %s skipping libdir QA test" % (package))
217 skippackages.append(package)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500218 elif d.getVar('PACKAGE_DEBUG_SPLIT_STYLE') == 'debug-file-directory' and package.endswith("-dbg"):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500219 bb.note("Package %s skipping libdir QA test for PACKAGE_DEBUG_SPLIT_STYLE equals debug-file-directory" % (package))
220 skippackages.append(package)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500221 for package in skippackages:
222 dirs.remove(package)
223 for file in files:
224 full_path = os.path.join(root, file)
225 rel_path = os.path.relpath(full_path, pkgdest)
226 if os.sep in rel_path:
227 package, rel_path = rel_path.split(os.sep, 1)
228 rel_path = os.sep + rel_path
229 if lib_re.match(rel_path):
230 if base_libdir not in rel_path:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500231 # make sure it's an actual ELF file
232 elf = oe.qa.ELFFile(full_path)
233 try:
234 elf.open()
235 messages.append("%s: found library in wrong location: %s" % (package, rel_path))
236 except (oe.qa.NotELFFileError):
237 pass
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500238 if exec_re.match(rel_path):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500239 if libdir not in rel_path and libexecdir not in rel_path:
240 # make sure it's an actual ELF file
241 elf = oe.qa.ELFFile(full_path)
242 try:
243 elf.open()
244 messages.append("%s: found library in wrong location: %s" % (package, rel_path))
245 except (oe.qa.NotELFFileError):
246 pass
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500247
248 if messages:
249 package_qa_handle_error("libdir", "\n".join(messages), d)
250
251QAPATHTEST[debug-files] = "package_qa_check_dbg"
252def package_qa_check_dbg(path, name, d, elf, messages):
253 """
254 Check for ".debug" files or directories outside of the dbg package
255 """
256
257 if not "-dbg" in name and not "-ptest" in name:
258 if '.debug' in path.split(os.path.sep):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500259 package_qa_add_message(messages, "debug-files", "non debug package contains .debug directory: %s path %s" % \
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500260 (name, package_qa_clean_path(path,d)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500261
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500262QAPATHTEST[arch] = "package_qa_check_arch"
263def package_qa_check_arch(path,name,d, elf, messages):
264 """
265 Check if archs are compatible
266 """
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800267 import re, oe.elf
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600268
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500269 if not elf:
270 return
271
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500272 target_os = d.getVar('TARGET_OS')
273 target_arch = d.getVar('TARGET_ARCH')
274 provides = d.getVar('PROVIDES')
275 bpn = d.getVar('BPN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500276
277 if target_arch == "allarch":
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500278 pn = d.getVar('PN')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500279 package_qa_add_message(messages, "arch", pn + ": Recipe inherits the allarch class, but has packaged architecture-specific binaries")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500280 return
281
282 # FIXME: Cross package confuse this check, so just skip them
283 for s in ['cross', 'nativesdk', 'cross-canadian']:
284 if bb.data.inherits_class(s, d):
285 return
286
287 # avoid following links to /usr/bin (e.g. on udev builds)
288 # we will check the files pointed to anyway...
289 if os.path.islink(path):
290 return
291
292 #if this will throw an exception, then fix the dict above
293 (machine, osabi, abiversion, littleendian, bits) \
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800294 = oe.elf.machine_dict(d)[target_os][target_arch]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500295
296 # Check the architecture and endiannes of the binary
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600297 is_32 = (("virtual/kernel" in provides) or bb.data.inherits_class("module", d)) and \
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800298 (target_os == "linux-gnux32" or target_os == "linux-muslx32" or \
Brad Bishop977dc1a2019-02-06 16:01:43 -0500299 target_os == "linux-gnu_ilp32" or re.match(r'mips64.*32', d.getVar('DEFAULTTUNE')))
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800300 is_bpf = (oe.qa.elf_machine_to_string(elf.machine()) == "BPF")
301 if not ((machine == elf.machine()) or is_32 or is_bpf):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600302 package_qa_add_message(messages, "arch", "Architecture did not match (%s, expected %s) on %s" % \
303 (oe.qa.elf_machine_to_string(elf.machine()), oe.qa.elf_machine_to_string(machine), package_qa_clean_path(path,d)))
Brad Bishop19323692019-04-05 15:28:33 -0400304 elif not ((bits == elf.abiSize()) or is_32 or is_bpf):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500305 package_qa_add_message(messages, "arch", "Bit size did not match (%d to %d) %s on %s" % \
306 (bits, elf.abiSize(), bpn, package_qa_clean_path(path,d)))
Brad Bishop19323692019-04-05 15:28:33 -0400307 elif not ((littleendian == elf.isLittleEndian()) or is_bpf):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500308 package_qa_add_message(messages, "arch", "Endiannes did not match (%d to %d) on %s" % \
309 (littleendian, elf.isLittleEndian(), package_qa_clean_path(path,d)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500310
311QAPATHTEST[desktop] = "package_qa_check_desktop"
312def package_qa_check_desktop(path, name, d, elf, messages):
313 """
314 Run all desktop files through desktop-file-validate.
315 """
316 if path.endswith(".desktop"):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500317 desktop_file_validate = os.path.join(d.getVar('STAGING_BINDIR_NATIVE'),'desktop-file-validate')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500318 output = os.popen("%s %s" % (desktop_file_validate, path))
319 # This only produces output on errors
320 for l in output:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500321 package_qa_add_message(messages, "desktop", "Desktop file issue: " + l.strip())
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500322
323QAPATHTEST[textrel] = "package_qa_textrel"
324def package_qa_textrel(path, name, d, elf, messages):
325 """
326 Check if the binary contains relocations in .text
327 """
328
329 if not elf:
330 return
331
332 if os.path.islink(path):
333 return
334
335 phdrs = elf.run_objdump("-p", d)
336 sane = True
337
338 import re
Brad Bishop977dc1a2019-02-06 16:01:43 -0500339 textrel_re = re.compile(r"\s+TEXTREL\s+")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500340 for line in phdrs.split("\n"):
341 if textrel_re.match(line):
342 sane = False
343
344 if not sane:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500345 package_qa_add_message(messages, "textrel", "ELF binary '%s' has relocations in .text" % path)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500346
347QAPATHTEST[ldflags] = "package_qa_hash_style"
348def package_qa_hash_style(path, name, d, elf, messages):
349 """
350 Check if the binary has the right hash style...
351 """
352
353 if not elf:
354 return
355
356 if os.path.islink(path):
357 return
358
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500359 gnu_hash = "--hash-style=gnu" in d.getVar('LDFLAGS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500360 if not gnu_hash:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500361 gnu_hash = "--hash-style=both" in d.getVar('LDFLAGS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500362 if not gnu_hash:
363 return
364
365 sane = False
366 has_syms = False
367
368 phdrs = elf.run_objdump("-p", d)
369
370 # If this binary has symbols, we expect it to have GNU_HASH too.
371 for line in phdrs.split("\n"):
372 if "SYMTAB" in line:
373 has_syms = True
374 if "GNU_HASH" in line:
375 sane = True
376 if "[mips32]" in line or "[mips64]" in line:
377 sane = True
378
379 if has_syms and not sane:
Brad Bishopa5c52ff2018-11-23 10:55:50 +1300380 package_qa_add_message(messages, "ldflags", "No GNU_HASH in the ELF binary %s, didn't pass LDFLAGS?" % path)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500381
382
383QAPATHTEST[buildpaths] = "package_qa_check_buildpaths"
384def package_qa_check_buildpaths(path, name, d, elf, messages):
385 """
386 Check for build paths inside target files and error if not found in the whitelist
387 """
388 # Ignore .debug files, not interesting
389 if path.find(".debug") != -1:
390 return
391
392 # Ignore symlinks
393 if os.path.islink(path):
394 return
395
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500396 # Ignore ipk and deb's CONTROL dir
397 if path.find(name + "/CONTROL/") != -1 or path.find(name + "/DEBIAN/") != -1:
398 return
399
Brad Bishopd5ae7d92018-06-14 09:52:03 -0700400 tmpdir = bytes(d.getVar('TMPDIR'), encoding="utf-8")
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500401 with open(path, 'rb') as f:
Brad Bishopd5ae7d92018-06-14 09:52:03 -0700402 file_content = f.read()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500403 if tmpdir in file_content:
Brad Bishopf3fd2882019-06-21 08:06:37 -0400404 trimmed = path.replace(os.path.join (d.getVar("PKGDEST"), name), "")
405 package_qa_add_message(messages, "buildpaths", "File %s in package %s contains reference to TMPDIR" % (trimmed, name))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500406
407
408QAPATHTEST[xorg-driver-abi] = "package_qa_check_xorg_driver_abi"
409def package_qa_check_xorg_driver_abi(path, name, d, elf, messages):
410 """
411 Check that all packages containing Xorg drivers have ABI dependencies
412 """
413
414 # Skip dev, dbg or nativesdk packages
415 if name.endswith("-dev") or name.endswith("-dbg") or name.startswith("nativesdk-"):
416 return
417
418 driverdir = d.expand("${libdir}/xorg/modules/drivers/")
419 if driverdir in path and path.endswith(".so"):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500420 mlprefix = d.getVar('MLPREFIX') or ''
421 for rdep in bb.utils.explode_deps(d.getVar('RDEPENDS_' + name) or ""):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500422 if rdep.startswith("%sxorg-abi-" % mlprefix):
423 return
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500424 package_qa_add_message(messages, "xorg-driver-abi", "Package %s contains Xorg driver (%s) but no xorg-abi- dependencies" % (name, os.path.basename(path)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500425
426QAPATHTEST[infodir] = "package_qa_check_infodir"
427def package_qa_check_infodir(path, name, d, elf, messages):
428 """
429 Check that /usr/share/info/dir isn't shipped in a particular package
430 """
431 infodir = d.expand("${infodir}/dir")
432
433 if infodir in path:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500434 package_qa_add_message(messages, "infodir", "The /usr/share/info/dir file is not meant to be shipped in a particular package.")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500435
436QAPATHTEST[symlink-to-sysroot] = "package_qa_check_symlink_to_sysroot"
437def package_qa_check_symlink_to_sysroot(path, name, d, elf, messages):
438 """
439 Check that the package doesn't contain any absolute symlinks to the sysroot.
440 """
441 if os.path.islink(path):
442 target = os.readlink(path)
443 if os.path.isabs(target):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500444 tmpdir = d.getVar('TMPDIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500445 if target.startswith(tmpdir):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500446 trimmed = path.replace(os.path.join (d.getVar("PKGDEST"), name), "")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500447 package_qa_add_message(messages, "symlink-to-sysroot", "Symlink %s in %s points to TMPDIR" % (trimmed, name))
448
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600449# Check license variables
450do_populate_lic[postfuncs] += "populate_lic_qa_checksum"
451python populate_lic_qa_checksum() {
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500452 """
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600453 Check for changes in the license files.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500454 """
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500455 sane = True
456
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500457 lic_files = d.getVar('LIC_FILES_CHKSUM') or ''
458 lic = d.getVar('LICENSE')
459 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500460
461 if lic == "CLOSED":
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500462 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500463
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500464 if not lic_files and d.getVar('SRC_URI'):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800465 sane &= package_qa_handle_error("license-checksum", pn + ": Recipe file fetches files and does not have license file information (LIC_FILES_CHKSUM)", d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500466
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500467 srcdir = d.getVar('S')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500468 corebase_licensefile = d.getVar('COREBASE') + "/LICENSE"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500469 for url in lic_files.split():
470 try:
471 (type, host, path, user, pswd, parm) = bb.fetch.decodeurl(url)
472 except bb.fetch.MalformedUrl:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800473 sane &= package_qa_handle_error("license-checksum", pn + ": LIC_FILES_CHKSUM contains an invalid URL: " + url, d)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500474 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500475 srclicfile = os.path.join(srcdir, path)
476 if not os.path.isfile(srclicfile):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800477 sane &= package_qa_handle_error("license-checksum", pn + ": LIC_FILES_CHKSUM points to an invalid file: " + srclicfile, d)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500478 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500479
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500480 if (srclicfile == corebase_licensefile):
481 bb.warn("${COREBASE}/LICENSE is not a valid license file, please use '${COMMON_LICENSE_DIR}/MIT' for a MIT License file in LIC_FILES_CHKSUM. This will become an error in the future")
482
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500483 recipemd5 = parm.get('md5', '')
484 beginline, endline = 0, 0
485 if 'beginline' in parm:
486 beginline = int(parm['beginline'])
487 if 'endline' in parm:
488 endline = int(parm['endline'])
489
490 if (not beginline) and (not endline):
491 md5chksum = bb.utils.md5_file(srclicfile)
Brad Bishop19323692019-04-05 15:28:33 -0400492 with open(srclicfile, 'r', errors='replace') as f:
493 license = f.read().splitlines()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500494 else:
Brad Bishop19323692019-04-05 15:28:33 -0400495 with open(srclicfile, 'rb') as f:
496 import hashlib
497 lineno = 0
498 license = []
499 m = hashlib.md5()
500 for line in f:
501 lineno += 1
502 if (lineno >= beginline):
503 if ((lineno <= endline) or not endline):
504 m.update(line)
505 license.append(line.decode('utf-8', errors='replace').rstrip())
506 else:
507 break
508 md5chksum = m.hexdigest()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500509 if recipemd5 == md5chksum:
510 bb.note (pn + ": md5 checksum matched for ", url)
511 else:
512 if recipemd5:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500513 msg = pn + ": The LIC_FILES_CHKSUM does not match for " + url
514 msg = msg + "\n" + pn + ": The new md5 checksum is " + md5chksum
Brad Bishop19323692019-04-05 15:28:33 -0400515 max_lines = int(d.getVar('QA_MAX_LICENSE_LINES') or 20)
516 if not license or license[-1] != '':
517 # Ensure that our license text ends with a line break
518 # (will be added with join() below).
519 license.append('')
520 remove = len(license) - max_lines
521 if remove > 0:
522 start = max_lines // 2
523 end = start + remove - 1
524 del license[start:end]
525 license.insert(start, '...')
526 msg = msg + "\n" + pn + ": Here is the selected license text:" + \
527 "\n" + \
528 "{:v^70}".format(" beginline=%d " % beginline if beginline else "") + \
529 "\n" + "\n".join(license) + \
530 "{:^^70}".format(" endline=%d " % endline if endline else "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500531 if beginline:
532 if endline:
533 srcfiledesc = "%s (lines %d through to %d)" % (srclicfile, beginline, endline)
534 else:
535 srcfiledesc = "%s (beginning on line %d)" % (srclicfile, beginline)
536 elif endline:
537 srcfiledesc = "%s (ending on line %d)" % (srclicfile, endline)
538 else:
539 srcfiledesc = srclicfile
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500540 msg = msg + "\n" + pn + ": Check if the license information has changed in %s to verify that the LICENSE value \"%s\" remains valid" % (srcfiledesc, lic)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500541
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500542 else:
543 msg = pn + ": LIC_FILES_CHKSUM is not specified for " + url
544 msg = msg + "\n" + pn + ": The md5 checksum is " + md5chksum
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800545 sane &= package_qa_handle_error("license-checksum", msg, d)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600546
547 if not sane:
548 bb.fatal("Fatal QA errors found, failing task.")
549}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500550
Brad Bishop19323692019-04-05 15:28:33 -0400551def qa_check_staged(path,d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500552 """
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500553 Check staged la and pc files for common problems like references to the work
554 directory.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500555
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500556 As this is run after every stage we should be able to find the one
557 responsible for the errors easily even if we look at every .pc and .la file.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500558 """
559
560 sane = True
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500561 tmpdir = d.getVar('TMPDIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500562 workdir = os.path.join(tmpdir, "work")
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500563 recipesysroot = d.getVar("RECIPE_SYSROOT")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500564
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500565 if bb.data.inherits_class("native", d) or bb.data.inherits_class("cross", d):
566 pkgconfigcheck = workdir
567 else:
568 pkgconfigcheck = tmpdir
569
Brad Bishop19323692019-04-05 15:28:33 -0400570 skip = (d.getVar('INSANE_SKIP') or "").split()
571 skip_la = False
572 if 'la' in skip:
573 bb.note("Recipe %s skipping qa checking: la" % d.getVar('PN'))
574 skip_la = True
575
576 skip_pkgconfig = False
577 if 'pkgconfig' in skip:
578 bb.note("Recipe %s skipping qa checking: pkgconfig" % d.getVar('PN'))
579 skip_pkgconfig = True
580
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500581 # find all .la and .pc files
582 # read the content
583 # and check for stuff that looks wrong
584 for root, dirs, files in os.walk(path):
585 for file in files:
586 path = os.path.join(root,file)
Brad Bishop19323692019-04-05 15:28:33 -0400587 if file.endswith(".la") and not skip_la:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500588 with open(path) as f:
589 file_content = f.read()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500590 file_content = file_content.replace(recipesysroot, "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500591 if workdir in file_content:
592 error_msg = "%s failed sanity test (workdir) in path %s" % (file,root)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800593 sane &= package_qa_handle_error("la", error_msg, d)
Brad Bishop19323692019-04-05 15:28:33 -0400594 elif file.endswith(".pc") and not skip_pkgconfig:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500595 with open(path) as f:
596 file_content = f.read()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500597 file_content = file_content.replace(recipesysroot, "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500598 if pkgconfigcheck in file_content:
599 error_msg = "%s failed sanity test (tmpdir) in path %s" % (file,root)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800600 sane &= package_qa_handle_error("pkgconfig", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500601
602 return sane
603
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500604# Run all package-wide warnfuncs and errorfuncs
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500605def package_qa_package(warnfuncs, errorfuncs, package, d):
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500606 warnings = {}
607 errors = {}
608
609 for func in warnfuncs:
610 func(package, d, warnings)
611 for func in errorfuncs:
612 func(package, d, errors)
613
614 for w in warnings:
615 package_qa_handle_error(w, warnings[w], d)
616 for e in errors:
617 package_qa_handle_error(e, errors[e], d)
618
619 return len(errors) == 0
620
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500621# Run all recipe-wide warnfuncs and errorfuncs
622def package_qa_recipe(warnfuncs, errorfuncs, pn, d):
623 warnings = {}
624 errors = {}
625
626 for func in warnfuncs:
627 func(pn, d, warnings)
628 for func in errorfuncs:
629 func(pn, d, errors)
630
631 for w in warnings:
632 package_qa_handle_error(w, warnings[w], d)
633 for e in errors:
634 package_qa_handle_error(e, errors[e], d)
635
636 return len(errors) == 0
637
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500638# Walk over all files in a directory and call func
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500639def package_qa_walk(warnfuncs, errorfuncs, package, d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500640 import oe.qa
641
642 #if this will throw an exception, then fix the dict above
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500643 target_os = d.getVar('TARGET_OS')
644 target_arch = d.getVar('TARGET_ARCH')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500645
646 warnings = {}
647 errors = {}
648 for path in pkgfiles[package]:
649 elf = oe.qa.ELFFile(path)
650 try:
651 elf.open()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500652 except (IOError, oe.qa.NotELFFileError):
653 # IOError can happen if the packaging control files disappear,
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500654 elf = None
655 for func in warnfuncs:
656 func(path, package, d, elf, warnings)
657 for func in errorfuncs:
658 func(path, package, d, elf, errors)
659
660 for w in warnings:
661 package_qa_handle_error(w, warnings[w], d)
662 for e in errors:
663 package_qa_handle_error(e, errors[e], d)
664
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500665def package_qa_check_rdepends(pkg, pkgdest, skip, taskdeps, packages, d):
666 # Don't do this check for kernel/module recipes, there aren't too many debug/development
667 # packages and you can get false positives e.g. on kernel-module-lirc-dev
668 if bb.data.inherits_class("kernel", d) or bb.data.inherits_class("module-base", d):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500669 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500670
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500671 if not "-dbg" in pkg and not "packagegroup-" in pkg and not "-image" in pkg:
672 localdata = bb.data.createCopy(d)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500673 localdata.setVar('OVERRIDES', localdata.getVar('OVERRIDES') + ':' + pkg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500674
675 # Now check the RDEPENDS
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500676 rdepends = bb.utils.explode_deps(localdata.getVar('RDEPENDS') or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500677
678 # Now do the sanity check!!!
679 if "build-deps" not in skip:
680 for rdepend in rdepends:
681 if "-dbg" in rdepend and "debug-deps" not in skip:
682 error_msg = "%s rdepends on %s" % (pkg,rdepend)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500683 package_qa_handle_error("debug-deps", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500684 if (not "-dev" in pkg and not "-staticdev" in pkg) and rdepend.endswith("-dev") and "dev-deps" not in skip:
685 error_msg = "%s rdepends on %s" % (pkg, rdepend)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500686 package_qa_handle_error("dev-deps", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500687 if rdepend not in packages:
688 rdep_data = oe.packagedata.read_subpkgdata(rdepend, d)
689 if rdep_data and 'PN' in rdep_data and rdep_data['PN'] in taskdeps:
690 continue
691 if not rdep_data or not 'PN' in rdep_data:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500692 pkgdata_dir = d.getVar("PKGDATA_DIR")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500693 try:
694 possibles = os.listdir("%s/runtime-rprovides/%s/" % (pkgdata_dir, rdepend))
695 except OSError:
696 possibles = []
697 for p in possibles:
698 rdep_data = oe.packagedata.read_subpkgdata(p, d)
699 if rdep_data and 'PN' in rdep_data and rdep_data['PN'] in taskdeps:
700 break
701 if rdep_data and 'PN' in rdep_data and rdep_data['PN'] in taskdeps:
702 continue
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500703 if rdep_data and 'PN' in rdep_data:
704 error_msg = "%s rdepends on %s, but it isn't a build dependency, missing %s in DEPENDS or PACKAGECONFIG?" % (pkg, rdepend, rdep_data['PN'])
705 else:
706 error_msg = "%s rdepends on %s, but it isn't a build dependency?" % (pkg, rdepend)
707 package_qa_handle_error("build-deps", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500708
709 if "file-rdeps" not in skip:
710 ignored_file_rdeps = set(['/bin/sh', '/usr/bin/env', 'rtld(GNU_HASH)'])
711 if bb.data.inherits_class('nativesdk', d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500712 ignored_file_rdeps |= set(['/bin/bash', '/usr/bin/perl', 'perl'])
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500713 # For Saving the FILERDEPENDS
714 filerdepends = {}
715 rdep_data = oe.packagedata.read_subpkgdata(pkg, d)
716 for key in rdep_data:
717 if key.startswith("FILERDEPENDS_"):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500718 for subkey in bb.utils.explode_deps(rdep_data[key]):
719 if subkey not in ignored_file_rdeps and \
720 not subkey.startswith('perl('):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500721 # We already know it starts with FILERDEPENDS_
722 filerdepends[subkey] = key[13:]
723
724 if filerdepends:
725 next = rdepends
726 done = rdepends[:]
727 # Find all the rdepends on the dependency chain
728 while next:
729 new = []
730 for rdep in next:
731 rdep_data = oe.packagedata.read_subpkgdata(rdep, d)
732 sub_rdeps = rdep_data.get("RDEPENDS_" + rdep)
733 if not sub_rdeps:
734 continue
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500735 for sub_rdep in bb.utils.explode_deps(sub_rdeps):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500736 if sub_rdep in done:
737 continue
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500738 if oe.packagedata.has_subpkgdata(sub_rdep, d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500739 # It's a new rdep
740 done.append(sub_rdep)
741 new.append(sub_rdep)
742 next = new
743
744 # Add the rprovides of itself
745 if pkg not in done:
746 done.insert(0, pkg)
747
748 # The python is not a package, but python-core provides it, so
749 # skip checking /usr/bin/python if python is in the rdeps, in
750 # case there is a RDEPENDS_pkg = "python" in the recipe.
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500751 for py in [ d.getVar('MLPREFIX') + "python", "python" ]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500752 if py in done:
753 filerdepends.pop("/usr/bin/python",None)
754 done.remove(py)
755 for rdep in done:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500756 # The file dependencies may contain package names, e.g.,
757 # perl
758 filerdepends.pop(rdep,None)
759
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500760 # For Saving the FILERPROVIDES, RPROVIDES and FILES_INFO
761 rdep_data = oe.packagedata.read_subpkgdata(rdep, d)
762 for key in rdep_data:
763 if key.startswith("FILERPROVIDES_") or key.startswith("RPROVIDES_"):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500764 for subkey in bb.utils.explode_deps(rdep_data[key]):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500765 filerdepends.pop(subkey,None)
766 # Add the files list to the rprovides
767 if key == "FILES_INFO":
768 # Use eval() to make it as a dict
769 for subkey in eval(rdep_data[key]):
770 filerdepends.pop(subkey,None)
771 if not filerdepends:
772 # Break if all the file rdepends are met
773 break
774 if filerdepends:
775 for key in filerdepends:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500776 error_msg = "%s contained in package %s requires %s, but no providers found in RDEPENDS_%s?" % \
777 (filerdepends[key].replace("_%s" % pkg, "").replace("@underscore@", "_"), pkg, key, pkg)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500778 package_qa_handle_error("file-rdeps", error_msg, d)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500779package_qa_check_rdepends[vardepsexclude] = "OVERRIDES"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500780
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500781def package_qa_check_deps(pkg, pkgdest, d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500782
783 localdata = bb.data.createCopy(d)
784 localdata.setVar('OVERRIDES', pkg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500785
786 def check_valid_deps(var):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500787 try:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500788 rvar = bb.utils.explode_dep_versions2(localdata.getVar(var) or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500789 except ValueError as e:
790 bb.fatal("%s_%s: %s" % (var, pkg, e))
791 for dep in rvar:
792 for v in rvar[dep]:
793 if v and not v.startswith(('< ', '= ', '> ', '<= ', '>=')):
794 error_msg = "%s_%s is invalid: %s (%s) only comparisons <, =, >, <=, and >= are allowed" % (var, pkg, dep, v)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500795 package_qa_handle_error("dep-cmp", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500796
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500797 check_valid_deps('RDEPENDS')
798 check_valid_deps('RRECOMMENDS')
799 check_valid_deps('RSUGGESTS')
800 check_valid_deps('RPROVIDES')
801 check_valid_deps('RREPLACES')
802 check_valid_deps('RCONFLICTS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500803
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500804QAPKGTEST[usrmerge] = "package_qa_check_usrmerge"
805def package_qa_check_usrmerge(pkg, d, messages):
806 pkgdest = d.getVar('PKGDEST')
807 pkg_dir = pkgdest + os.sep + pkg + os.sep
808 merged_dirs = ['bin', 'sbin', 'lib'] + d.getVar('MULTILIB_VARIANTS').split()
809 for f in merged_dirs:
810 if os.path.exists(pkg_dir + f) and not os.path.islink(pkg_dir + f):
811 msg = "%s package is not obeying usrmerge distro feature. /%s should be relocated to /usr." % (pkg, f)
812 package_qa_add_message(messages, "usrmerge", msg)
813 return False
814 return True
815
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500816QAPKGTEST[expanded-d] = "package_qa_check_expanded_d"
817def package_qa_check_expanded_d(package, d, messages):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500818 """
819 Check for the expanded D (${D}) value in pkg_* and FILES
820 variables, warn the user to use it correctly.
821 """
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500822 sane = True
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500823 expanded_d = d.getVar('D')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500824
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500825 for var in 'FILES','pkg_preinst', 'pkg_postinst', 'pkg_prerm', 'pkg_postrm':
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500826 bbvar = d.getVar(var + "_" + package) or ""
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500827 if expanded_d in bbvar:
828 if var == 'FILES':
829 package_qa_add_message(messages, "expanded-d", "FILES in %s recipe should not contain the ${D} variable as it references the local build directory not the target filesystem, best solution is to remove the ${D} reference" % package)
830 sane = False
831 else:
832 package_qa_add_message(messages, "expanded-d", "%s in %s recipe contains ${D}, it should be replaced by $D instead" % (var, package))
833 sane = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500834 return sane
835
836def package_qa_check_encoding(keys, encode, d):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600837 def check_encoding(key, enc):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500838 sane = True
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500839 value = d.getVar(key)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500840 if value:
841 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600842 s = value.encode(enc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500843 except UnicodeDecodeError as e:
844 error_msg = "%s has non %s characters" % (key,enc)
845 sane = False
846 package_qa_handle_error("invalid-chars", error_msg, d)
847 return sane
848
849 for key in keys:
850 sane = check_encoding(key, encode)
851 if not sane:
852 break
853
854HOST_USER_UID := "${@os.getuid()}"
855HOST_USER_GID := "${@os.getgid()}"
856
857QAPATHTEST[host-user-contaminated] = "package_qa_check_host_user"
858def package_qa_check_host_user(path, name, d, elf, messages):
859 """Check for paths outside of /home which are owned by the user running bitbake."""
860
861 if not os.path.lexists(path):
862 return
863
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500864 dest = d.getVar('PKGDEST')
865 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500866 home = os.path.join(dest, 'home')
867 if path == home or path.startswith(home + os.sep):
868 return
869
870 try:
871 stat = os.lstat(path)
872 except OSError as exc:
873 import errno
874 if exc.errno != errno.ENOENT:
875 raise
876 else:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500877 check_uid = int(d.getVar('HOST_USER_UID'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500878 if stat.st_uid == check_uid:
Brad Bishop96ff1982019-08-19 13:50:42 -0400879 package_qa_add_message(messages, "host-user-contaminated", "%s: %s is owned by uid %d, which is the same as the user running bitbake. This may be due to host contamination" % (pn, package_qa_clean_path(path, d, name), check_uid))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500880 return False
881
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500882 check_gid = int(d.getVar('HOST_USER_GID'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500883 if stat.st_gid == check_gid:
Brad Bishop96ff1982019-08-19 13:50:42 -0400884 package_qa_add_message(messages, "host-user-contaminated", "%s: %s is owned by gid %d, which is the same as the user running bitbake. This may be due to host contamination" % (pn, package_qa_clean_path(path, d, name), check_gid))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500885 return False
886 return True
887
Brad Bishop15ae2502019-06-18 21:44:24 -0400888QARECIPETEST[src-uri-bad] = "package_qa_check_src_uri"
889def package_qa_check_src_uri(pn, d, messages):
890 import re
891
892 if "${PN}" in d.getVar("SRC_URI", False):
893 package_qa_handle_error("src-uri-bad", "%s: SRC_URI uses PN not BPN" % pn, d)
894
895 pn = d.getVar("SRC_URI")
896 if re.search(r"github\.com/.+/.+/archive/.+", pn):
897 package_qa_handle_error("src-uri-bad", "%s: SRC_URI uses unstable GitHub archives" % pn, d)
898
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500899
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500900# The PACKAGE FUNC to scan each package
901python do_package_qa () {
902 import subprocess
903 import oe.packagedata
904
905 bb.note("DO PACKAGE QA")
906
907 bb.build.exec_func("read_subpackage_metadata", d)
908
909 # Check non UTF-8 characters on recipe's metadata
910 package_qa_check_encoding(['DESCRIPTION', 'SUMMARY', 'LICENSE', 'SECTION'], 'utf-8', d)
911
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500912 logdir = d.getVar('T')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500913 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500914
915 # Check the compile log for host contamination
916 compilelog = os.path.join(logdir,"log.do_compile")
917
918 if os.path.exists(compilelog):
919 statement = "grep -e 'CROSS COMPILE Badness:' -e 'is unsafe for cross-compilation' %s > /dev/null" % compilelog
920 if subprocess.call(statement, shell=True) == 0:
921 msg = "%s: The compile log indicates that host include and/or library paths were used.\n \
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500922 Please check the log '%s' for more information." % (pn, compilelog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500923 package_qa_handle_error("compile-host-path", msg, d)
924
925 # Check the install log for host contamination
926 installlog = os.path.join(logdir,"log.do_install")
927
928 if os.path.exists(installlog):
929 statement = "grep -e 'CROSS COMPILE Badness:' -e 'is unsafe for cross-compilation' %s > /dev/null" % installlog
930 if subprocess.call(statement, shell=True) == 0:
931 msg = "%s: The install log indicates that host include and/or library paths were used.\n \
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500932 Please check the log '%s' for more information." % (pn, installlog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500933 package_qa_handle_error("install-host-path", msg, d)
934
935 # Scan the packages...
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500936 pkgdest = d.getVar('PKGDEST')
937 packages = set((d.getVar('PACKAGES') or '').split())
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500938
939 cpath = oe.cachedpath.CachedPath()
940 global pkgfiles
941 pkgfiles = {}
942 for pkg in packages:
943 pkgfiles[pkg] = []
944 for walkroot, dirs, files in cpath.walk(pkgdest + "/" + pkg):
945 for file in files:
946 pkgfiles[pkg].append(walkroot + os.sep + file)
947
948 # no packages should be scanned
949 if not packages:
950 return
951
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500952 import re
953 # The package name matches the [a-z0-9.+-]+ regular expression
Brad Bishop977dc1a2019-02-06 16:01:43 -0500954 pkgname_pattern = re.compile(r"^[a-z0-9.+-]+$")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500955
956 taskdepdata = d.getVar("BB_TASKDEPDATA", False)
957 taskdeps = set()
958 for dep in taskdepdata:
959 taskdeps.add(taskdepdata[dep][0])
960
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500961 def parse_test_matrix(matrix_name):
962 testmatrix = d.getVarFlags(matrix_name) or {}
963 g = globals()
964 warnchecks = []
965 for w in (d.getVar("WARN_QA") or "").split():
966 if w in skip:
967 continue
968 if w in testmatrix and testmatrix[w] in g:
969 warnchecks.append(g[testmatrix[w]])
970
971 errorchecks = []
972 for e in (d.getVar("ERROR_QA") or "").split():
973 if e in skip:
974 continue
975 if e in testmatrix and testmatrix[e] in g:
976 errorchecks.append(g[testmatrix[e]])
977 return warnchecks, errorchecks
978
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500979 for package in packages:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500980 skip = set((d.getVar('INSANE_SKIP') or "").split() +
981 (d.getVar('INSANE_SKIP_' + package) or "").split())
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500982 if skip:
983 bb.note("Package %s skipping QA tests: %s" % (package, str(skip)))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500984
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500985 bb.note("Checking Package: %s" % package)
986 # Check package name
987 if not pkgname_pattern.match(package):
988 package_qa_handle_error("pkgname",
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500989 "%s doesn't match the [a-z0-9.+-]+ regex" % package, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500990
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500991 warn_checks, error_checks = parse_test_matrix("QAPATHTEST")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500992 package_qa_walk(warn_checks, error_checks, package, d)
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500993
994 warn_checks, error_checks = parse_test_matrix("QAPKGTEST")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500995 package_qa_package(warn_checks, error_checks, package, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500996
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500997 package_qa_check_rdepends(package, pkgdest, skip, taskdeps, packages, d)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500998 package_qa_check_deps(package, pkgdest, d)
999
1000 warn_checks, error_checks = parse_test_matrix("QARECIPETEST")
1001 package_qa_recipe(warn_checks, error_checks, pn, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001002
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001003 if 'libdir' in d.getVar("ALL_QA").split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001004 package_qa_check_libdir(d)
1005
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001006 qa_sane = d.getVar("QA_SANE")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001007 if not qa_sane:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001008 bb.fatal("QA run found fatal errors. Please consider fixing them.")
1009 bb.note("DONE with PACKAGE QA")
1010}
1011
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001012# binutils is used for most checks, so need to set as dependency
1013# POPULATESYSROOTDEPS is defined in staging class.
1014do_package_qa[depends] += "${POPULATESYSROOTDEPS}"
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001015do_package_qa[vardepsexclude] = "BB_TASKDEPDATA"
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001016do_package_qa[rdeptask] = "do_packagedata"
1017addtask do_package_qa after do_packagedata do_package before do_build
1018
Brad Bishop19323692019-04-05 15:28:33 -04001019# Add the package specific INSANE_SKIPs to the sstate dependencies
1020python() {
1021 pkgs = (d.getVar('PACKAGES') or '').split()
1022 for pkg in pkgs:
1023 d.appendVarFlag("do_package_qa", "vardeps", " INSANE_SKIP_{}".format(pkg))
1024}
1025
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001026SSTATETASKS += "do_package_qa"
1027do_package_qa[sstate-inputdirs] = ""
1028do_package_qa[sstate-outputdirs] = ""
1029python do_package_qa_setscene () {
1030 sstate_setscene(d)
1031}
1032addtask do_package_qa_setscene
1033
1034python do_qa_staging() {
1035 bb.note("QA checking staging")
Brad Bishop19323692019-04-05 15:28:33 -04001036 if not qa_check_staged(d.expand('${SYSROOT_DESTDIR}${libdir}'), d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001037 bb.fatal("QA staging was broken by the package built above")
1038}
1039
Brad Bishopd89cb5f2019-04-10 09:02:41 -04001040python do_qa_patch() {
1041 import subprocess
1042
1043 ###########################################################################
1044 # Check patch.log for fuzz warnings
1045 #
1046 # Further information on why we check for patch fuzz warnings:
1047 # http://lists.openembedded.org/pipermail/openembedded-core/2018-March/148675.html
1048 # https://bugzilla.yoctoproject.org/show_bug.cgi?id=10450
1049 ###########################################################################
1050
1051 logdir = d.getVar('T')
1052 patchlog = os.path.join(logdir,"log.do_patch")
1053
1054 if os.path.exists(patchlog):
1055 fuzzheader = '--- Patch fuzz start ---'
1056 fuzzfooter = '--- Patch fuzz end ---'
1057 statement = "grep -e '%s' %s > /dev/null" % (fuzzheader, patchlog)
1058 if subprocess.call(statement, shell=True) == 0:
1059 msg = "Fuzz detected:\n\n"
1060 fuzzmsg = ""
1061 inFuzzInfo = False
1062 f = open(patchlog, "r")
1063 for line in f:
1064 if fuzzheader in line:
1065 inFuzzInfo = True
1066 fuzzmsg = ""
1067 elif fuzzfooter in line:
1068 fuzzmsg = fuzzmsg.replace('\n\n', '\n')
1069 msg += fuzzmsg
1070 msg += "\n"
1071 inFuzzInfo = False
1072 elif inFuzzInfo and not 'Now at patch' in line:
1073 fuzzmsg += line
1074 f.close()
1075 msg += "The context lines in the patches can be updated with devtool:\n"
1076 msg += "\n"
1077 msg += " devtool modify %s\n" % d.getVar('PN')
1078 msg += " devtool finish --force-patch-refresh %s <layer_path>\n\n" % d.getVar('PN')
1079 msg += "Don't forget to review changes done by devtool!\n"
1080 if 'patch-fuzz' in d.getVar('ERROR_QA'):
1081 bb.error(msg)
1082 elif 'patch-fuzz' in d.getVar('WARN_QA'):
1083 bb.warn(msg)
1084 msg = "Patch log indicates that patches do not apply cleanly."
1085 package_qa_handle_error("patch-fuzz", msg, d)
1086}
1087
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001088python do_qa_configure() {
1089 import subprocess
1090
1091 ###########################################################################
1092 # Check config.log for cross compile issues
1093 ###########################################################################
1094
1095 configs = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001096 workdir = d.getVar('WORKDIR')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001097
Brad Bishop19323692019-04-05 15:28:33 -04001098 skip = (d.getVar('INSANE_SKIP') or "").split()
1099 skip_configure_unsafe = False
1100 if 'configure-unsafe' in skip:
1101 bb.note("Recipe %s skipping qa checking: configure-unsafe" % d.getVar('PN'))
1102 skip_configure_unsafe = True
1103
1104 if bb.data.inherits_class('autotools', d) and not skip_configure_unsafe:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001105 bb.note("Checking autotools environment for common misconfiguration")
1106 for root, dirs, files in os.walk(workdir):
1107 statement = "grep -q -F -e 'CROSS COMPILE Badness:' -e 'is unsafe for cross-compilation' %s" % \
1108 os.path.join(root,"config.log")
1109 if "config.log" in files:
1110 if subprocess.call(statement, shell=True) == 0:
Brad Bishop19323692019-04-05 15:28:33 -04001111 error_msg = """This autoconf log indicates errors, it looked at host include and/or library paths while determining system capabilities.
1112Rerun configure task after fixing this."""
1113 package_qa_handle_error("configure-unsafe", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001114
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001115 if "configure.ac" in files:
1116 configs.append(os.path.join(root,"configure.ac"))
1117 if "configure.in" in files:
1118 configs.append(os.path.join(root, "configure.in"))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001119
1120 ###########################################################################
1121 # Check gettext configuration and dependencies are correct
1122 ###########################################################################
1123
Brad Bishop19323692019-04-05 15:28:33 -04001124 skip_configure_gettext = False
1125 if 'configure-gettext' in skip:
1126 bb.note("Recipe %s skipping qa checking: configure-gettext" % d.getVar('PN'))
1127 skip_configure_gettext = True
1128
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001129 cnf = d.getVar('EXTRA_OECONF') or ""
Brad Bishop19323692019-04-05 15:28:33 -04001130 if not ("gettext" in d.getVar('P') or "gcc-runtime" in d.getVar('P') or \
1131 "--disable-nls" in cnf or skip_configure_gettext):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001132 ml = d.getVar("MLPREFIX") or ""
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001133 if bb.data.inherits_class('cross-canadian', d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001134 gt = "nativesdk-gettext"
1135 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001136 gt = "gettext-native"
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001137 deps = bb.utils.explode_deps(d.getVar('DEPENDS') or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001138 if gt not in deps:
1139 for config in configs:
1140 gnu = "grep \"^[[:space:]]*AM_GNU_GETTEXT\" %s >/dev/null" % config
1141 if subprocess.call(gnu, shell=True) == 0:
Brad Bishopd89cb5f2019-04-10 09:02:41 -04001142 error_msg = "AM_GNU_GETTEXT used but no inherit gettext"
Brad Bishop19323692019-04-05 15:28:33 -04001143 package_qa_handle_error("configure-gettext", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001144
1145 ###########################################################################
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001146 # Check unrecognised configure options (with a white list)
1147 ###########################################################################
Brad Bishopc342db32019-05-15 21:57:59 -04001148 if bb.data.inherits_class("autotools", d) or bb.data.inherits_class("meson", d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001149 bb.note("Checking configure output for unrecognised options")
1150 try:
Brad Bishopc342db32019-05-15 21:57:59 -04001151 if bb.data.inherits_class("autotools", d):
1152 flag = "WARNING: unrecognized options:"
1153 log = os.path.join(d.getVar('B'), 'config.log')
1154 if bb.data.inherits_class("meson", d):
1155 flag = "WARNING: Unknown options:"
1156 log = os.path.join(d.getVar('T'), 'log.do_configure')
1157 output = subprocess.check_output(['grep', '-F', flag, log]).decode("utf-8").replace(', ', ' ').replace('"', '')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001158 options = set()
1159 for line in output.splitlines():
1160 options |= set(line.partition(flag)[2].split())
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001161 whitelist = set(d.getVar("UNKNOWN_CONFIGURE_WHITELIST").split())
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001162 options -= whitelist
1163 if options:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001164 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001165 error_msg = pn + ": configure was passed unrecognised options: " + " ".join(options)
1166 package_qa_handle_error("unknown-configure-option", error_msg, d)
1167 except subprocess.CalledProcessError:
1168 pass
1169
1170 # Check invalid PACKAGECONFIG
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001171 pkgconfig = (d.getVar("PACKAGECONFIG") or "").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001172 if pkgconfig:
1173 pkgconfigflags = d.getVarFlags("PACKAGECONFIG") or {}
1174 for pconfig in pkgconfig:
1175 if pconfig not in pkgconfigflags:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001176 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001177 error_msg = "%s: invalid PACKAGECONFIG: %s" % (pn, pconfig)
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001178 package_qa_handle_error("invalid-packageconfig", error_msg, d)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001179
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001180 qa_sane = d.getVar("QA_SANE")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001181 if not qa_sane:
1182 bb.fatal("Fatal QA errors found, failing task.")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001183}
1184
1185python do_qa_unpack() {
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001186 src_uri = d.getVar('SRC_URI')
1187 s_dir = d.getVar('S')
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001188 if src_uri and not os.path.exists(s_dir):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001189 bb.warn('%s: the directory %s (%s) pointed to by the S variable doesn\'t exist - please set S within the recipe to point to where the source has been unpacked to' % (d.getVar('PN'), d.getVar('S', False), s_dir))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001190}
1191
1192# The Staging Func, to check all staging
1193#addtask qa_staging after do_populate_sysroot before do_build
1194do_populate_sysroot[postfuncs] += "do_qa_staging "
1195
Brad Bishopd89cb5f2019-04-10 09:02:41 -04001196# Check for patch fuzz
1197do_patch[postfuncs] += "do_qa_patch "
1198
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001199# Check broken config.log files, for packages requiring Gettext which
1200# don't have it in DEPENDS.
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001201#addtask qa_configure after do_configure before do_compile
1202do_configure[postfuncs] += "do_qa_configure "
1203
1204# Check does S exist.
1205do_unpack[postfuncs] += "do_qa_unpack"
1206
1207python () {
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001208 import re
1209
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001210 tests = d.getVar('ALL_QA').split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001211 if "desktop" in tests:
1212 d.appendVar("PACKAGE_DEPENDS", " desktop-file-utils-native")
1213
1214 ###########################################################################
1215 # Check various variables
1216 ###########################################################################
1217
1218 # Checking ${FILESEXTRAPATHS}
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001219 extrapaths = (d.getVar("FILESEXTRAPATHS") or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001220 if '__default' not in extrapaths.split(":"):
1221 msg = "FILESEXTRAPATHS-variable, must always use _prepend (or _append)\n"
1222 msg += "type of assignment, and don't forget the colon.\n"
1223 msg += "Please assign it with the format of:\n"
1224 msg += " FILESEXTRAPATHS_append := \":${THISDIR}/Your_Files_Path\" or\n"
1225 msg += " FILESEXTRAPATHS_prepend := \"${THISDIR}/Your_Files_Path:\"\n"
1226 msg += "in your bbappend file\n\n"
1227 msg += "Your incorrect assignment is:\n"
1228 msg += "%s\n" % extrapaths
1229 bb.warn(msg)
1230
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001231 overrides = d.getVar('OVERRIDES').split(':')
1232 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001233 if pn in overrides:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001234 msg = 'Recipe %s has PN of "%s" which is in OVERRIDES, this can result in unexpected behaviour.' % (d.getVar("FILE"), pn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001235 package_qa_handle_error("pn-overrides", msg, d)
Brad Bishop977dc1a2019-02-06 16:01:43 -05001236 prog = re.compile(r'[A-Z]')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001237 if prog.search(pn):
1238 package_qa_handle_error("uppercase-pn", 'PN: %s is upper case, this can result in unexpected behavior.' % pn, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001239
1240 issues = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001241 if (d.getVar('PACKAGES') or "").split():
1242 for dep in (d.getVar('QADEPENDS') or "").split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001243 d.appendVarFlag('do_package_qa', 'depends', " %s:do_populate_sysroot" % dep)
1244 for var in 'RDEPENDS', 'RRECOMMENDS', 'RSUGGESTS', 'RCONFLICTS', 'RPROVIDES', 'RREPLACES', 'FILES', 'pkg_preinst', 'pkg_postinst', 'pkg_prerm', 'pkg_postrm', 'ALLOW_EMPTY':
1245 if d.getVar(var, False):
1246 issues.append(var)
1247
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001248 fakeroot_tests = d.getVar('FAKEROOT_QA').split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001249 if set(tests) & set(fakeroot_tests):
1250 d.setVarFlag('do_package_qa', 'fakeroot', '1')
1251 d.appendVarFlag('do_package_qa', 'depends', ' virtual/fakeroot-native:do_populate_sysroot')
1252 else:
1253 d.setVarFlag('do_package_qa', 'rdeptask', '')
1254 for i in issues:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001255 package_qa_handle_error("pkgvarcheck", "%s: Variable %s is set as not being package specific, please fix this." % (d.getVar("FILE"), i), d)
1256 qa_sane = d.getVar("QA_SANE")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001257 if not qa_sane:
1258 bb.fatal("Fatal QA errors found, failing task.")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001259}