blob: 4267cbd0f6106db7763ad8151d4467af69001e6b [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 Bishop6e60e8b2018-02-01 10:27:11 -050028 pn-overrides infodir build-deps \
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
262QAPATHTEST[perms] = "package_qa_check_perm"
263def package_qa_check_perm(path,name,d, elf, messages):
264 """
265 Check the permission of files
266 """
267 return
268
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500269QAPATHTEST[arch] = "package_qa_check_arch"
270def package_qa_check_arch(path,name,d, elf, messages):
271 """
272 Check if archs are compatible
273 """
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800274 import re, oe.elf
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600275
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500276 if not elf:
277 return
278
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500279 target_os = d.getVar('TARGET_OS')
280 target_arch = d.getVar('TARGET_ARCH')
281 provides = d.getVar('PROVIDES')
282 bpn = d.getVar('BPN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500283
284 if target_arch == "allarch":
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500285 pn = d.getVar('PN')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500286 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 -0500287 return
288
289 # FIXME: Cross package confuse this check, so just skip them
290 for s in ['cross', 'nativesdk', 'cross-canadian']:
291 if bb.data.inherits_class(s, d):
292 return
293
294 # avoid following links to /usr/bin (e.g. on udev builds)
295 # we will check the files pointed to anyway...
296 if os.path.islink(path):
297 return
298
299 #if this will throw an exception, then fix the dict above
300 (machine, osabi, abiversion, littleendian, bits) \
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800301 = oe.elf.machine_dict(d)[target_os][target_arch]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500302
303 # Check the architecture and endiannes of the binary
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600304 is_32 = (("virtual/kernel" in provides) or bb.data.inherits_class("module", d)) and \
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800305 (target_os == "linux-gnux32" or target_os == "linux-muslx32" or \
Brad Bishop977dc1a2019-02-06 16:01:43 -0500306 target_os == "linux-gnu_ilp32" or re.match(r'mips64.*32', d.getVar('DEFAULTTUNE')))
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800307 is_bpf = (oe.qa.elf_machine_to_string(elf.machine()) == "BPF")
308 if not ((machine == elf.machine()) or is_32 or is_bpf):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600309 package_qa_add_message(messages, "arch", "Architecture did not match (%s, expected %s) on %s" % \
310 (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 -0400311 elif not ((bits == elf.abiSize()) or is_32 or is_bpf):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500312 package_qa_add_message(messages, "arch", "Bit size did not match (%d to %d) %s on %s" % \
313 (bits, elf.abiSize(), bpn, package_qa_clean_path(path,d)))
Brad Bishop19323692019-04-05 15:28:33 -0400314 elif not ((littleendian == elf.isLittleEndian()) or is_bpf):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500315 package_qa_add_message(messages, "arch", "Endiannes did not match (%d to %d) on %s" % \
316 (littleendian, elf.isLittleEndian(), package_qa_clean_path(path,d)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500317
318QAPATHTEST[desktop] = "package_qa_check_desktop"
319def package_qa_check_desktop(path, name, d, elf, messages):
320 """
321 Run all desktop files through desktop-file-validate.
322 """
323 if path.endswith(".desktop"):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500324 desktop_file_validate = os.path.join(d.getVar('STAGING_BINDIR_NATIVE'),'desktop-file-validate')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500325 output = os.popen("%s %s" % (desktop_file_validate, path))
326 # This only produces output on errors
327 for l in output:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500328 package_qa_add_message(messages, "desktop", "Desktop file issue: " + l.strip())
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500329
330QAPATHTEST[textrel] = "package_qa_textrel"
331def package_qa_textrel(path, name, d, elf, messages):
332 """
333 Check if the binary contains relocations in .text
334 """
335
336 if not elf:
337 return
338
339 if os.path.islink(path):
340 return
341
342 phdrs = elf.run_objdump("-p", d)
343 sane = True
344
345 import re
Brad Bishop977dc1a2019-02-06 16:01:43 -0500346 textrel_re = re.compile(r"\s+TEXTREL\s+")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500347 for line in phdrs.split("\n"):
348 if textrel_re.match(line):
349 sane = False
350
351 if not sane:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500352 package_qa_add_message(messages, "textrel", "ELF binary '%s' has relocations in .text" % path)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500353
354QAPATHTEST[ldflags] = "package_qa_hash_style"
355def package_qa_hash_style(path, name, d, elf, messages):
356 """
357 Check if the binary has the right hash style...
358 """
359
360 if not elf:
361 return
362
363 if os.path.islink(path):
364 return
365
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500366 gnu_hash = "--hash-style=gnu" in d.getVar('LDFLAGS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500367 if not gnu_hash:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500368 gnu_hash = "--hash-style=both" in d.getVar('LDFLAGS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500369 if not gnu_hash:
370 return
371
372 sane = False
373 has_syms = False
374
375 phdrs = elf.run_objdump("-p", d)
376
377 # If this binary has symbols, we expect it to have GNU_HASH too.
378 for line in phdrs.split("\n"):
379 if "SYMTAB" in line:
380 has_syms = True
381 if "GNU_HASH" in line:
382 sane = True
383 if "[mips32]" in line or "[mips64]" in line:
384 sane = True
385
386 if has_syms and not sane:
Brad Bishopa5c52ff2018-11-23 10:55:50 +1300387 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 -0500388
389
390QAPATHTEST[buildpaths] = "package_qa_check_buildpaths"
391def package_qa_check_buildpaths(path, name, d, elf, messages):
392 """
393 Check for build paths inside target files and error if not found in the whitelist
394 """
395 # Ignore .debug files, not interesting
396 if path.find(".debug") != -1:
397 return
398
399 # Ignore symlinks
400 if os.path.islink(path):
401 return
402
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500403 # Ignore ipk and deb's CONTROL dir
404 if path.find(name + "/CONTROL/") != -1 or path.find(name + "/DEBIAN/") != -1:
405 return
406
Brad Bishopd5ae7d92018-06-14 09:52:03 -0700407 tmpdir = bytes(d.getVar('TMPDIR'), encoding="utf-8")
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500408 with open(path, 'rb') as f:
Brad Bishopd5ae7d92018-06-14 09:52:03 -0700409 file_content = f.read()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500410 if tmpdir in file_content:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500411 package_qa_add_message(messages, "buildpaths", "File %s in package contained reference to tmpdir" % package_qa_clean_path(path,d))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500412
413
414QAPATHTEST[xorg-driver-abi] = "package_qa_check_xorg_driver_abi"
415def package_qa_check_xorg_driver_abi(path, name, d, elf, messages):
416 """
417 Check that all packages containing Xorg drivers have ABI dependencies
418 """
419
420 # Skip dev, dbg or nativesdk packages
421 if name.endswith("-dev") or name.endswith("-dbg") or name.startswith("nativesdk-"):
422 return
423
424 driverdir = d.expand("${libdir}/xorg/modules/drivers/")
425 if driverdir in path and path.endswith(".so"):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500426 mlprefix = d.getVar('MLPREFIX') or ''
427 for rdep in bb.utils.explode_deps(d.getVar('RDEPENDS_' + name) or ""):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500428 if rdep.startswith("%sxorg-abi-" % mlprefix):
429 return
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500430 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 -0500431
432QAPATHTEST[infodir] = "package_qa_check_infodir"
433def package_qa_check_infodir(path, name, d, elf, messages):
434 """
435 Check that /usr/share/info/dir isn't shipped in a particular package
436 """
437 infodir = d.expand("${infodir}/dir")
438
439 if infodir in path:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500440 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 -0500441
442QAPATHTEST[symlink-to-sysroot] = "package_qa_check_symlink_to_sysroot"
443def package_qa_check_symlink_to_sysroot(path, name, d, elf, messages):
444 """
445 Check that the package doesn't contain any absolute symlinks to the sysroot.
446 """
447 if os.path.islink(path):
448 target = os.readlink(path)
449 if os.path.isabs(target):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500450 tmpdir = d.getVar('TMPDIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500451 if target.startswith(tmpdir):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500452 trimmed = path.replace(os.path.join (d.getVar("PKGDEST"), name), "")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500453 package_qa_add_message(messages, "symlink-to-sysroot", "Symlink %s in %s points to TMPDIR" % (trimmed, name))
454
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600455# Check license variables
456do_populate_lic[postfuncs] += "populate_lic_qa_checksum"
457python populate_lic_qa_checksum() {
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500458 """
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600459 Check for changes in the license files.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500460 """
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500461 sane = True
462
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500463 lic_files = d.getVar('LIC_FILES_CHKSUM') or ''
464 lic = d.getVar('LICENSE')
465 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500466
467 if lic == "CLOSED":
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500468 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500469
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500470 if not lic_files and d.getVar('SRC_URI'):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800471 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 -0500472
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500473 srcdir = d.getVar('S')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500474 corebase_licensefile = d.getVar('COREBASE') + "/LICENSE"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500475 for url in lic_files.split():
476 try:
477 (type, host, path, user, pswd, parm) = bb.fetch.decodeurl(url)
478 except bb.fetch.MalformedUrl:
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800479 sane &= package_qa_handle_error("license-checksum", pn + ": LIC_FILES_CHKSUM contains an invalid URL: " + url, d)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500480 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500481 srclicfile = os.path.join(srcdir, path)
482 if not os.path.isfile(srclicfile):
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800483 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 -0500484 continue
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500485
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500486 if (srclicfile == corebase_licensefile):
487 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")
488
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500489 recipemd5 = parm.get('md5', '')
490 beginline, endline = 0, 0
491 if 'beginline' in parm:
492 beginline = int(parm['beginline'])
493 if 'endline' in parm:
494 endline = int(parm['endline'])
495
496 if (not beginline) and (not endline):
497 md5chksum = bb.utils.md5_file(srclicfile)
Brad Bishop19323692019-04-05 15:28:33 -0400498 with open(srclicfile, 'r', errors='replace') as f:
499 license = f.read().splitlines()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500500 else:
Brad Bishop19323692019-04-05 15:28:33 -0400501 with open(srclicfile, 'rb') as f:
502 import hashlib
503 lineno = 0
504 license = []
505 m = hashlib.md5()
506 for line in f:
507 lineno += 1
508 if (lineno >= beginline):
509 if ((lineno <= endline) or not endline):
510 m.update(line)
511 license.append(line.decode('utf-8', errors='replace').rstrip())
512 else:
513 break
514 md5chksum = m.hexdigest()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500515 if recipemd5 == md5chksum:
516 bb.note (pn + ": md5 checksum matched for ", url)
517 else:
518 if recipemd5:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500519 msg = pn + ": The LIC_FILES_CHKSUM does not match for " + url
520 msg = msg + "\n" + pn + ": The new md5 checksum is " + md5chksum
Brad Bishop19323692019-04-05 15:28:33 -0400521 max_lines = int(d.getVar('QA_MAX_LICENSE_LINES') or 20)
522 if not license or license[-1] != '':
523 # Ensure that our license text ends with a line break
524 # (will be added with join() below).
525 license.append('')
526 remove = len(license) - max_lines
527 if remove > 0:
528 start = max_lines // 2
529 end = start + remove - 1
530 del license[start:end]
531 license.insert(start, '...')
532 msg = msg + "\n" + pn + ": Here is the selected license text:" + \
533 "\n" + \
534 "{:v^70}".format(" beginline=%d " % beginline if beginline else "") + \
535 "\n" + "\n".join(license) + \
536 "{:^^70}".format(" endline=%d " % endline if endline else "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500537 if beginline:
538 if endline:
539 srcfiledesc = "%s (lines %d through to %d)" % (srclicfile, beginline, endline)
540 else:
541 srcfiledesc = "%s (beginning on line %d)" % (srclicfile, beginline)
542 elif endline:
543 srcfiledesc = "%s (ending on line %d)" % (srclicfile, endline)
544 else:
545 srcfiledesc = srclicfile
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500546 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 -0500547
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500548 else:
549 msg = pn + ": LIC_FILES_CHKSUM is not specified for " + url
550 msg = msg + "\n" + pn + ": The md5 checksum is " + md5chksum
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800551 sane &= package_qa_handle_error("license-checksum", msg, d)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600552
553 if not sane:
554 bb.fatal("Fatal QA errors found, failing task.")
555}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500556
Brad Bishop19323692019-04-05 15:28:33 -0400557def qa_check_staged(path,d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500558 """
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500559 Check staged la and pc files for common problems like references to the work
560 directory.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500561
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500562 As this is run after every stage we should be able to find the one
563 responsible for the errors easily even if we look at every .pc and .la file.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500564 """
565
566 sane = True
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500567 tmpdir = d.getVar('TMPDIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500568 workdir = os.path.join(tmpdir, "work")
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500569 recipesysroot = d.getVar("RECIPE_SYSROOT")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500570
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500571 if bb.data.inherits_class("native", d) or bb.data.inherits_class("cross", d):
572 pkgconfigcheck = workdir
573 else:
574 pkgconfigcheck = tmpdir
575
Brad Bishop19323692019-04-05 15:28:33 -0400576 skip = (d.getVar('INSANE_SKIP') or "").split()
577 skip_la = False
578 if 'la' in skip:
579 bb.note("Recipe %s skipping qa checking: la" % d.getVar('PN'))
580 skip_la = True
581
582 skip_pkgconfig = False
583 if 'pkgconfig' in skip:
584 bb.note("Recipe %s skipping qa checking: pkgconfig" % d.getVar('PN'))
585 skip_pkgconfig = True
586
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500587 # find all .la and .pc files
588 # read the content
589 # and check for stuff that looks wrong
590 for root, dirs, files in os.walk(path):
591 for file in files:
592 path = os.path.join(root,file)
Brad Bishop19323692019-04-05 15:28:33 -0400593 if file.endswith(".la") and not skip_la:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500594 with open(path) as f:
595 file_content = f.read()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500596 file_content = file_content.replace(recipesysroot, "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500597 if workdir in file_content:
598 error_msg = "%s failed sanity test (workdir) in path %s" % (file,root)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800599 sane &= package_qa_handle_error("la", error_msg, d)
Brad Bishop19323692019-04-05 15:28:33 -0400600 elif file.endswith(".pc") and not skip_pkgconfig:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500601 with open(path) as f:
602 file_content = f.read()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500603 file_content = file_content.replace(recipesysroot, "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500604 if pkgconfigcheck in file_content:
605 error_msg = "%s failed sanity test (tmpdir) in path %s" % (file,root)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800606 sane &= package_qa_handle_error("pkgconfig", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500607
608 return sane
609
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500610# Run all package-wide warnfuncs and errorfuncs
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500611def package_qa_package(warnfuncs, errorfuncs, package, d):
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500612 warnings = {}
613 errors = {}
614
615 for func in warnfuncs:
616 func(package, d, warnings)
617 for func in errorfuncs:
618 func(package, d, errors)
619
620 for w in warnings:
621 package_qa_handle_error(w, warnings[w], d)
622 for e in errors:
623 package_qa_handle_error(e, errors[e], d)
624
625 return len(errors) == 0
626
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500627# Run all recipe-wide warnfuncs and errorfuncs
628def package_qa_recipe(warnfuncs, errorfuncs, pn, d):
629 warnings = {}
630 errors = {}
631
632 for func in warnfuncs:
633 func(pn, d, warnings)
634 for func in errorfuncs:
635 func(pn, d, errors)
636
637 for w in warnings:
638 package_qa_handle_error(w, warnings[w], d)
639 for e in errors:
640 package_qa_handle_error(e, errors[e], d)
641
642 return len(errors) == 0
643
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500644# Walk over all files in a directory and call func
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500645def package_qa_walk(warnfuncs, errorfuncs, package, d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500646 import oe.qa
647
648 #if this will throw an exception, then fix the dict above
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500649 target_os = d.getVar('TARGET_OS')
650 target_arch = d.getVar('TARGET_ARCH')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500651
652 warnings = {}
653 errors = {}
654 for path in pkgfiles[package]:
655 elf = oe.qa.ELFFile(path)
656 try:
657 elf.open()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500658 except (IOError, oe.qa.NotELFFileError):
659 # IOError can happen if the packaging control files disappear,
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500660 elf = None
661 for func in warnfuncs:
662 func(path, package, d, elf, warnings)
663 for func in errorfuncs:
664 func(path, package, d, elf, errors)
665
666 for w in warnings:
667 package_qa_handle_error(w, warnings[w], d)
668 for e in errors:
669 package_qa_handle_error(e, errors[e], d)
670
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500671def package_qa_check_rdepends(pkg, pkgdest, skip, taskdeps, packages, d):
672 # Don't do this check for kernel/module recipes, there aren't too many debug/development
673 # packages and you can get false positives e.g. on kernel-module-lirc-dev
674 if bb.data.inherits_class("kernel", d) or bb.data.inherits_class("module-base", d):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500675 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500676
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500677 if not "-dbg" in pkg and not "packagegroup-" in pkg and not "-image" in pkg:
678 localdata = bb.data.createCopy(d)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500679 localdata.setVar('OVERRIDES', localdata.getVar('OVERRIDES') + ':' + pkg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500680
681 # Now check the RDEPENDS
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500682 rdepends = bb.utils.explode_deps(localdata.getVar('RDEPENDS') or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500683
684 # Now do the sanity check!!!
685 if "build-deps" not in skip:
686 for rdepend in rdepends:
687 if "-dbg" in rdepend and "debug-deps" not in skip:
688 error_msg = "%s rdepends on %s" % (pkg,rdepend)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500689 package_qa_handle_error("debug-deps", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500690 if (not "-dev" in pkg and not "-staticdev" in pkg) and rdepend.endswith("-dev") and "dev-deps" not in skip:
691 error_msg = "%s rdepends on %s" % (pkg, rdepend)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500692 package_qa_handle_error("dev-deps", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500693 if rdepend not in packages:
694 rdep_data = oe.packagedata.read_subpkgdata(rdepend, d)
695 if rdep_data and 'PN' in rdep_data and rdep_data['PN'] in taskdeps:
696 continue
697 if not rdep_data or not 'PN' in rdep_data:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500698 pkgdata_dir = d.getVar("PKGDATA_DIR")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500699 try:
700 possibles = os.listdir("%s/runtime-rprovides/%s/" % (pkgdata_dir, rdepend))
701 except OSError:
702 possibles = []
703 for p in possibles:
704 rdep_data = oe.packagedata.read_subpkgdata(p, d)
705 if rdep_data and 'PN' in rdep_data and rdep_data['PN'] in taskdeps:
706 break
707 if rdep_data and 'PN' in rdep_data and rdep_data['PN'] in taskdeps:
708 continue
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500709 if rdep_data and 'PN' in rdep_data:
710 error_msg = "%s rdepends on %s, but it isn't a build dependency, missing %s in DEPENDS or PACKAGECONFIG?" % (pkg, rdepend, rdep_data['PN'])
711 else:
712 error_msg = "%s rdepends on %s, but it isn't a build dependency?" % (pkg, rdepend)
713 package_qa_handle_error("build-deps", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500714
715 if "file-rdeps" not in skip:
716 ignored_file_rdeps = set(['/bin/sh', '/usr/bin/env', 'rtld(GNU_HASH)'])
717 if bb.data.inherits_class('nativesdk', d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500718 ignored_file_rdeps |= set(['/bin/bash', '/usr/bin/perl', 'perl'])
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500719 # For Saving the FILERDEPENDS
720 filerdepends = {}
721 rdep_data = oe.packagedata.read_subpkgdata(pkg, d)
722 for key in rdep_data:
723 if key.startswith("FILERDEPENDS_"):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500724 for subkey in bb.utils.explode_deps(rdep_data[key]):
725 if subkey not in ignored_file_rdeps and \
726 not subkey.startswith('perl('):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500727 # We already know it starts with FILERDEPENDS_
728 filerdepends[subkey] = key[13:]
729
730 if filerdepends:
731 next = rdepends
732 done = rdepends[:]
733 # Find all the rdepends on the dependency chain
734 while next:
735 new = []
736 for rdep in next:
737 rdep_data = oe.packagedata.read_subpkgdata(rdep, d)
738 sub_rdeps = rdep_data.get("RDEPENDS_" + rdep)
739 if not sub_rdeps:
740 continue
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500741 for sub_rdep in bb.utils.explode_deps(sub_rdeps):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500742 if sub_rdep in done:
743 continue
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500744 if oe.packagedata.has_subpkgdata(sub_rdep, d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500745 # It's a new rdep
746 done.append(sub_rdep)
747 new.append(sub_rdep)
748 next = new
749
750 # Add the rprovides of itself
751 if pkg not in done:
752 done.insert(0, pkg)
753
754 # The python is not a package, but python-core provides it, so
755 # skip checking /usr/bin/python if python is in the rdeps, in
756 # case there is a RDEPENDS_pkg = "python" in the recipe.
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500757 for py in [ d.getVar('MLPREFIX') + "python", "python" ]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500758 if py in done:
759 filerdepends.pop("/usr/bin/python",None)
760 done.remove(py)
761 for rdep in done:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500762 # The file dependencies may contain package names, e.g.,
763 # perl
764 filerdepends.pop(rdep,None)
765
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500766 # For Saving the FILERPROVIDES, RPROVIDES and FILES_INFO
767 rdep_data = oe.packagedata.read_subpkgdata(rdep, d)
768 for key in rdep_data:
769 if key.startswith("FILERPROVIDES_") or key.startswith("RPROVIDES_"):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500770 for subkey in bb.utils.explode_deps(rdep_data[key]):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500771 filerdepends.pop(subkey,None)
772 # Add the files list to the rprovides
773 if key == "FILES_INFO":
774 # Use eval() to make it as a dict
775 for subkey in eval(rdep_data[key]):
776 filerdepends.pop(subkey,None)
777 if not filerdepends:
778 # Break if all the file rdepends are met
779 break
780 if filerdepends:
781 for key in filerdepends:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500782 error_msg = "%s contained in package %s requires %s, but no providers found in RDEPENDS_%s?" % \
783 (filerdepends[key].replace("_%s" % pkg, "").replace("@underscore@", "_"), pkg, key, pkg)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500784 package_qa_handle_error("file-rdeps", error_msg, d)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500785package_qa_check_rdepends[vardepsexclude] = "OVERRIDES"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500786
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500787def package_qa_check_deps(pkg, pkgdest, d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500788
789 localdata = bb.data.createCopy(d)
790 localdata.setVar('OVERRIDES', pkg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500791
792 def check_valid_deps(var):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500793 try:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500794 rvar = bb.utils.explode_dep_versions2(localdata.getVar(var) or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500795 except ValueError as e:
796 bb.fatal("%s_%s: %s" % (var, pkg, e))
797 for dep in rvar:
798 for v in rvar[dep]:
799 if v and not v.startswith(('< ', '= ', '> ', '<= ', '>=')):
800 error_msg = "%s_%s is invalid: %s (%s) only comparisons <, =, >, <=, and >= are allowed" % (var, pkg, dep, v)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500801 package_qa_handle_error("dep-cmp", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500802
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500803 check_valid_deps('RDEPENDS')
804 check_valid_deps('RRECOMMENDS')
805 check_valid_deps('RSUGGESTS')
806 check_valid_deps('RPROVIDES')
807 check_valid_deps('RREPLACES')
808 check_valid_deps('RCONFLICTS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500809
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500810QAPKGTEST[usrmerge] = "package_qa_check_usrmerge"
811def package_qa_check_usrmerge(pkg, d, messages):
812 pkgdest = d.getVar('PKGDEST')
813 pkg_dir = pkgdest + os.sep + pkg + os.sep
814 merged_dirs = ['bin', 'sbin', 'lib'] + d.getVar('MULTILIB_VARIANTS').split()
815 for f in merged_dirs:
816 if os.path.exists(pkg_dir + f) and not os.path.islink(pkg_dir + f):
817 msg = "%s package is not obeying usrmerge distro feature. /%s should be relocated to /usr." % (pkg, f)
818 package_qa_add_message(messages, "usrmerge", msg)
819 return False
820 return True
821
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500822QAPKGTEST[expanded-d] = "package_qa_check_expanded_d"
823def package_qa_check_expanded_d(package, d, messages):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500824 """
825 Check for the expanded D (${D}) value in pkg_* and FILES
826 variables, warn the user to use it correctly.
827 """
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500828 sane = True
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500829 expanded_d = d.getVar('D')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500830
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500831 for var in 'FILES','pkg_preinst', 'pkg_postinst', 'pkg_prerm', 'pkg_postrm':
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500832 bbvar = d.getVar(var + "_" + package) or ""
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500833 if expanded_d in bbvar:
834 if var == 'FILES':
835 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)
836 sane = False
837 else:
838 package_qa_add_message(messages, "expanded-d", "%s in %s recipe contains ${D}, it should be replaced by $D instead" % (var, package))
839 sane = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500840 return sane
841
842def package_qa_check_encoding(keys, encode, d):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600843 def check_encoding(key, enc):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500844 sane = True
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500845 value = d.getVar(key)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500846 if value:
847 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600848 s = value.encode(enc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500849 except UnicodeDecodeError as e:
850 error_msg = "%s has non %s characters" % (key,enc)
851 sane = False
852 package_qa_handle_error("invalid-chars", error_msg, d)
853 return sane
854
855 for key in keys:
856 sane = check_encoding(key, encode)
857 if not sane:
858 break
859
860HOST_USER_UID := "${@os.getuid()}"
861HOST_USER_GID := "${@os.getgid()}"
862
863QAPATHTEST[host-user-contaminated] = "package_qa_check_host_user"
864def package_qa_check_host_user(path, name, d, elf, messages):
865 """Check for paths outside of /home which are owned by the user running bitbake."""
866
867 if not os.path.lexists(path):
868 return
869
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500870 dest = d.getVar('PKGDEST')
871 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500872 home = os.path.join(dest, 'home')
873 if path == home or path.startswith(home + os.sep):
874 return
875
876 try:
877 stat = os.lstat(path)
878 except OSError as exc:
879 import errno
880 if exc.errno != errno.ENOENT:
881 raise
882 else:
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500883 rootfs_path = path[len(dest):]
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500884 check_uid = int(d.getVar('HOST_USER_UID'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500885 if stat.st_uid == check_uid:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500886 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, rootfs_path, check_uid))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500887 return False
888
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500889 check_gid = int(d.getVar('HOST_USER_GID'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500890 if stat.st_gid == check_gid:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500891 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, rootfs_path, check_gid))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500892 return False
893 return True
894
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500895
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500896# The PACKAGE FUNC to scan each package
897python do_package_qa () {
898 import subprocess
899 import oe.packagedata
900
901 bb.note("DO PACKAGE QA")
902
903 bb.build.exec_func("read_subpackage_metadata", d)
904
905 # Check non UTF-8 characters on recipe's metadata
906 package_qa_check_encoding(['DESCRIPTION', 'SUMMARY', 'LICENSE', 'SECTION'], 'utf-8', d)
907
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500908 logdir = d.getVar('T')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500909 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500910
911 # Check the compile log for host contamination
912 compilelog = os.path.join(logdir,"log.do_compile")
913
914 if os.path.exists(compilelog):
915 statement = "grep -e 'CROSS COMPILE Badness:' -e 'is unsafe for cross-compilation' %s > /dev/null" % compilelog
916 if subprocess.call(statement, shell=True) == 0:
917 msg = "%s: The compile log indicates that host include and/or library paths were used.\n \
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500918 Please check the log '%s' for more information." % (pn, compilelog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500919 package_qa_handle_error("compile-host-path", msg, d)
920
921 # Check the install log for host contamination
922 installlog = os.path.join(logdir,"log.do_install")
923
924 if os.path.exists(installlog):
925 statement = "grep -e 'CROSS COMPILE Badness:' -e 'is unsafe for cross-compilation' %s > /dev/null" % installlog
926 if subprocess.call(statement, shell=True) == 0:
927 msg = "%s: The install log indicates that host include and/or library paths were used.\n \
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500928 Please check the log '%s' for more information." % (pn, installlog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500929 package_qa_handle_error("install-host-path", msg, d)
930
931 # Scan the packages...
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500932 pkgdest = d.getVar('PKGDEST')
933 packages = set((d.getVar('PACKAGES') or '').split())
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500934
935 cpath = oe.cachedpath.CachedPath()
936 global pkgfiles
937 pkgfiles = {}
938 for pkg in packages:
939 pkgfiles[pkg] = []
940 for walkroot, dirs, files in cpath.walk(pkgdest + "/" + pkg):
941 for file in files:
942 pkgfiles[pkg].append(walkroot + os.sep + file)
943
944 # no packages should be scanned
945 if not packages:
946 return
947
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500948 import re
949 # The package name matches the [a-z0-9.+-]+ regular expression
Brad Bishop977dc1a2019-02-06 16:01:43 -0500950 pkgname_pattern = re.compile(r"^[a-z0-9.+-]+$")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500951
952 taskdepdata = d.getVar("BB_TASKDEPDATA", False)
953 taskdeps = set()
954 for dep in taskdepdata:
955 taskdeps.add(taskdepdata[dep][0])
956
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500957 def parse_test_matrix(matrix_name):
958 testmatrix = d.getVarFlags(matrix_name) or {}
959 g = globals()
960 warnchecks = []
961 for w in (d.getVar("WARN_QA") or "").split():
962 if w in skip:
963 continue
964 if w in testmatrix and testmatrix[w] in g:
965 warnchecks.append(g[testmatrix[w]])
966
967 errorchecks = []
968 for e in (d.getVar("ERROR_QA") or "").split():
969 if e in skip:
970 continue
971 if e in testmatrix and testmatrix[e] in g:
972 errorchecks.append(g[testmatrix[e]])
973 return warnchecks, errorchecks
974
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500975 for package in packages:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500976 skip = set((d.getVar('INSANE_SKIP') or "").split() +
977 (d.getVar('INSANE_SKIP_' + package) or "").split())
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500978 if skip:
979 bb.note("Package %s skipping QA tests: %s" % (package, str(skip)))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500980
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500981 bb.note("Checking Package: %s" % package)
982 # Check package name
983 if not pkgname_pattern.match(package):
984 package_qa_handle_error("pkgname",
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500985 "%s doesn't match the [a-z0-9.+-]+ regex" % package, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500986
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500987 warn_checks, error_checks = parse_test_matrix("QAPATHTEST")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500988 package_qa_walk(warn_checks, error_checks, package, d)
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500989
990 warn_checks, error_checks = parse_test_matrix("QAPKGTEST")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500991 package_qa_package(warn_checks, error_checks, package, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500992
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500993 package_qa_check_rdepends(package, pkgdest, skip, taskdeps, packages, d)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500994 package_qa_check_deps(package, pkgdest, d)
995
996 warn_checks, error_checks = parse_test_matrix("QARECIPETEST")
997 package_qa_recipe(warn_checks, error_checks, pn, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500998
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500999 if 'libdir' in d.getVar("ALL_QA").split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001000 package_qa_check_libdir(d)
1001
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001002 qa_sane = d.getVar("QA_SANE")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001003 if not qa_sane:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001004 bb.fatal("QA run found fatal errors. Please consider fixing them.")
1005 bb.note("DONE with PACKAGE QA")
1006}
1007
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001008# binutils is used for most checks, so need to set as dependency
1009# POPULATESYSROOTDEPS is defined in staging class.
1010do_package_qa[depends] += "${POPULATESYSROOTDEPS}"
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001011do_package_qa[vardepsexclude] = "BB_TASKDEPDATA"
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001012do_package_qa[rdeptask] = "do_packagedata"
1013addtask do_package_qa after do_packagedata do_package before do_build
1014
Brad Bishop19323692019-04-05 15:28:33 -04001015# Add the package specific INSANE_SKIPs to the sstate dependencies
1016python() {
1017 pkgs = (d.getVar('PACKAGES') or '').split()
1018 for pkg in pkgs:
1019 d.appendVarFlag("do_package_qa", "vardeps", " INSANE_SKIP_{}".format(pkg))
1020}
1021
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001022SSTATETASKS += "do_package_qa"
1023do_package_qa[sstate-inputdirs] = ""
1024do_package_qa[sstate-outputdirs] = ""
1025python do_package_qa_setscene () {
1026 sstate_setscene(d)
1027}
1028addtask do_package_qa_setscene
1029
1030python do_qa_staging() {
1031 bb.note("QA checking staging")
Brad Bishop19323692019-04-05 15:28:33 -04001032 if not qa_check_staged(d.expand('${SYSROOT_DESTDIR}${libdir}'), d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001033 bb.fatal("QA staging was broken by the package built above")
1034}
1035
Brad Bishopd89cb5f2019-04-10 09:02:41 -04001036python do_qa_patch() {
1037 import subprocess
1038
1039 ###########################################################################
1040 # Check patch.log for fuzz warnings
1041 #
1042 # Further information on why we check for patch fuzz warnings:
1043 # http://lists.openembedded.org/pipermail/openembedded-core/2018-March/148675.html
1044 # https://bugzilla.yoctoproject.org/show_bug.cgi?id=10450
1045 ###########################################################################
1046
1047 logdir = d.getVar('T')
1048 patchlog = os.path.join(logdir,"log.do_patch")
1049
1050 if os.path.exists(patchlog):
1051 fuzzheader = '--- Patch fuzz start ---'
1052 fuzzfooter = '--- Patch fuzz end ---'
1053 statement = "grep -e '%s' %s > /dev/null" % (fuzzheader, patchlog)
1054 if subprocess.call(statement, shell=True) == 0:
1055 msg = "Fuzz detected:\n\n"
1056 fuzzmsg = ""
1057 inFuzzInfo = False
1058 f = open(patchlog, "r")
1059 for line in f:
1060 if fuzzheader in line:
1061 inFuzzInfo = True
1062 fuzzmsg = ""
1063 elif fuzzfooter in line:
1064 fuzzmsg = fuzzmsg.replace('\n\n', '\n')
1065 msg += fuzzmsg
1066 msg += "\n"
1067 inFuzzInfo = False
1068 elif inFuzzInfo and not 'Now at patch' in line:
1069 fuzzmsg += line
1070 f.close()
1071 msg += "The context lines in the patches can be updated with devtool:\n"
1072 msg += "\n"
1073 msg += " devtool modify %s\n" % d.getVar('PN')
1074 msg += " devtool finish --force-patch-refresh %s <layer_path>\n\n" % d.getVar('PN')
1075 msg += "Don't forget to review changes done by devtool!\n"
1076 if 'patch-fuzz' in d.getVar('ERROR_QA'):
1077 bb.error(msg)
1078 elif 'patch-fuzz' in d.getVar('WARN_QA'):
1079 bb.warn(msg)
1080 msg = "Patch log indicates that patches do not apply cleanly."
1081 package_qa_handle_error("patch-fuzz", msg, d)
1082}
1083
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001084python do_qa_configure() {
1085 import subprocess
1086
1087 ###########################################################################
1088 # Check config.log for cross compile issues
1089 ###########################################################################
1090
1091 configs = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001092 workdir = d.getVar('WORKDIR')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001093
Brad Bishop19323692019-04-05 15:28:33 -04001094 skip = (d.getVar('INSANE_SKIP') or "").split()
1095 skip_configure_unsafe = False
1096 if 'configure-unsafe' in skip:
1097 bb.note("Recipe %s skipping qa checking: configure-unsafe" % d.getVar('PN'))
1098 skip_configure_unsafe = True
1099
1100 if bb.data.inherits_class('autotools', d) and not skip_configure_unsafe:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001101 bb.note("Checking autotools environment for common misconfiguration")
1102 for root, dirs, files in os.walk(workdir):
1103 statement = "grep -q -F -e 'CROSS COMPILE Badness:' -e 'is unsafe for cross-compilation' %s" % \
1104 os.path.join(root,"config.log")
1105 if "config.log" in files:
1106 if subprocess.call(statement, shell=True) == 0:
Brad Bishop19323692019-04-05 15:28:33 -04001107 error_msg = """This autoconf log indicates errors, it looked at host include and/or library paths while determining system capabilities.
1108Rerun configure task after fixing this."""
1109 package_qa_handle_error("configure-unsafe", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001110
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001111 if "configure.ac" in files:
1112 configs.append(os.path.join(root,"configure.ac"))
1113 if "configure.in" in files:
1114 configs.append(os.path.join(root, "configure.in"))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001115
1116 ###########################################################################
1117 # Check gettext configuration and dependencies are correct
1118 ###########################################################################
1119
Brad Bishop19323692019-04-05 15:28:33 -04001120 skip_configure_gettext = False
1121 if 'configure-gettext' in skip:
1122 bb.note("Recipe %s skipping qa checking: configure-gettext" % d.getVar('PN'))
1123 skip_configure_gettext = True
1124
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001125 cnf = d.getVar('EXTRA_OECONF') or ""
Brad Bishop19323692019-04-05 15:28:33 -04001126 if not ("gettext" in d.getVar('P') or "gcc-runtime" in d.getVar('P') or \
1127 "--disable-nls" in cnf or skip_configure_gettext):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001128 ml = d.getVar("MLPREFIX") or ""
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001129 if bb.data.inherits_class('cross-canadian', d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001130 gt = "nativesdk-gettext"
1131 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001132 gt = "gettext-native"
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001133 deps = bb.utils.explode_deps(d.getVar('DEPENDS') or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001134 if gt not in deps:
1135 for config in configs:
1136 gnu = "grep \"^[[:space:]]*AM_GNU_GETTEXT\" %s >/dev/null" % config
1137 if subprocess.call(gnu, shell=True) == 0:
Brad Bishopd89cb5f2019-04-10 09:02:41 -04001138 error_msg = "AM_GNU_GETTEXT used but no inherit gettext"
Brad Bishop19323692019-04-05 15:28:33 -04001139 package_qa_handle_error("configure-gettext", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001140
1141 ###########################################################################
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001142 # Check unrecognised configure options (with a white list)
1143 ###########################################################################
1144 if bb.data.inherits_class("autotools", d):
1145 bb.note("Checking configure output for unrecognised options")
1146 try:
1147 flag = "WARNING: unrecognized options:"
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001148 log = os.path.join(d.getVar('B'), 'config.log')
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001149 output = subprocess.check_output(['grep', '-F', flag, log]).decode("utf-8").replace(', ', ' ')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001150 options = set()
1151 for line in output.splitlines():
1152 options |= set(line.partition(flag)[2].split())
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001153 whitelist = set(d.getVar("UNKNOWN_CONFIGURE_WHITELIST").split())
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001154 options -= whitelist
1155 if options:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001156 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001157 error_msg = pn + ": configure was passed unrecognised options: " + " ".join(options)
1158 package_qa_handle_error("unknown-configure-option", error_msg, d)
1159 except subprocess.CalledProcessError:
1160 pass
1161
1162 # Check invalid PACKAGECONFIG
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001163 pkgconfig = (d.getVar("PACKAGECONFIG") or "").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001164 if pkgconfig:
1165 pkgconfigflags = d.getVarFlags("PACKAGECONFIG") or {}
1166 for pconfig in pkgconfig:
1167 if pconfig not in pkgconfigflags:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001168 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001169 error_msg = "%s: invalid PACKAGECONFIG: %s" % (pn, pconfig)
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001170 package_qa_handle_error("invalid-packageconfig", error_msg, d)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001171
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001172 qa_sane = d.getVar("QA_SANE")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001173 if not qa_sane:
1174 bb.fatal("Fatal QA errors found, failing task.")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001175}
1176
1177python do_qa_unpack() {
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001178 src_uri = d.getVar('SRC_URI')
1179 s_dir = d.getVar('S')
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001180 if src_uri and not os.path.exists(s_dir):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001181 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 -05001182}
1183
1184# The Staging Func, to check all staging
1185#addtask qa_staging after do_populate_sysroot before do_build
1186do_populate_sysroot[postfuncs] += "do_qa_staging "
1187
Brad Bishopd89cb5f2019-04-10 09:02:41 -04001188# Check for patch fuzz
1189do_patch[postfuncs] += "do_qa_patch "
1190
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001191# Check broken config.log files, for packages requiring Gettext which
1192# don't have it in DEPENDS.
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001193#addtask qa_configure after do_configure before do_compile
1194do_configure[postfuncs] += "do_qa_configure "
1195
1196# Check does S exist.
1197do_unpack[postfuncs] += "do_qa_unpack"
1198
1199python () {
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001200 import re
1201
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001202 tests = d.getVar('ALL_QA').split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001203 if "desktop" in tests:
1204 d.appendVar("PACKAGE_DEPENDS", " desktop-file-utils-native")
1205
1206 ###########################################################################
1207 # Check various variables
1208 ###########################################################################
1209
1210 # Checking ${FILESEXTRAPATHS}
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001211 extrapaths = (d.getVar("FILESEXTRAPATHS") or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001212 if '__default' not in extrapaths.split(":"):
1213 msg = "FILESEXTRAPATHS-variable, must always use _prepend (or _append)\n"
1214 msg += "type of assignment, and don't forget the colon.\n"
1215 msg += "Please assign it with the format of:\n"
1216 msg += " FILESEXTRAPATHS_append := \":${THISDIR}/Your_Files_Path\" or\n"
1217 msg += " FILESEXTRAPATHS_prepend := \"${THISDIR}/Your_Files_Path:\"\n"
1218 msg += "in your bbappend file\n\n"
1219 msg += "Your incorrect assignment is:\n"
1220 msg += "%s\n" % extrapaths
1221 bb.warn(msg)
1222
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001223 overrides = d.getVar('OVERRIDES').split(':')
1224 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001225 if pn in overrides:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001226 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 -05001227 package_qa_handle_error("pn-overrides", msg, d)
Brad Bishop977dc1a2019-02-06 16:01:43 -05001228 prog = re.compile(r'[A-Z]')
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001229 if prog.search(pn):
1230 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 -05001231
1232 issues = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001233 if (d.getVar('PACKAGES') or "").split():
1234 for dep in (d.getVar('QADEPENDS') or "").split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001235 d.appendVarFlag('do_package_qa', 'depends', " %s:do_populate_sysroot" % dep)
1236 for var in 'RDEPENDS', 'RRECOMMENDS', 'RSUGGESTS', 'RCONFLICTS', 'RPROVIDES', 'RREPLACES', 'FILES', 'pkg_preinst', 'pkg_postinst', 'pkg_prerm', 'pkg_postrm', 'ALLOW_EMPTY':
1237 if d.getVar(var, False):
1238 issues.append(var)
1239
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001240 fakeroot_tests = d.getVar('FAKEROOT_QA').split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001241 if set(tests) & set(fakeroot_tests):
1242 d.setVarFlag('do_package_qa', 'fakeroot', '1')
1243 d.appendVarFlag('do_package_qa', 'depends', ' virtual/fakeroot-native:do_populate_sysroot')
1244 else:
1245 d.setVarFlag('do_package_qa', 'rdeptask', '')
1246 for i in issues:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001247 package_qa_handle_error("pkgvarcheck", "%s: Variable %s is set as not being package specific, please fix this." % (d.getVar("FILE"), i), d)
1248 qa_sane = d.getVar("QA_SANE")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001249 if not qa_sane:
1250 bb.fatal("Fatal QA errors found, failing task.")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001251}