blob: 4644221bc6b0b1eb401473eefbb85e76b2e2c00a [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 Bishopd7bf8c12018-02-25 22:55:05 -050030 invalid-packageconfig host-user-contaminated uppercase-pn \
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 Bishop6e60e8b2018-02-01 10:27:11 -050036 license-checksum dev-elf file-rdeps \
Patrick Williamsc124f4f2015-09-15 14:41:29 -050037 "
Brad Bishopd7bf8c12018-02-25 22:55:05 -050038# Add usrmerge QA check based on distro feature
39ERROR_QA_append = "${@bb.utils.contains('DISTRO_FEATURES', 'usrmerge', ' usrmerge', '', d)}"
40
Patrick Williamsc124f4f2015-09-15 14:41:29 -050041FAKEROOT_QA = "host-user-contaminated"
42FAKEROOT_QA[doc] = "QA tests which need to run under fakeroot. If any \
43enabled tests are listed here, the do_package_qa task will run under fakeroot."
44
45ALL_QA = "${WARN_QA} ${ERROR_QA}"
46
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050047UNKNOWN_CONFIGURE_WHITELIST ?= "--enable-nls --disable-nls --disable-silent-rules --disable-dependency-tracking --with-libtool-sysroot --disable-static"
Patrick Williamsc124f4f2015-09-15 14:41:29 -050048
Patrick Williamsc0f7c042017-02-23 20:41:17 -060049def package_qa_clean_path(path, d, pkg=None):
50 """
51 Remove redundant paths from the path for display. If pkg isn't set then
52 TMPDIR is stripped, otherwise PKGDEST/pkg is stripped.
53 """
54 if pkg:
Brad Bishop6e60e8b2018-02-01 10:27:11 -050055 path = path.replace(os.path.join(d.getVar("PKGDEST"), pkg), "/")
56 return path.replace(d.getVar("TMPDIR"), "/").replace("//", "/")
Patrick Williamsc124f4f2015-09-15 14:41:29 -050057
58def package_qa_write_error(type, error, d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -050059 logfile = d.getVar('QA_LOGFILE')
Patrick Williamsc124f4f2015-09-15 14:41:29 -050060 if logfile:
Brad Bishop6e60e8b2018-02-01 10:27:11 -050061 p = d.getVar('P')
Patrick Williamsc0f7c042017-02-23 20:41:17 -060062 with open(logfile, "a+") as f:
63 f.write("%s: %s [%s]\n" % (p, error, type))
Patrick Williamsc124f4f2015-09-15 14:41:29 -050064
65def package_qa_handle_error(error_class, error_msg, d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -050066 if error_class in (d.getVar("ERROR_QA") or "").split():
Brad Bishopd7bf8c12018-02-25 22:55:05 -050067 package_qa_write_error(error_class, error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050068 bb.error("QA Issue: %s [%s]" % (error_msg, error_class))
69 d.setVar("QA_SANE", False)
70 return False
Brad Bishop6e60e8b2018-02-01 10:27:11 -050071 elif error_class in (d.getVar("WARN_QA") or "").split():
Brad Bishopd7bf8c12018-02-25 22:55:05 -050072 package_qa_write_error(error_class, error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050073 bb.warn("QA Issue: %s [%s]" % (error_msg, error_class))
74 else:
75 bb.note("QA Issue: %s [%s]" % (error_msg, error_class))
76 return True
77
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050078def package_qa_add_message(messages, section, new_msg):
79 if section not in messages:
80 messages[section] = new_msg
81 else:
82 messages[section] = messages[section] + "\n" + new_msg
83
Patrick Williamsc124f4f2015-09-15 14:41:29 -050084QAPATHTEST[libexec] = "package_qa_check_libexec"
85def package_qa_check_libexec(path,name, d, elf, messages):
86
87 # Skip the case where the default is explicitly /usr/libexec
Brad Bishop6e60e8b2018-02-01 10:27:11 -050088 libexec = d.getVar('libexecdir')
Patrick Williamsc124f4f2015-09-15 14:41:29 -050089 if libexec == "/usr/libexec":
90 return True
91
92 if 'libexec' in path.split(os.path.sep):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050093 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 -050094 return False
95
96 return True
97
98QAPATHTEST[rpaths] = "package_qa_check_rpath"
99def package_qa_check_rpath(file,name, d, elf, messages):
100 """
101 Check for dangerous RPATHs
102 """
103 if not elf:
104 return
105
106 if os.path.islink(file):
107 return
108
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500109 bad_dirs = [d.getVar('BASE_WORKDIR'), d.getVar('STAGING_DIR_TARGET')]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500110
111 phdrs = elf.run_objdump("-p", d)
112
113 import re
114 rpath_re = re.compile("\s+RPATH\s+(.*)")
115 for line in phdrs.split("\n"):
116 m = rpath_re.match(line)
117 if m:
118 rpath = m.group(1)
119 for dir in bad_dirs:
120 if dir in rpath:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500121 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 -0500122
123QAPATHTEST[useless-rpaths] = "package_qa_check_useless_rpaths"
124def package_qa_check_useless_rpaths(file, name, d, elf, messages):
125 """
126 Check for RPATHs that are useless but not dangerous
127 """
128 def rpath_eq(a, b):
129 return os.path.normpath(a) == os.path.normpath(b)
130
131 if not elf:
132 return
133
134 if os.path.islink(file):
135 return
136
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500137 libdir = d.getVar("libdir")
138 base_libdir = d.getVar("base_libdir")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500139
140 phdrs = elf.run_objdump("-p", d)
141
142 import re
143 rpath_re = re.compile("\s+RPATH\s+(.*)")
144 for line in phdrs.split("\n"):
145 m = rpath_re.match(line)
146 if m:
147 rpath = m.group(1)
148 if rpath_eq(rpath, libdir) or rpath_eq(rpath, base_libdir):
149 # The dynamic linker searches both these places anyway. There is no point in
150 # looking there again.
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500151 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 -0500152
153QAPATHTEST[dev-so] = "package_qa_check_dev"
154def package_qa_check_dev(path, name, d, elf, messages):
155 """
156 Check for ".so" library symlinks in non-dev packages
157 """
158
159 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 -0500160 package_qa_add_message(messages, "dev-so", "non -dev/-dbg/nativesdk- package contains symlink .so: %s path '%s'" % \
161 (name, package_qa_clean_path(path,d)))
162
163QAPATHTEST[dev-elf] = "package_qa_check_dev_elf"
164def package_qa_check_dev_elf(path, name, d, elf, messages):
165 """
166 Check that -dev doesn't contain real shared libraries. The test has to
167 check that the file is not a link and is an ELF object as some recipes
168 install link-time .so files that are linker scripts.
169 """
170 if name.endswith("-dev") and path.endswith(".so") and not os.path.islink(path) and elf:
171 package_qa_add_message(messages, "dev-elf", "-dev package contains non-symlink .so: %s path '%s'" % \
172 (name, package_qa_clean_path(path,d)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500173
174QAPATHTEST[staticdev] = "package_qa_check_staticdev"
175def package_qa_check_staticdev(path, name, d, elf, messages):
176 """
177 Check for ".a" library in non-staticdev packages
178 There are a number of exceptions to this rule, -pic packages can contain
179 static libraries, the _nonshared.a belong with their -dev packages and
180 libgcc.a, libgcov.a will be skipped in their packages
181 """
182
183 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 -0500184 package_qa_add_message(messages, "staticdev", "non -staticdev package contains static .a library: %s path '%s'" % \
185 (name, package_qa_clean_path(path,d)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500186
187def package_qa_check_libdir(d):
188 """
189 Check for wrong library installation paths. For instance, catch
190 recipes installing /lib/bar.so when ${base_libdir}="lib32" or
191 installing in /usr/lib64 when ${libdir}="/usr/lib"
192 """
193 import re
194
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500195 pkgdest = d.getVar('PKGDEST')
196 base_libdir = d.getVar("base_libdir") + os.sep
197 libdir = d.getVar("libdir") + os.sep
198 libexecdir = d.getVar("libexecdir") + os.sep
199 exec_prefix = d.getVar("exec_prefix") + os.sep
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500200
201 messages = []
202
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500203 # The re's are purposely fuzzy, as some there are some .so.x.y.z files
204 # that don't follow the standard naming convention. It checks later
205 # that they are actual ELF files
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500206 lib_re = re.compile("^/lib.+\.so(\..+)?$")
207 exec_re = re.compile("^%s.*/lib.+\.so(\..+)?$" % exec_prefix)
208
209 for root, dirs, files in os.walk(pkgdest):
210 if root == pkgdest:
211 # Skip subdirectories for any packages with libdir in INSANE_SKIP
212 skippackages = []
213 for package in dirs:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500214 if 'libdir' in (d.getVar('INSANE_SKIP_' + package) or "").split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500215 bb.note("Package %s skipping libdir QA test" % (package))
216 skippackages.append(package)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500217 elif d.getVar('PACKAGE_DEBUG_SPLIT_STYLE') == 'debug-file-directory' and package.endswith("-dbg"):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500218 bb.note("Package %s skipping libdir QA test for PACKAGE_DEBUG_SPLIT_STYLE equals debug-file-directory" % (package))
219 skippackages.append(package)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500220 for package in skippackages:
221 dirs.remove(package)
222 for file in files:
223 full_path = os.path.join(root, file)
224 rel_path = os.path.relpath(full_path, pkgdest)
225 if os.sep in rel_path:
226 package, rel_path = rel_path.split(os.sep, 1)
227 rel_path = os.sep + rel_path
228 if lib_re.match(rel_path):
229 if base_libdir not in rel_path:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500230 # make sure it's an actual ELF file
231 elf = oe.qa.ELFFile(full_path)
232 try:
233 elf.open()
234 messages.append("%s: found library in wrong location: %s" % (package, rel_path))
235 except (oe.qa.NotELFFileError):
236 pass
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500237 if exec_re.match(rel_path):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500238 if libdir not in rel_path and libexecdir not in rel_path:
239 # make sure it's an actual ELF file
240 elf = oe.qa.ELFFile(full_path)
241 try:
242 elf.open()
243 messages.append("%s: found library in wrong location: %s" % (package, rel_path))
244 except (oe.qa.NotELFFileError):
245 pass
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500246
247 if messages:
248 package_qa_handle_error("libdir", "\n".join(messages), d)
249
250QAPATHTEST[debug-files] = "package_qa_check_dbg"
251def package_qa_check_dbg(path, name, d, elf, messages):
252 """
253 Check for ".debug" files or directories outside of the dbg package
254 """
255
256 if not "-dbg" in name and not "-ptest" in name:
257 if '.debug' in path.split(os.path.sep):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500258 package_qa_add_message(messages, "debug-files", "non debug package contains .debug directory: %s path %s" % \
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500259 (name, package_qa_clean_path(path,d)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500260
261QAPATHTEST[perms] = "package_qa_check_perm"
262def package_qa_check_perm(path,name,d, elf, messages):
263 """
264 Check the permission of files
265 """
266 return
267
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500268QAPATHTEST[arch] = "package_qa_check_arch"
269def package_qa_check_arch(path,name,d, elf, messages):
270 """
271 Check if archs are compatible
272 """
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800273 import re, oe.elf
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600274
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500275 if not elf:
276 return
277
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500278 target_os = d.getVar('TARGET_OS')
279 target_arch = d.getVar('TARGET_ARCH')
280 provides = d.getVar('PROVIDES')
281 bpn = d.getVar('BPN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500282
283 if target_arch == "allarch":
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500284 pn = d.getVar('PN')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500285 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 -0500286 return
287
288 # FIXME: Cross package confuse this check, so just skip them
289 for s in ['cross', 'nativesdk', 'cross-canadian']:
290 if bb.data.inherits_class(s, d):
291 return
292
293 # avoid following links to /usr/bin (e.g. on udev builds)
294 # we will check the files pointed to anyway...
295 if os.path.islink(path):
296 return
297
298 #if this will throw an exception, then fix the dict above
299 (machine, osabi, abiversion, littleendian, bits) \
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800300 = oe.elf.machine_dict(d)[target_os][target_arch]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500301
302 # Check the architecture and endiannes of the binary
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600303 is_32 = (("virtual/kernel" in provides) or bb.data.inherits_class("module", d)) and \
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800304 (target_os == "linux-gnux32" or target_os == "linux-muslx32" or \
305 target_os == "linux-gnu_ilp32" or re.match('mips64.*32', d.getVar('DEFAULTTUNE')))
306 is_bpf = (oe.qa.elf_machine_to_string(elf.machine()) == "BPF")
307 if not ((machine == elf.machine()) or is_32 or is_bpf):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600308 package_qa_add_message(messages, "arch", "Architecture did not match (%s, expected %s) on %s" % \
309 (oe.qa.elf_machine_to_string(elf.machine()), oe.qa.elf_machine_to_string(machine), package_qa_clean_path(path,d)))
310 elif not ((bits == elf.abiSize()) or is_32):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500311 package_qa_add_message(messages, "arch", "Bit size did not match (%d to %d) %s on %s" % \
312 (bits, elf.abiSize(), bpn, package_qa_clean_path(path,d)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500313 elif not littleendian == elf.isLittleEndian():
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500314 package_qa_add_message(messages, "arch", "Endiannes did not match (%d to %d) on %s" % \
315 (littleendian, elf.isLittleEndian(), package_qa_clean_path(path,d)))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500316
317QAPATHTEST[desktop] = "package_qa_check_desktop"
318def package_qa_check_desktop(path, name, d, elf, messages):
319 """
320 Run all desktop files through desktop-file-validate.
321 """
322 if path.endswith(".desktop"):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500323 desktop_file_validate = os.path.join(d.getVar('STAGING_BINDIR_NATIVE'),'desktop-file-validate')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500324 output = os.popen("%s %s" % (desktop_file_validate, path))
325 # This only produces output on errors
326 for l in output:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500327 package_qa_add_message(messages, "desktop", "Desktop file issue: " + l.strip())
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500328
329QAPATHTEST[textrel] = "package_qa_textrel"
330def package_qa_textrel(path, name, d, elf, messages):
331 """
332 Check if the binary contains relocations in .text
333 """
334
335 if not elf:
336 return
337
338 if os.path.islink(path):
339 return
340
341 phdrs = elf.run_objdump("-p", d)
342 sane = True
343
344 import re
345 textrel_re = re.compile("\s+TEXTREL\s+")
346 for line in phdrs.split("\n"):
347 if textrel_re.match(line):
348 sane = False
349
350 if not sane:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500351 package_qa_add_message(messages, "textrel", "ELF binary '%s' has relocations in .text" % path)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500352
353QAPATHTEST[ldflags] = "package_qa_hash_style"
354def package_qa_hash_style(path, name, d, elf, messages):
355 """
356 Check if the binary has the right hash style...
357 """
358
359 if not elf:
360 return
361
362 if os.path.islink(path):
363 return
364
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500365 gnu_hash = "--hash-style=gnu" in d.getVar('LDFLAGS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500366 if not gnu_hash:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500367 gnu_hash = "--hash-style=both" in d.getVar('LDFLAGS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500368 if not gnu_hash:
369 return
370
371 sane = False
372 has_syms = False
373
374 phdrs = elf.run_objdump("-p", d)
375
376 # If this binary has symbols, we expect it to have GNU_HASH too.
377 for line in phdrs.split("\n"):
378 if "SYMTAB" in line:
379 has_syms = True
380 if "GNU_HASH" in line:
381 sane = True
382 if "[mips32]" in line or "[mips64]" in line:
383 sane = True
384
385 if has_syms and not sane:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500386 package_qa_add_message(messages, "ldflags", "No GNU_HASH in the elf binary: '%s'" % path)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500387
388
389QAPATHTEST[buildpaths] = "package_qa_check_buildpaths"
390def package_qa_check_buildpaths(path, name, d, elf, messages):
391 """
392 Check for build paths inside target files and error if not found in the whitelist
393 """
394 # Ignore .debug files, not interesting
395 if path.find(".debug") != -1:
396 return
397
398 # Ignore symlinks
399 if os.path.islink(path):
400 return
401
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500402 # Ignore ipk and deb's CONTROL dir
403 if path.find(name + "/CONTROL/") != -1 or path.find(name + "/DEBIAN/") != -1:
404 return
405
Brad Bishopd5ae7d92018-06-14 09:52:03 -0700406 tmpdir = bytes(d.getVar('TMPDIR'), encoding="utf-8")
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500407 with open(path, 'rb') as f:
Brad Bishopd5ae7d92018-06-14 09:52:03 -0700408 file_content = f.read()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500409 if tmpdir in file_content:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500410 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 -0500411
412
413QAPATHTEST[xorg-driver-abi] = "package_qa_check_xorg_driver_abi"
414def package_qa_check_xorg_driver_abi(path, name, d, elf, messages):
415 """
416 Check that all packages containing Xorg drivers have ABI dependencies
417 """
418
419 # Skip dev, dbg or nativesdk packages
420 if name.endswith("-dev") or name.endswith("-dbg") or name.startswith("nativesdk-"):
421 return
422
423 driverdir = d.expand("${libdir}/xorg/modules/drivers/")
424 if driverdir in path and path.endswith(".so"):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500425 mlprefix = d.getVar('MLPREFIX') or ''
426 for rdep in bb.utils.explode_deps(d.getVar('RDEPENDS_' + name) or ""):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500427 if rdep.startswith("%sxorg-abi-" % mlprefix):
428 return
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500429 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 -0500430
431QAPATHTEST[infodir] = "package_qa_check_infodir"
432def package_qa_check_infodir(path, name, d, elf, messages):
433 """
434 Check that /usr/share/info/dir isn't shipped in a particular package
435 """
436 infodir = d.expand("${infodir}/dir")
437
438 if infodir in path:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500439 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 -0500440
441QAPATHTEST[symlink-to-sysroot] = "package_qa_check_symlink_to_sysroot"
442def package_qa_check_symlink_to_sysroot(path, name, d, elf, messages):
443 """
444 Check that the package doesn't contain any absolute symlinks to the sysroot.
445 """
446 if os.path.islink(path):
447 target = os.readlink(path)
448 if os.path.isabs(target):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500449 tmpdir = d.getVar('TMPDIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500450 if target.startswith(tmpdir):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500451 trimmed = path.replace(os.path.join (d.getVar("PKGDEST"), name), "")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500452 package_qa_add_message(messages, "symlink-to-sysroot", "Symlink %s in %s points to TMPDIR" % (trimmed, name))
453
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600454# Check license variables
455do_populate_lic[postfuncs] += "populate_lic_qa_checksum"
456python populate_lic_qa_checksum() {
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500457 """
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600458 Check for changes in the license files.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500459 """
460 import tempfile
461 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 Bishop6e60e8b2018-02-01 10:27:11 -0500498 with open(srclicfile, 'rb') as f:
499 license = f.read()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500500 else:
501 fi = open(srclicfile, 'rb')
502 fo = tempfile.NamedTemporaryFile(mode='wb', prefix='poky.', suffix='.tmp', delete=False)
503 tmplicfile = fo.name;
504 lineno = 0
505 linesout = 0
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500506 license = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500507 for line in fi:
508 lineno += 1
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600509 if (lineno >= beginline):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500510 if ((lineno <= endline) or not endline):
511 fo.write(line)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500512 license.append(line)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500513 linesout += 1
514 else:
515 break
516 fo.flush()
517 fo.close()
518 fi.close()
519 md5chksum = bb.utils.md5_file(tmplicfile)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500520 license = b''.join(license)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500521 os.unlink(tmplicfile)
522
523 if recipemd5 == md5chksum:
524 bb.note (pn + ": md5 checksum matched for ", url)
525 else:
526 if recipemd5:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500527 msg = pn + ": The LIC_FILES_CHKSUM does not match for " + url
528 msg = msg + "\n" + pn + ": The new md5 checksum is " + md5chksum
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500529 try:
530 license_lines = license.decode('utf-8').split('\n')
531 except:
532 # License text might not be valid UTF-8, in which
533 # case we don't know how to include it in our output
534 # and have to skip it.
535 pass
536 else:
537 max_lines = int(d.getVar('QA_MAX_LICENSE_LINES') or 20)
538 if not license_lines or license_lines[-1] != '':
539 # Ensure that our license text ends with a line break
540 # (will be added with join() below).
541 license_lines.append('')
542 remove = len(license_lines) - max_lines
543 if remove > 0:
544 start = max_lines // 2
545 end = start + remove - 1
546 del license_lines[start:end]
547 license_lines.insert(start, '...')
548 msg = msg + "\n" + pn + ": Here is the selected license text:" + \
549 "\n" + \
550 "{:v^70}".format(" beginline=%d " % beginline if beginline else "") + \
551 "\n" + "\n".join(license_lines) + \
552 "{:^^70}".format(" endline=%d " % endline if endline else "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500553 if beginline:
554 if endline:
555 srcfiledesc = "%s (lines %d through to %d)" % (srclicfile, beginline, endline)
556 else:
557 srcfiledesc = "%s (beginning on line %d)" % (srclicfile, beginline)
558 elif endline:
559 srcfiledesc = "%s (ending on line %d)" % (srclicfile, endline)
560 else:
561 srcfiledesc = srclicfile
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500562 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 -0500563
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500564 else:
565 msg = pn + ": LIC_FILES_CHKSUM is not specified for " + url
566 msg = msg + "\n" + pn + ": The md5 checksum is " + md5chksum
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800567 sane &= package_qa_handle_error("license-checksum", msg, d)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600568
569 if not sane:
570 bb.fatal("Fatal QA errors found, failing task.")
571}
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500572
573def package_qa_check_staged(path,d):
574 """
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500575 Check staged la and pc files for common problems like references to the work
576 directory.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500577
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500578 As this is run after every stage we should be able to find the one
579 responsible for the errors easily even if we look at every .pc and .la file.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500580 """
581
582 sane = True
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500583 tmpdir = d.getVar('TMPDIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500584 workdir = os.path.join(tmpdir, "work")
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500585 recipesysroot = d.getVar("RECIPE_SYSROOT")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500586
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500587 if bb.data.inherits_class("native", d) or bb.data.inherits_class("cross", d):
588 pkgconfigcheck = workdir
589 else:
590 pkgconfigcheck = tmpdir
591
592 # find all .la and .pc files
593 # read the content
594 # and check for stuff that looks wrong
595 for root, dirs, files in os.walk(path):
596 for file in files:
597 path = os.path.join(root,file)
598 if file.endswith(".la"):
599 with open(path) as f:
600 file_content = f.read()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500601 file_content = file_content.replace(recipesysroot, "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500602 if workdir in file_content:
603 error_msg = "%s failed sanity test (workdir) in path %s" % (file,root)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800604 sane &= package_qa_handle_error("la", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500605 elif file.endswith(".pc"):
606 with open(path) as f:
607 file_content = f.read()
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500608 file_content = file_content.replace(recipesysroot, "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500609 if pkgconfigcheck in file_content:
610 error_msg = "%s failed sanity test (tmpdir) in path %s" % (file,root)
Brad Bishop1a4b7ee2018-12-16 17:11:34 -0800611 sane &= package_qa_handle_error("pkgconfig", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500612
613 return sane
614
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500615# Run all package-wide warnfuncs and errorfuncs
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500616def package_qa_package(warnfuncs, errorfuncs, package, d):
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500617 warnings = {}
618 errors = {}
619
620 for func in warnfuncs:
621 func(package, d, warnings)
622 for func in errorfuncs:
623 func(package, d, errors)
624
625 for w in warnings:
626 package_qa_handle_error(w, warnings[w], d)
627 for e in errors:
628 package_qa_handle_error(e, errors[e], d)
629
630 return len(errors) == 0
631
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500632# Run all recipe-wide warnfuncs and errorfuncs
633def package_qa_recipe(warnfuncs, errorfuncs, pn, d):
634 warnings = {}
635 errors = {}
636
637 for func in warnfuncs:
638 func(pn, d, warnings)
639 for func in errorfuncs:
640 func(pn, d, errors)
641
642 for w in warnings:
643 package_qa_handle_error(w, warnings[w], d)
644 for e in errors:
645 package_qa_handle_error(e, errors[e], d)
646
647 return len(errors) == 0
648
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500649# Walk over all files in a directory and call func
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500650def package_qa_walk(warnfuncs, errorfuncs, package, d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500651 import oe.qa
652
653 #if this will throw an exception, then fix the dict above
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500654 target_os = d.getVar('TARGET_OS')
655 target_arch = d.getVar('TARGET_ARCH')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500656
657 warnings = {}
658 errors = {}
659 for path in pkgfiles[package]:
660 elf = oe.qa.ELFFile(path)
661 try:
662 elf.open()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500663 except (IOError, oe.qa.NotELFFileError):
664 # IOError can happen if the packaging control files disappear,
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500665 elf = None
666 for func in warnfuncs:
667 func(path, package, d, elf, warnings)
668 for func in errorfuncs:
669 func(path, package, d, elf, errors)
670
671 for w in warnings:
672 package_qa_handle_error(w, warnings[w], d)
673 for e in errors:
674 package_qa_handle_error(e, errors[e], d)
675
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500676def package_qa_check_rdepends(pkg, pkgdest, skip, taskdeps, packages, d):
677 # Don't do this check for kernel/module recipes, there aren't too many debug/development
678 # packages and you can get false positives e.g. on kernel-module-lirc-dev
679 if bb.data.inherits_class("kernel", d) or bb.data.inherits_class("module-base", d):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500680 return
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500681
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500682 if not "-dbg" in pkg and not "packagegroup-" in pkg and not "-image" in pkg:
683 localdata = bb.data.createCopy(d)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500684 localdata.setVar('OVERRIDES', localdata.getVar('OVERRIDES') + ':' + pkg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500685
686 # Now check the RDEPENDS
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500687 rdepends = bb.utils.explode_deps(localdata.getVar('RDEPENDS') or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500688
689 # Now do the sanity check!!!
690 if "build-deps" not in skip:
691 for rdepend in rdepends:
692 if "-dbg" in rdepend and "debug-deps" not in skip:
693 error_msg = "%s rdepends on %s" % (pkg,rdepend)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500694 package_qa_handle_error("debug-deps", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500695 if (not "-dev" in pkg and not "-staticdev" in pkg) and rdepend.endswith("-dev") and "dev-deps" not in skip:
696 error_msg = "%s rdepends on %s" % (pkg, rdepend)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500697 package_qa_handle_error("dev-deps", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500698 if rdepend not in packages:
699 rdep_data = oe.packagedata.read_subpkgdata(rdepend, d)
700 if rdep_data and 'PN' in rdep_data and rdep_data['PN'] in taskdeps:
701 continue
702 if not rdep_data or not 'PN' in rdep_data:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500703 pkgdata_dir = d.getVar("PKGDATA_DIR")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500704 try:
705 possibles = os.listdir("%s/runtime-rprovides/%s/" % (pkgdata_dir, rdepend))
706 except OSError:
707 possibles = []
708 for p in possibles:
709 rdep_data = oe.packagedata.read_subpkgdata(p, d)
710 if rdep_data and 'PN' in rdep_data and rdep_data['PN'] in taskdeps:
711 break
712 if rdep_data and 'PN' in rdep_data and rdep_data['PN'] in taskdeps:
713 continue
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500714 if rdep_data and 'PN' in rdep_data:
715 error_msg = "%s rdepends on %s, but it isn't a build dependency, missing %s in DEPENDS or PACKAGECONFIG?" % (pkg, rdepend, rdep_data['PN'])
716 else:
717 error_msg = "%s rdepends on %s, but it isn't a build dependency?" % (pkg, rdepend)
718 package_qa_handle_error("build-deps", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500719
720 if "file-rdeps" not in skip:
721 ignored_file_rdeps = set(['/bin/sh', '/usr/bin/env', 'rtld(GNU_HASH)'])
722 if bb.data.inherits_class('nativesdk', d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500723 ignored_file_rdeps |= set(['/bin/bash', '/usr/bin/perl', 'perl'])
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500724 # For Saving the FILERDEPENDS
725 filerdepends = {}
726 rdep_data = oe.packagedata.read_subpkgdata(pkg, d)
727 for key in rdep_data:
728 if key.startswith("FILERDEPENDS_"):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500729 for subkey in bb.utils.explode_deps(rdep_data[key]):
730 if subkey not in ignored_file_rdeps and \
731 not subkey.startswith('perl('):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500732 # We already know it starts with FILERDEPENDS_
733 filerdepends[subkey] = key[13:]
734
735 if filerdepends:
736 next = rdepends
737 done = rdepends[:]
738 # Find all the rdepends on the dependency chain
739 while next:
740 new = []
741 for rdep in next:
742 rdep_data = oe.packagedata.read_subpkgdata(rdep, d)
743 sub_rdeps = rdep_data.get("RDEPENDS_" + rdep)
744 if not sub_rdeps:
745 continue
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500746 for sub_rdep in bb.utils.explode_deps(sub_rdeps):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500747 if sub_rdep in done:
748 continue
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500749 if oe.packagedata.has_subpkgdata(sub_rdep, d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500750 # It's a new rdep
751 done.append(sub_rdep)
752 new.append(sub_rdep)
753 next = new
754
755 # Add the rprovides of itself
756 if pkg not in done:
757 done.insert(0, pkg)
758
759 # The python is not a package, but python-core provides it, so
760 # skip checking /usr/bin/python if python is in the rdeps, in
761 # case there is a RDEPENDS_pkg = "python" in the recipe.
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500762 for py in [ d.getVar('MLPREFIX') + "python", "python" ]:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500763 if py in done:
764 filerdepends.pop("/usr/bin/python",None)
765 done.remove(py)
766 for rdep in done:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500767 # The file dependencies may contain package names, e.g.,
768 # perl
769 filerdepends.pop(rdep,None)
770
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500771 # For Saving the FILERPROVIDES, RPROVIDES and FILES_INFO
772 rdep_data = oe.packagedata.read_subpkgdata(rdep, d)
773 for key in rdep_data:
774 if key.startswith("FILERPROVIDES_") or key.startswith("RPROVIDES_"):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500775 for subkey in bb.utils.explode_deps(rdep_data[key]):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500776 filerdepends.pop(subkey,None)
777 # Add the files list to the rprovides
778 if key == "FILES_INFO":
779 # Use eval() to make it as a dict
780 for subkey in eval(rdep_data[key]):
781 filerdepends.pop(subkey,None)
782 if not filerdepends:
783 # Break if all the file rdepends are met
784 break
785 if filerdepends:
786 for key in filerdepends:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500787 error_msg = "%s contained in package %s requires %s, but no providers found in RDEPENDS_%s?" % \
788 (filerdepends[key].replace("_%s" % pkg, "").replace("@underscore@", "_"), pkg, key, pkg)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500789 package_qa_handle_error("file-rdeps", error_msg, d)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500790package_qa_check_rdepends[vardepsexclude] = "OVERRIDES"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500791
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500792def package_qa_check_deps(pkg, pkgdest, d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500793
794 localdata = bb.data.createCopy(d)
795 localdata.setVar('OVERRIDES', pkg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500796
797 def check_valid_deps(var):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500798 try:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500799 rvar = bb.utils.explode_dep_versions2(localdata.getVar(var) or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500800 except ValueError as e:
801 bb.fatal("%s_%s: %s" % (var, pkg, e))
802 for dep in rvar:
803 for v in rvar[dep]:
804 if v and not v.startswith(('< ', '= ', '> ', '<= ', '>=')):
805 error_msg = "%s_%s is invalid: %s (%s) only comparisons <, =, >, <=, and >= are allowed" % (var, pkg, dep, v)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500806 package_qa_handle_error("dep-cmp", error_msg, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500807
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500808 check_valid_deps('RDEPENDS')
809 check_valid_deps('RRECOMMENDS')
810 check_valid_deps('RSUGGESTS')
811 check_valid_deps('RPROVIDES')
812 check_valid_deps('RREPLACES')
813 check_valid_deps('RCONFLICTS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500814
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500815QAPKGTEST[usrmerge] = "package_qa_check_usrmerge"
816def package_qa_check_usrmerge(pkg, d, messages):
817 pkgdest = d.getVar('PKGDEST')
818 pkg_dir = pkgdest + os.sep + pkg + os.sep
819 merged_dirs = ['bin', 'sbin', 'lib'] + d.getVar('MULTILIB_VARIANTS').split()
820 for f in merged_dirs:
821 if os.path.exists(pkg_dir + f) and not os.path.islink(pkg_dir + f):
822 msg = "%s package is not obeying usrmerge distro feature. /%s should be relocated to /usr." % (pkg, f)
823 package_qa_add_message(messages, "usrmerge", msg)
824 return False
825 return True
826
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500827QAPKGTEST[expanded-d] = "package_qa_check_expanded_d"
828def package_qa_check_expanded_d(package, d, messages):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500829 """
830 Check for the expanded D (${D}) value in pkg_* and FILES
831 variables, warn the user to use it correctly.
832 """
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500833 sane = True
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500834 expanded_d = d.getVar('D')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500835
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500836 for var in 'FILES','pkg_preinst', 'pkg_postinst', 'pkg_prerm', 'pkg_postrm':
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500837 bbvar = d.getVar(var + "_" + package) or ""
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500838 if expanded_d in bbvar:
839 if var == 'FILES':
840 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)
841 sane = False
842 else:
843 package_qa_add_message(messages, "expanded-d", "%s in %s recipe contains ${D}, it should be replaced by $D instead" % (var, package))
844 sane = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500845 return sane
846
847def package_qa_check_encoding(keys, encode, d):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600848 def check_encoding(key, enc):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500849 sane = True
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500850 value = d.getVar(key)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500851 if value:
852 try:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600853 s = value.encode(enc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500854 except UnicodeDecodeError as e:
855 error_msg = "%s has non %s characters" % (key,enc)
856 sane = False
857 package_qa_handle_error("invalid-chars", error_msg, d)
858 return sane
859
860 for key in keys:
861 sane = check_encoding(key, encode)
862 if not sane:
863 break
864
865HOST_USER_UID := "${@os.getuid()}"
866HOST_USER_GID := "${@os.getgid()}"
867
868QAPATHTEST[host-user-contaminated] = "package_qa_check_host_user"
869def package_qa_check_host_user(path, name, d, elf, messages):
870 """Check for paths outside of /home which are owned by the user running bitbake."""
871
872 if not os.path.lexists(path):
873 return
874
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500875 dest = d.getVar('PKGDEST')
876 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500877 home = os.path.join(dest, 'home')
878 if path == home or path.startswith(home + os.sep):
879 return
880
881 try:
882 stat = os.lstat(path)
883 except OSError as exc:
884 import errno
885 if exc.errno != errno.ENOENT:
886 raise
887 else:
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500888 rootfs_path = path[len(dest):]
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500889 check_uid = int(d.getVar('HOST_USER_UID'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500890 if stat.st_uid == check_uid:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500891 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 -0500892 return False
893
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500894 check_gid = int(d.getVar('HOST_USER_GID'))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500895 if stat.st_gid == check_gid:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500896 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 -0500897 return False
898 return True
899
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500900
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500901# The PACKAGE FUNC to scan each package
902python do_package_qa () {
903 import subprocess
904 import oe.packagedata
905
906 bb.note("DO PACKAGE QA")
907
908 bb.build.exec_func("read_subpackage_metadata", d)
909
910 # Check non UTF-8 characters on recipe's metadata
911 package_qa_check_encoding(['DESCRIPTION', 'SUMMARY', 'LICENSE', 'SECTION'], 'utf-8', d)
912
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500913 logdir = d.getVar('T')
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500914 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500915
916 # Check the compile log for host contamination
917 compilelog = os.path.join(logdir,"log.do_compile")
918
919 if os.path.exists(compilelog):
920 statement = "grep -e 'CROSS COMPILE Badness:' -e 'is unsafe for cross-compilation' %s > /dev/null" % compilelog
921 if subprocess.call(statement, shell=True) == 0:
922 msg = "%s: The compile log indicates that host include and/or library paths were used.\n \
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500923 Please check the log '%s' for more information." % (pn, compilelog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500924 package_qa_handle_error("compile-host-path", msg, d)
925
926 # Check the install log for host contamination
927 installlog = os.path.join(logdir,"log.do_install")
928
929 if os.path.exists(installlog):
930 statement = "grep -e 'CROSS COMPILE Badness:' -e 'is unsafe for cross-compilation' %s > /dev/null" % installlog
931 if subprocess.call(statement, shell=True) == 0:
932 msg = "%s: The install log indicates that host include and/or library paths were used.\n \
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500933 Please check the log '%s' for more information." % (pn, installlog)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500934 package_qa_handle_error("install-host-path", msg, d)
935
936 # Scan the packages...
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500937 pkgdest = d.getVar('PKGDEST')
938 packages = set((d.getVar('PACKAGES') or '').split())
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500939
940 cpath = oe.cachedpath.CachedPath()
941 global pkgfiles
942 pkgfiles = {}
943 for pkg in packages:
944 pkgfiles[pkg] = []
945 for walkroot, dirs, files in cpath.walk(pkgdest + "/" + pkg):
946 for file in files:
947 pkgfiles[pkg].append(walkroot + os.sep + file)
948
949 # no packages should be scanned
950 if not packages:
951 return
952
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500953 import re
954 # The package name matches the [a-z0-9.+-]+ regular expression
955 pkgname_pattern = re.compile("^[a-z0-9.+-]+$")
956
957 taskdepdata = d.getVar("BB_TASKDEPDATA", False)
958 taskdeps = set()
959 for dep in taskdepdata:
960 taskdeps.add(taskdepdata[dep][0])
961
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500962 def parse_test_matrix(matrix_name):
963 testmatrix = d.getVarFlags(matrix_name) or {}
964 g = globals()
965 warnchecks = []
966 for w in (d.getVar("WARN_QA") or "").split():
967 if w in skip:
968 continue
969 if w in testmatrix and testmatrix[w] in g:
970 warnchecks.append(g[testmatrix[w]])
971
972 errorchecks = []
973 for e in (d.getVar("ERROR_QA") or "").split():
974 if e in skip:
975 continue
976 if e in testmatrix and testmatrix[e] in g:
977 errorchecks.append(g[testmatrix[e]])
978 return warnchecks, errorchecks
979
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500980 for package in packages:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500981 skip = set((d.getVar('INSANE_SKIP') or "").split() +
982 (d.getVar('INSANE_SKIP_' + package) or "").split())
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500983 if skip:
984 bb.note("Package %s skipping QA tests: %s" % (package, str(skip)))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500985
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500986 bb.note("Checking Package: %s" % package)
987 # Check package name
988 if not pkgname_pattern.match(package):
989 package_qa_handle_error("pkgname",
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500990 "%s doesn't match the [a-z0-9.+-]+ regex" % package, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500991
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500992 warn_checks, error_checks = parse_test_matrix("QAPATHTEST")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500993 package_qa_walk(warn_checks, error_checks, package, d)
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500994
995 warn_checks, error_checks = parse_test_matrix("QAPKGTEST")
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500996 package_qa_package(warn_checks, error_checks, package, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500997
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500998 package_qa_check_rdepends(package, pkgdest, skip, taskdeps, packages, d)
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500999 package_qa_check_deps(package, pkgdest, d)
1000
1001 warn_checks, error_checks = parse_test_matrix("QARECIPETEST")
1002 package_qa_recipe(warn_checks, error_checks, pn, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001003
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001004 if 'libdir' in d.getVar("ALL_QA").split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001005 package_qa_check_libdir(d)
1006
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001007 qa_sane = d.getVar("QA_SANE")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001008 if not qa_sane:
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001009 bb.fatal("QA run found fatal errors. Please consider fixing them.")
1010 bb.note("DONE with PACKAGE QA")
1011}
1012
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001013# binutils is used for most checks, so need to set as dependency
1014# POPULATESYSROOTDEPS is defined in staging class.
1015do_package_qa[depends] += "${POPULATESYSROOTDEPS}"
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001016do_package_qa[vardepsexclude] = "BB_TASKDEPDATA"
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001017do_package_qa[rdeptask] = "do_packagedata"
1018addtask do_package_qa after do_packagedata do_package before do_build
1019
1020SSTATETASKS += "do_package_qa"
1021do_package_qa[sstate-inputdirs] = ""
1022do_package_qa[sstate-outputdirs] = ""
1023python do_package_qa_setscene () {
1024 sstate_setscene(d)
1025}
1026addtask do_package_qa_setscene
1027
1028python do_qa_staging() {
1029 bb.note("QA checking staging")
1030
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001031 if not package_qa_check_staged(d.expand('${SYSROOT_DESTDIR}${libdir}'), d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001032 bb.fatal("QA staging was broken by the package built above")
1033}
1034
1035python do_qa_configure() {
1036 import subprocess
1037
1038 ###########################################################################
1039 # Check config.log for cross compile issues
1040 ###########################################################################
1041
1042 configs = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001043 workdir = d.getVar('WORKDIR')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001044
1045 if bb.data.inherits_class('autotools', d):
1046 bb.note("Checking autotools environment for common misconfiguration")
1047 for root, dirs, files in os.walk(workdir):
1048 statement = "grep -q -F -e 'CROSS COMPILE Badness:' -e 'is unsafe for cross-compilation' %s" % \
1049 os.path.join(root,"config.log")
1050 if "config.log" in files:
1051 if subprocess.call(statement, shell=True) == 0:
1052 bb.fatal("""This autoconf log indicates errors, it looked at host include and/or library paths while determining system capabilities.
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001053Rerun configure task after fixing this.""")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001054
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001055 if "configure.ac" in files:
1056 configs.append(os.path.join(root,"configure.ac"))
1057 if "configure.in" in files:
1058 configs.append(os.path.join(root, "configure.in"))
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001059
1060 ###########################################################################
1061 # Check gettext configuration and dependencies are correct
1062 ###########################################################################
1063
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001064 cnf = d.getVar('EXTRA_OECONF') or ""
1065 if "gettext" not in d.getVar('P') and "gcc-runtime" not in d.getVar('P') and "--disable-nls" not in cnf:
1066 ml = d.getVar("MLPREFIX") or ""
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001067 if bb.data.inherits_class('cross-canadian', d):
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001068 gt = "nativesdk-gettext"
1069 else:
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001070 gt = "gettext-native"
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001071 deps = bb.utils.explode_deps(d.getVar('DEPENDS') or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001072 if gt not in deps:
1073 for config in configs:
1074 gnu = "grep \"^[[:space:]]*AM_GNU_GETTEXT\" %s >/dev/null" % config
1075 if subprocess.call(gnu, shell=True) == 0:
1076 bb.fatal("""%s required but not in DEPENDS for file %s.
1077Missing inherit gettext?""" % (gt, config))
1078
1079 ###########################################################################
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001080 # Check unrecognised configure options (with a white list)
1081 ###########################################################################
1082 if bb.data.inherits_class("autotools", d):
1083 bb.note("Checking configure output for unrecognised options")
1084 try:
1085 flag = "WARNING: unrecognized options:"
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001086 log = os.path.join(d.getVar('B'), 'config.log')
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001087 output = subprocess.check_output(['grep', '-F', flag, log]).decode("utf-8").replace(', ', ' ')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001088 options = set()
1089 for line in output.splitlines():
1090 options |= set(line.partition(flag)[2].split())
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001091 whitelist = set(d.getVar("UNKNOWN_CONFIGURE_WHITELIST").split())
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001092 options -= whitelist
1093 if options:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001094 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001095 error_msg = pn + ": configure was passed unrecognised options: " + " ".join(options)
1096 package_qa_handle_error("unknown-configure-option", error_msg, d)
1097 except subprocess.CalledProcessError:
1098 pass
1099
1100 # Check invalid PACKAGECONFIG
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001101 pkgconfig = (d.getVar("PACKAGECONFIG") or "").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001102 if pkgconfig:
1103 pkgconfigflags = d.getVarFlags("PACKAGECONFIG") or {}
1104 for pconfig in pkgconfig:
1105 if pconfig not in pkgconfigflags:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001106 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001107 error_msg = "%s: invalid PACKAGECONFIG: %s" % (pn, pconfig)
Patrick Williamsf1e5d692016-03-30 15:21:19 -05001108 package_qa_handle_error("invalid-packageconfig", error_msg, d)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001109
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001110 qa_sane = d.getVar("QA_SANE")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001111 if not qa_sane:
1112 bb.fatal("Fatal QA errors found, failing task.")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001113}
1114
1115python do_qa_unpack() {
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001116 src_uri = d.getVar('SRC_URI')
1117 s_dir = d.getVar('S')
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001118 if src_uri and not os.path.exists(s_dir):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001119 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 -05001120}
1121
1122# The Staging Func, to check all staging
1123#addtask qa_staging after do_populate_sysroot before do_build
1124do_populate_sysroot[postfuncs] += "do_qa_staging "
1125
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001126# Check broken config.log files, for packages requiring Gettext which
1127# don't have it in DEPENDS.
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001128#addtask qa_configure after do_configure before do_compile
1129do_configure[postfuncs] += "do_qa_configure "
1130
1131# Check does S exist.
1132do_unpack[postfuncs] += "do_qa_unpack"
1133
1134python () {
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001135 import re
1136
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001137 tests = d.getVar('ALL_QA').split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001138 if "desktop" in tests:
1139 d.appendVar("PACKAGE_DEPENDS", " desktop-file-utils-native")
1140
1141 ###########################################################################
1142 # Check various variables
1143 ###########################################################################
1144
1145 # Checking ${FILESEXTRAPATHS}
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001146 extrapaths = (d.getVar("FILESEXTRAPATHS") or "")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001147 if '__default' not in extrapaths.split(":"):
1148 msg = "FILESEXTRAPATHS-variable, must always use _prepend (or _append)\n"
1149 msg += "type of assignment, and don't forget the colon.\n"
1150 msg += "Please assign it with the format of:\n"
1151 msg += " FILESEXTRAPATHS_append := \":${THISDIR}/Your_Files_Path\" or\n"
1152 msg += " FILESEXTRAPATHS_prepend := \"${THISDIR}/Your_Files_Path:\"\n"
1153 msg += "in your bbappend file\n\n"
1154 msg += "Your incorrect assignment is:\n"
1155 msg += "%s\n" % extrapaths
1156 bb.warn(msg)
1157
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001158 overrides = d.getVar('OVERRIDES').split(':')
1159 pn = d.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001160 if pn in overrides:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001161 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 -05001162 package_qa_handle_error("pn-overrides", msg, d)
Brad Bishopd7bf8c12018-02-25 22:55:05 -05001163 prog = re.compile('[A-Z]')
1164 if prog.search(pn):
1165 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 -05001166
1167 issues = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001168 if (d.getVar('PACKAGES') or "").split():
1169 for dep in (d.getVar('QADEPENDS') or "").split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001170 d.appendVarFlag('do_package_qa', 'depends', " %s:do_populate_sysroot" % dep)
1171 for var in 'RDEPENDS', 'RRECOMMENDS', 'RSUGGESTS', 'RCONFLICTS', 'RPROVIDES', 'RREPLACES', 'FILES', 'pkg_preinst', 'pkg_postinst', 'pkg_prerm', 'pkg_postrm', 'ALLOW_EMPTY':
1172 if d.getVar(var, False):
1173 issues.append(var)
1174
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001175 fakeroot_tests = d.getVar('FAKEROOT_QA').split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001176 if set(tests) & set(fakeroot_tests):
1177 d.setVarFlag('do_package_qa', 'fakeroot', '1')
1178 d.appendVarFlag('do_package_qa', 'depends', ' virtual/fakeroot-native:do_populate_sysroot')
1179 else:
1180 d.setVarFlag('do_package_qa', 'rdeptask', '')
1181 for i in issues:
Brad Bishop6e60e8b2018-02-01 10:27:11 -05001182 package_qa_handle_error("pkgvarcheck", "%s: Variable %s is set as not being package specific, please fix this." % (d.getVar("FILE"), i), d)
1183 qa_sane = d.getVar("QA_SANE")
Patrick Williamsd8c66bc2016-06-20 12:57:21 -05001184 if not qa_sane:
1185 bb.fatal("Fatal QA errors found, failing task.")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001186}