blob: 7682ffbb8c18440bd211a6f0a7cce38cafd85ea4 [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001#
2# Sanity check the users setup for common misconfigurations
3#
4
5SANITY_REQUIRED_UTILITIES ?= "patch diffstat makeinfo git bzip2 tar \
Patrick Williamsf1e5d692016-03-30 15:21:19 -05006 gzip gawk chrpath wget cpio perl file"
Patrick Williamsc124f4f2015-09-15 14:41:29 -05007
8def bblayers_conf_file(d):
9 return os.path.join(d.getVar('TOPDIR', True), 'conf/bblayers.conf')
10
11def sanity_conf_read(fn):
12 with open(fn, 'r') as f:
13 lines = f.readlines()
14 return lines
15
16def sanity_conf_find_line(pattern, lines):
17 import re
18 return next(((index, line)
19 for index, line in enumerate(lines)
20 if re.search(pattern, line)), (None, None))
21
22def sanity_conf_update(fn, lines, version_var_name, new_version):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050023 index, line = sanity_conf_find_line(r"^%s" % version_var_name, lines)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050024 lines[index] = '%s = "%d"\n' % (version_var_name, new_version)
25 with open(fn, "w") as f:
26 f.write(''.join(lines))
27
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050028# Functions added to this variable MUST throw a NotImplementedError exception unless
29# they successfully changed the config version in the config file. Exceptions
30# are used since exec_func doesn't handle return values.
31BBLAYERS_CONF_UPDATE_FUNCS += " \
32 conf/bblayers.conf:LCONF_VERSION:LAYER_CONF_VERSION:oecore_update_bblayers \
33 conf/local.conf:CONF_VERSION:LOCALCONF_VERSION:oecore_update_localconf \
34 conf/site.conf:SCONF_VERSION:SITE_CONF_VERSION:oecore_update_siteconf \
35"
Patrick Williamsc124f4f2015-09-15 14:41:29 -050036
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050037SANITY_DIFF_TOOL ?= "meld"
38
39SANITY_LOCALCONF_SAMPLE ?= "${COREBASE}/meta*/conf/local.conf.sample"
40python oecore_update_localconf() {
41 # Check we are using a valid local.conf
42 current_conf = d.getVar('CONF_VERSION', True)
43 conf_version = d.getVar('LOCALCONF_VERSION', True)
44
45 failmsg = """Your version of local.conf was generated from an older/newer version of
46local.conf.sample and there have been updates made to this file. Please compare the two
47files and merge any changes before continuing.
48
49Matching the version numbers will remove this message.
50
51\"${SANITY_DIFF_TOOL} conf/local.conf ${SANITY_LOCALCONF_SAMPLE}\"
52
53is a good way to visualise the changes."""
54 failmsg = d.expand(failmsg)
55
56 raise NotImplementedError(failmsg)
57}
58
59SANITY_SITECONF_SAMPLE ?= "${COREBASE}/meta*/conf/site.conf.sample"
60python oecore_update_siteconf() {
61 # If we have a site.conf, check it's valid
62 current_sconf = d.getVar('SCONF_VERSION', True)
63 sconf_version = d.getVar('SITE_CONF_VERSION', True)
64
65 failmsg = """Your version of site.conf was generated from an older version of
66site.conf.sample and there have been updates made to this file. Please compare the two
67files and merge any changes before continuing.
68
69Matching the version numbers will remove this message.
70
71\"${SANITY_DIFF_TOOL} conf/site.conf ${SANITY_SITECONF_SAMPLE}\"
72
73is a good way to visualise the changes."""
74 failmsg = d.expand(failmsg)
75
76 raise NotImplementedError(failmsg)
77}
78
79SANITY_BBLAYERCONF_SAMPLE ?= "${COREBASE}/meta*/conf/bblayers.conf.sample"
Patrick Williamsc124f4f2015-09-15 14:41:29 -050080python oecore_update_bblayers() {
81 # bblayers.conf is out of date, so see if we can resolve that
82
83 current_lconf = int(d.getVar('LCONF_VERSION', True))
Patrick Williamsc124f4f2015-09-15 14:41:29 -050084 lconf_version = int(d.getVar('LAYER_CONF_VERSION', True))
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050085
86 failmsg = """Your version of bblayers.conf has the wrong LCONF_VERSION (has ${LCONF_VERSION}, expecting ${LAYER_CONF_VERSION}).
87Please compare your file against bblayers.conf.sample and merge any changes before continuing.
88"${SANITY_DIFF_TOOL} conf/bblayers.conf ${SANITY_BBLAYERCONF_SAMPLE}"
89
90is a good way to visualise the changes."""
91 failmsg = d.expand(failmsg)
92
93 if not current_lconf:
94 raise NotImplementedError(failmsg)
95
Patrick Williamsc124f4f2015-09-15 14:41:29 -050096 lines = []
97
98 if current_lconf < 4:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050099 raise NotImplementedError(failmsg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500100
101 bblayers_fn = bblayers_conf_file(d)
102 lines = sanity_conf_read(bblayers_fn)
103
104 if current_lconf == 4 and lconf_version > 4:
105 topdir_var = '$' + '{TOPDIR}'
106 index, bbpath_line = sanity_conf_find_line('BBPATH', lines)
107 if bbpath_line:
108 start = bbpath_line.find('"')
109 if start != -1 and (len(bbpath_line) != (start + 1)):
110 if bbpath_line[start + 1] == '"':
111 lines[index] = (bbpath_line[:start + 1] +
112 topdir_var + bbpath_line[start + 1:])
113 else:
114 if not topdir_var in bbpath_line:
115 lines[index] = (bbpath_line[:start + 1] +
116 topdir_var + ':' + bbpath_line[start + 1:])
117 else:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500118 raise NotImplementedError(failmsg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500119 else:
120 index, bbfiles_line = sanity_conf_find_line('BBFILES', lines)
121 if bbfiles_line:
122 lines.insert(index, 'BBPATH = "' + topdir_var + '"\n')
123 else:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500124 raise NotImplementedError(failmsg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500125
126 current_lconf += 1
127 sanity_conf_update(bblayers_fn, lines, 'LCONF_VERSION', current_lconf)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500128 bb.note("Your conf/bblayers.conf has been automatically updated.")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500129 return
130
131 elif current_lconf == 5 and lconf_version > 5:
132 # Null update, to avoid issues with people switching between poky and other distros
133 current_lconf = 6
134 sanity_conf_update(bblayers_fn, lines, 'LCONF_VERSION', current_lconf)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500135 bb.note("Your conf/bblayers.conf has been automatically updated.")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500136 return
137
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600138 status.addresult()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500139
140 elif current_lconf == 6 and lconf_version > 6:
141 # Handle rename of meta-yocto -> meta-poky
142 # This marks the start of separate version numbers but code is needed in OE-Core
143 # for the migration, one last time.
144 layers = d.getVar('BBLAYERS', True).split()
145 layers = [ os.path.basename(path) for path in layers ]
146 if 'meta-yocto' in layers:
147 found = False
148 while True:
149 index, meta_yocto_line = sanity_conf_find_line(r'.*meta-yocto[\'"\s\n]', lines)
150 if meta_yocto_line:
151 lines[index] = meta_yocto_line.replace('meta-yocto', 'meta-poky')
152 found = True
153 else:
154 break
155 if not found:
156 raise NotImplementedError(failmsg)
157 index, meta_yocto_line = sanity_conf_find_line('LCONF_VERSION.*\n', lines)
158 if meta_yocto_line:
159 lines[index] = 'POKY_BBLAYERS_CONF_VERSION = "1"\n'
160 else:
161 raise NotImplementedError(failmsg)
162 with open(bblayers_fn, "w") as f:
163 f.write(''.join(lines))
164 bb.note("Your conf/bblayers.conf has been automatically updated.")
165 return
166 current_lconf += 1
167 sanity_conf_update(bblayers_fn, lines, 'LCONF_VERSION', current_lconf)
168 bb.note("Your conf/bblayers.conf has been automatically updated.")
169 return
170
171 raise NotImplementedError(failmsg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500172}
173
174def raise_sanity_error(msg, d, network_error=False):
175 if d.getVar("SANITY_USE_EVENTS", True) == "1":
176 try:
177 bb.event.fire(bb.event.SanityCheckFailed(msg, network_error), d)
178 except TypeError:
179 bb.event.fire(bb.event.SanityCheckFailed(msg), d)
180 return
181
182 bb.fatal(""" OE-core's config sanity checker detected a potential misconfiguration.
183 Either fix the cause of this error or at your own risk disable the checker (see sanity.conf).
184 Following is the list of potential problems / advisories:
185
186 %s""" % msg)
187
188# Check flags associated with a tuning.
189def check_toolchain_tune_args(data, tune, multilib, errs):
190 found_errors = False
191 if check_toolchain_args_present(data, tune, multilib, errs, 'CCARGS'):
192 found_errors = True
193 if check_toolchain_args_present(data, tune, multilib, errs, 'ASARGS'):
194 found_errors = True
195 if check_toolchain_args_present(data, tune, multilib, errs, 'LDARGS'):
196 found_errors = True
197
198 return found_errors
199
200def check_toolchain_args_present(data, tune, multilib, tune_errors, which):
201 args_set = (data.getVar("TUNE_%s" % which, True) or "").split()
202 args_wanted = (data.getVar("TUNEABI_REQUIRED_%s_tune-%s" % (which, tune), True) or "").split()
203 args_missing = []
204
205 # If no args are listed/required, we are done.
206 if not args_wanted:
207 return
208 for arg in args_wanted:
209 if arg not in args_set:
210 args_missing.append(arg)
211
212 found_errors = False
213 if args_missing:
214 found_errors = True
215 tune_errors.append("TUNEABI for %s requires '%s' in TUNE_%s (%s)." %
216 (tune, ' '.join(args_missing), which, ' '.join(args_set)))
217 return found_errors
218
219# Check a single tune for validity.
220def check_toolchain_tune(data, tune, multilib):
221 tune_errors = []
222 if not tune:
223 return "No tuning found for %s multilib." % multilib
224 localdata = bb.data.createCopy(data)
225 if multilib != "default":
226 # Apply the overrides so we can look at the details.
227 overrides = localdata.getVar("OVERRIDES", False) + ":virtclass-multilib-" + multilib
228 localdata.setVar("OVERRIDES", overrides)
229 bb.data.update_data(localdata)
230 bb.debug(2, "Sanity-checking tuning '%s' (%s) features:" % (tune, multilib))
231 features = (localdata.getVar("TUNE_FEATURES_tune-%s" % tune, True) or "").split()
232 if not features:
233 return "Tuning '%s' has no defined features, and cannot be used." % tune
234 valid_tunes = localdata.getVarFlags('TUNEVALID') or {}
235 conflicts = localdata.getVarFlags('TUNECONFLICTS') or {}
236 # [doc] is the documentation for the variable, not a real feature
237 if 'doc' in valid_tunes:
238 del valid_tunes['doc']
239 if 'doc' in conflicts:
240 del conflicts['doc']
241 for feature in features:
242 if feature in conflicts:
243 for conflict in conflicts[feature].split():
244 if conflict in features:
245 tune_errors.append("Feature '%s' conflicts with '%s'." %
246 (feature, conflict))
247 if feature in valid_tunes:
248 bb.debug(2, " %s: %s" % (feature, valid_tunes[feature]))
249 else:
250 tune_errors.append("Feature '%s' is not defined." % feature)
251 whitelist = localdata.getVar("TUNEABI_WHITELIST", True)
252 if whitelist:
253 tuneabi = localdata.getVar("TUNEABI_tune-%s" % tune, True)
254 if not tuneabi:
255 tuneabi = tune
256 if True not in [x in whitelist.split() for x in tuneabi.split()]:
257 tune_errors.append("Tuning '%s' (%s) cannot be used with any supported tuning/ABI." %
258 (tune, tuneabi))
259 else:
260 if not check_toolchain_tune_args(localdata, tuneabi, multilib, tune_errors):
261 bb.debug(2, "Sanity check: Compiler args OK for %s." % tune)
262 if tune_errors:
263 return "Tuning '%s' has the following errors:\n" % tune + '\n'.join(tune_errors)
264
265def check_toolchain(data):
266 tune_error_set = []
267 deftune = data.getVar("DEFAULTTUNE", True)
268 tune_errors = check_toolchain_tune(data, deftune, 'default')
269 if tune_errors:
270 tune_error_set.append(tune_errors)
271
272 multilibs = (data.getVar("MULTILIB_VARIANTS", True) or "").split()
273 global_multilibs = (data.getVar("MULTILIB_GLOBAL_VARIANTS", True) or "").split()
274
275 if multilibs:
276 seen_libs = []
277 seen_tunes = []
278 for lib in multilibs:
279 if lib in seen_libs:
280 tune_error_set.append("The multilib '%s' appears more than once." % lib)
281 else:
282 seen_libs.append(lib)
283 if not lib in global_multilibs:
284 tune_error_set.append("Multilib %s is not present in MULTILIB_GLOBAL_VARIANTS" % lib)
285 tune = data.getVar("DEFAULTTUNE_virtclass-multilib-%s" % lib, True)
286 if tune in seen_tunes:
287 tune_error_set.append("The tuning '%s' appears in more than one multilib." % tune)
288 else:
289 seen_libs.append(tune)
290 if tune == deftune:
291 tune_error_set.append("Multilib '%s' (%s) is also the default tuning." % (lib, deftune))
292 else:
293 tune_errors = check_toolchain_tune(data, tune, lib)
294 if tune_errors:
295 tune_error_set.append(tune_errors)
296 if tune_error_set:
297 return "Toolchain tunings invalid:\n" + '\n'.join(tune_error_set) + "\n"
298
299 return ""
300
301def check_conf_exists(fn, data):
302 bbpath = []
303 fn = data.expand(fn)
304 vbbpath = data.getVar("BBPATH", False)
305 if vbbpath:
306 bbpath += vbbpath.split(":")
307 for p in bbpath:
308 currname = os.path.join(data.expand(p), fn)
309 if os.access(currname, os.R_OK):
310 return True
311 return False
312
313def check_create_long_filename(filepath, pathname):
314 import string, random
315 testfile = os.path.join(filepath, ''.join(random.choice(string.ascii_letters) for x in range(200)))
316 try:
317 if not os.path.exists(filepath):
318 bb.utils.mkdirhier(filepath)
319 f = open(testfile, "w")
320 f.close()
321 os.remove(testfile)
322 except IOError as e:
323 import errno
324 err, strerror = e.args
325 if err == errno.ENAMETOOLONG:
326 return "Failed to create a file with a long name in %s. Please use a filesystem that does not unreasonably limit filename length.\n" % pathname
327 else:
328 return "Failed to create a file in %s: %s.\n" % (pathname, strerror)
329 except OSError as e:
330 errno, strerror = e.args
331 return "Failed to create %s directory in which to run long name sanity check: %s.\n" % (pathname, strerror)
332 return ""
333
334def check_path_length(filepath, pathname, limit):
335 if len(filepath) > limit:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500336 return "The length of %s is longer than %s, this would cause unexpected errors, please use a shorter path.\n" % (pathname, limit)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500337 return ""
338
339def get_filesystem_id(path):
340 status, result = oe.utils.getstatusoutput("stat -f -c '%s' %s" % ("%t", path))
341 if status == 0:
342 return result
343 else:
344 bb.warn("Can't get the filesystem id of: %s" % path)
345 return None
346
347# Check that the path isn't located on nfs.
348def check_not_nfs(path, name):
349 # The nfs' filesystem id is 6969
350 if get_filesystem_id(path) == "6969":
351 return "The %s: %s can't be located on nfs.\n" % (name, path)
352 return ""
353
354# Check that path isn't a broken symlink
355def check_symlink(lnk, data):
356 if os.path.islink(lnk) and not os.path.exists(lnk):
357 raise_sanity_error("%s is a broken symlink." % lnk, data)
358
359def check_connectivity(d):
360 # URI's to check can be set in the CONNECTIVITY_CHECK_URIS variable
361 # using the same syntax as for SRC_URI. If the variable is not set
362 # the check is skipped
363 test_uris = (d.getVar('CONNECTIVITY_CHECK_URIS', True) or "").split()
364 retval = ""
365
366 # Only check connectivity if network enabled and the
367 # CONNECTIVITY_CHECK_URIS are set
368 network_enabled = not d.getVar('BB_NO_NETWORK', True)
369 check_enabled = len(test_uris)
370 # Take a copy of the data store and unset MIRRORS and PREMIRRORS
371 data = bb.data.createCopy(d)
372 data.delVar('PREMIRRORS')
373 data.delVar('MIRRORS')
374 if check_enabled and network_enabled:
375 try:
376 fetcher = bb.fetch2.Fetch(test_uris, data)
377 fetcher.checkstatus()
378 except Exception as err:
379 # Allow the message to be configured so that users can be
380 # pointed to a support mechanism.
381 msg = data.getVar('CONNECTIVITY_CHECK_MSG', True) or ""
382 if len(msg) == 0:
383 msg = "%s. Please ensure your network is configured correctly.\n" % err
384 retval = msg
385
386 return retval
387
388def check_supported_distro(sanity_data):
389 from fnmatch import fnmatch
390
391 tested_distros = sanity_data.getVar('SANITY_TESTED_DISTROS', True)
392 if not tested_distros:
393 return
394
395 try:
396 distro = oe.lsb.distro_identifier()
397 except Exception:
398 distro = None
399
400 if not distro:
401 bb.warn('Host distribution could not be determined; you may possibly experience unexpected failures. It is recommended that you use a tested distribution.')
402
403 for supported in [x.strip() for x in tested_distros.split('\\n')]:
404 if fnmatch(distro, supported):
405 return
406
407 bb.warn('Host distribution "%s" has not been validated with this version of the build system; you may possibly experience unexpected failures. It is recommended that you use a tested distribution.' % distro)
408
409# Checks we should only make if MACHINE is set correctly
410def check_sanity_validmachine(sanity_data):
411 messages = ""
412
413 # Check TUNE_ARCH is set
414 if sanity_data.getVar('TUNE_ARCH', True) == 'INVALID':
415 messages = messages + 'TUNE_ARCH is unset. Please ensure your MACHINE configuration includes a valid tune configuration file which will set this correctly.\n'
416
417 # Check TARGET_OS is set
418 if sanity_data.getVar('TARGET_OS', True) == 'INVALID':
419 messages = messages + 'Please set TARGET_OS directly, or choose a MACHINE or DISTRO that does so.\n'
420
421 # Check that we don't have duplicate entries in PACKAGE_ARCHS & that TUNE_PKGARCH is in PACKAGE_ARCHS
422 pkgarchs = sanity_data.getVar('PACKAGE_ARCHS', True)
423 tunepkg = sanity_data.getVar('TUNE_PKGARCH', True)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500424 defaulttune = sanity_data.getVar('DEFAULTTUNE', True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500425 tunefound = False
426 seen = {}
427 dups = []
428
429 for pa in pkgarchs.split():
430 if seen.get(pa, 0) == 1:
431 dups.append(pa)
432 else:
433 seen[pa] = 1
434 if pa == tunepkg:
435 tunefound = True
436
437 if len(dups):
438 messages = messages + "Error, the PACKAGE_ARCHS variable contains duplicates. The following archs are listed more than once: %s" % " ".join(dups)
439
440 if tunefound == False:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500441 messages = messages + "Error, the PACKAGE_ARCHS variable (%s) for DEFAULTTUNE (%s) does not contain TUNE_PKGARCH (%s)." % (pkgarchs, defaulttune, tunepkg)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500442
443 return messages
444
445# Checks if necessary to add option march to host gcc
446def check_gcc_march(sanity_data):
447 result = True
448 message = ""
449
450 # Check if -march not in BUILD_CFLAGS
451 if sanity_data.getVar("BUILD_CFLAGS",True).find("-march") < 0:
452 result = False
453
454 # Construct a test file
455 f = open("gcc_test.c", "w")
456 f.write("int main (){ volatile int atomic = 2; __sync_bool_compare_and_swap (&atomic, 2, 3); return 0; }\n")
457 f.close()
458
459 # Check if GCC could work without march
460 if not result:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600461 status,res = oe.utils.getstatusoutput(sanity_data.expand("${BUILD_CC} gcc_test.c -o gcc_test"))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500462 if status == 0:
463 result = True;
464
465 if not result:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600466 status,res = oe.utils.getstatusoutput(sanity_data.expand("${BUILD_CC} -march=native gcc_test.c -o gcc_test"))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500467 if status == 0:
468 message = "BUILD_CFLAGS_append = \" -march=native\""
469 result = True;
470
471 if not result:
472 build_arch = sanity_data.getVar('BUILD_ARCH', True)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600473 status,res = oe.utils.getstatusoutput(sanity_data.expand("${BUILD_CC} -march=%s gcc_test.c -o gcc_test" % build_arch))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500474 if status == 0:
475 message = "BUILD_CFLAGS_append = \" -march=%s\"" % build_arch
476 result = True;
477
478 os.remove("gcc_test.c")
479 if os.path.exists("gcc_test"):
480 os.remove("gcc_test")
481
482 return (result, message)
483
484# Unpatched versions of make 3.82 are known to be broken. See GNU Savannah Bug 30612.
485# Use a modified reproducer from http://savannah.gnu.org/bugs/?30612 to validate.
486def check_make_version(sanity_data):
487 from distutils.version import LooseVersion
488 status, result = oe.utils.getstatusoutput("make --version")
489 if status != 0:
490 return "Unable to execute make --version, exit code %s\n" % status
491 version = result.split()[2]
492 if LooseVersion(version) == LooseVersion("3.82"):
493 # Construct a test file
494 f = open("makefile_test", "w")
495 f.write("makefile_test.a: makefile_test_a.c makefile_test_b.c makefile_test.a( makefile_test_a.c makefile_test_b.c)\n")
496 f.write("\n")
497 f.write("makefile_test_a.c:\n")
498 f.write(" touch $@\n")
499 f.write("\n")
500 f.write("makefile_test_b.c:\n")
501 f.write(" touch $@\n")
502 f.close()
503
504 # Check if make 3.82 has been patched
505 status,result = oe.utils.getstatusoutput("make -f makefile_test")
506
507 os.remove("makefile_test")
508 if os.path.exists("makefile_test_a.c"):
509 os.remove("makefile_test_a.c")
510 if os.path.exists("makefile_test_b.c"):
511 os.remove("makefile_test_b.c")
512 if os.path.exists("makefile_test.a"):
513 os.remove("makefile_test.a")
514
515 if status != 0:
516 return "Your version of make 3.82 is broken. Please revert to 3.81 or install a patched version.\n"
517 return None
518
519
520# Tar version 1.24 and onwards handle overwriting symlinks correctly
521# but earlier versions do not; this needs to work properly for sstate
522def check_tar_version(sanity_data):
523 from distutils.version import LooseVersion
524 status, result = oe.utils.getstatusoutput("tar --version")
525 if status != 0:
526 return "Unable to execute tar --version, exit code %s\n" % status
527 version = result.split()[3]
528 if LooseVersion(version) < LooseVersion("1.24"):
529 return "Your version of tar is older than 1.24 and has bugs which will break builds. Please install a newer version of tar.\n"
530 return None
531
532# We use git parameters and functionality only found in 1.7.8 or later
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500533# The kernel tools assume git >= 1.8.3.1 (verified needed > 1.7.9.5) see #6162
534# The git fetcher also had workarounds for git < 1.7.9.2 which we've dropped
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500535def check_git_version(sanity_data):
536 from distutils.version import LooseVersion
537 status, result = oe.utils.getstatusoutput("git --version 2> /dev/null")
538 if status != 0:
539 return "Unable to execute git --version, exit code %s\n" % status
540 version = result.split()[2]
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500541 if LooseVersion(version) < LooseVersion("1.8.3.1"):
542 return "Your version of git is older than 1.8.3.1 and has bugs which will break builds. Please install a newer version of git.\n"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500543 return None
544
545# Check the required perl modules which may not be installed by default
546def check_perl_modules(sanity_data):
547 ret = ""
548 modules = ( "Text::ParseWords", "Thread::Queue", "Data::Dumper" )
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500549 errresult = ''
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500550 for m in modules:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500551 status, result = oe.utils.getstatusoutput("perl -e 'use %s'" % m)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500552 if status != 0:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500553 errresult += result
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500554 ret += "%s " % m
555 if ret:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500556 return "Required perl module(s) not found: %s\n\n%s\n" % (ret, errresult)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500557 return None
558
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600559def sanity_check_conffiles(d):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500560 funcs = d.getVar('BBLAYERS_CONF_UPDATE_FUNCS', True).split()
561 for func in funcs:
562 conffile, current_version, required_version, func = func.split(":")
563 if check_conf_exists(conffile, d) and d.getVar(current_version, True) is not None and \
564 d.getVar(current_version, True) != d.getVar(required_version, True):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500565 try:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500566 bb.build.exec_func(func, d, pythonexception=True)
567 except NotImplementedError as e:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600568 bb.fatal(e)
569 d.setVar("BB_INVALIDCONF", True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500570
571def sanity_handle_abichanges(status, d):
572 #
573 # Check the 'ABI' of TMPDIR
574 #
575 import subprocess
576
577 current_abi = d.getVar('OELAYOUT_ABI', True)
578 abifile = d.getVar('SANITY_ABIFILE', True)
579 if os.path.exists(abifile):
580 with open(abifile, "r") as f:
581 abi = f.read().strip()
582 if not abi.isdigit():
583 with open(abifile, "w") as f:
584 f.write(current_abi)
585 elif abi == "2" and current_abi == "3":
586 bb.note("Converting staging from layout version 2 to layout version 3")
587 subprocess.call(d.expand("mv ${TMPDIR}/staging ${TMPDIR}/sysroots"), shell=True)
588 subprocess.call(d.expand("ln -s sysroots ${TMPDIR}/staging"), shell=True)
589 subprocess.call(d.expand("cd ${TMPDIR}/stamps; for i in */*do_populate_staging; do new=`echo $i | sed -e 's/do_populate_staging/do_populate_sysroot/'`; mv $i $new; done"), shell=True)
590 with open(abifile, "w") as f:
591 f.write(current_abi)
592 elif abi == "3" and current_abi == "4":
593 bb.note("Converting staging layout from version 3 to layout version 4")
594 if os.path.exists(d.expand("${STAGING_DIR_NATIVE}${bindir_native}/${MULTIMACH_HOST_SYS}")):
595 subprocess.call(d.expand("mv ${STAGING_DIR_NATIVE}${bindir_native}/${MULTIMACH_HOST_SYS} ${STAGING_BINDIR_CROSS}"), shell=True)
596 subprocess.call(d.expand("ln -s ${STAGING_BINDIR_CROSS} ${STAGING_DIR_NATIVE}${bindir_native}/${MULTIMACH_HOST_SYS}"), shell=True)
597 with open(abifile, "w") as f:
598 f.write(current_abi)
599 elif abi == "4":
600 status.addresult("Staging layout has changed. The cross directory has been deprecated and cross packages are now built under the native sysroot.\nThis requires a rebuild.\n")
601 elif abi == "5" and current_abi == "6":
602 bb.note("Converting staging layout from version 5 to layout version 6")
603 subprocess.call(d.expand("mv ${TMPDIR}/pstagelogs ${SSTATE_MANIFESTS}"), shell=True)
604 with open(abifile, "w") as f:
605 f.write(current_abi)
606 elif abi == "7" and current_abi == "8":
607 status.addresult("Your configuration is using stamp files including the sstate hash but your build directory was built with stamp files that do not include this.\nTo continue, either rebuild or switch back to the OEBasic signature handler with BB_SIGNATURE_HANDLER = 'OEBasic'.\n")
608 elif (abi != current_abi and current_abi == "9"):
609 status.addresult("The layout of the TMPDIR STAMPS directory has changed. Please clean out TMPDIR and rebuild (sstate will be still be valid and reused)\n")
610 elif (abi != current_abi and current_abi == "10" and (abi == "8" or abi == "9")):
611 bb.note("Converting staging layout from version 8/9 to layout version 10")
612 cmd = d.expand("grep -r -l sysroot-providers/virtual_kernel ${SSTATE_MANIFESTS}")
613 ret, result = oe.utils.getstatusoutput(cmd)
614 result = result.split()
615 for f in result:
616 bb.note("Uninstalling manifest file %s" % f)
617 sstate_clean_manifest(f, d)
618 with open(abifile, "w") as f:
619 f.write(current_abi)
620 elif abi == "10" and current_abi == "11":
621 bb.note("Converting staging layout from version 10 to layout version 11")
622 # Files in xf86-video-modesetting moved to xserver-xorg and bitbake can't currently handle that:
623 subprocess.call(d.expand("rm ${TMPDIR}/sysroots/*/usr/lib/xorg/modules/drivers/modesetting_drv.so ${TMPDIR}/sysroots/*/pkgdata/runtime/xf86-video-modesetting* ${TMPDIR}/sysroots/*/pkgdata/runtime-reverse/xf86-video-modesetting* ${TMPDIR}/sysroots/*/pkgdata/shlibs2/xf86-video-modesetting*"), shell=True)
624 with open(abifile, "w") as f:
625 f.write(current_abi)
626 elif (abi != current_abi):
627 # Code to convert from one ABI to another could go here if possible.
628 status.addresult("Error, TMPDIR has changed its layout version number (%s to %s) and you need to either rebuild, revert or adjust it at your own risk.\n" % (abi, current_abi))
629 else:
630 with open(abifile, "w") as f:
631 f.write(current_abi)
632
633def check_sanity_sstate_dir_change(sstate_dir, data):
634 # Sanity checks to be done when the value of SSTATE_DIR changes
635
636 # Check that SSTATE_DIR isn't on a filesystem with limited filename length (eg. eCryptFS)
637 testmsg = ""
638 if sstate_dir != "":
639 testmsg = check_create_long_filename(sstate_dir, "SSTATE_DIR")
640 # If we don't have permissions to SSTATE_DIR, suggest the user set it as an SSTATE_MIRRORS
641 try:
642 err = testmsg.split(': ')[1].strip()
643 if err == "Permission denied.":
644 testmsg = testmsg + "You could try using %s in SSTATE_MIRRORS rather than as an SSTATE_CACHE.\n" % (sstate_dir)
645 except IndexError:
646 pass
647 return testmsg
648
649def check_sanity_version_change(status, d):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500650 # Sanity checks to be done when SANITY_VERSION or NATIVELSBSTRING changes
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500651 # In other words, these tests run once in a given build directory and then
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500652 # never again until the sanity version or host distrubution id/version changes.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500653
654 # Check the python install is complete. glib-2.0-natives requries
655 # xml.parsers.expat
656 try:
657 import xml.parsers.expat
658 except ImportError:
659 status.addresult('Your python is not a full install. Please install the module xml.parsers.expat (python-xml on openSUSE and SUSE Linux).\n')
660 import stat
661
662 status.addresult(check_make_version(d))
663 status.addresult(check_tar_version(d))
664 status.addresult(check_git_version(d))
665 status.addresult(check_perl_modules(d))
666
667 missing = ""
668
669 if not check_app_exists("${MAKE}", d):
670 missing = missing + "GNU make,"
671
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600672 if not check_app_exists('${BUILD_CC}', d):
673 missing = missing + "C Compiler (%s)," % d.getVar("BUILD_CC", True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500674
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600675 if not check_app_exists('${BUILD_CXX}', d):
676 missing = missing + "C++ Compiler (%s)," % d.getVar("BUILD_CXX", True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500677
678 required_utilities = d.getVar('SANITY_REQUIRED_UTILITIES', True)
679
680 for util in required_utilities.split():
681 if not check_app_exists(util, d):
682 missing = missing + "%s," % util
683
684 if missing:
685 missing = missing.rstrip(',')
686 status.addresult("Please install the following missing utilities: %s\n" % missing)
687
688 assume_provided = d.getVar('ASSUME_PROVIDED', True).split()
689 # Check user doesn't have ASSUME_PROVIDED = instead of += in local.conf
690 if "diffstat-native" not in assume_provided:
691 status.addresult('Please use ASSUME_PROVIDED +=, not ASSUME_PROVIDED = in your local.conf\n')
692
693 if "qemu-native" in assume_provided:
694 if not check_app_exists("qemu-arm", d):
695 status.addresult("qemu-native was in ASSUME_PROVIDED but the QEMU binaries (qemu-arm) can't be found in PATH")
696
697 if "libsdl-native" in assume_provided:
698 if not check_app_exists("sdl-config", d):
699 status.addresult("libsdl-native is set to be ASSUME_PROVIDED but sdl-config can't be found in PATH. Please either install it, or configure qemu not to require sdl.")
700
701 (result, message) = check_gcc_march(d)
702 if result and message:
703 status.addresult("Your gcc version is older than 4.5, please add the following param to local.conf\n \
704 %s\n" % message)
705 if not result:
706 status.addresult("Your gcc version is older than 4.5 or is not working properly. Please verify you can build")
707 status.addresult(" and link something that uses atomic operations, such as: \n")
708 status.addresult(" __sync_bool_compare_and_swap (&atomic, 2, 3);\n")
709
710 # Check that TMPDIR isn't on a filesystem with limited filename length (eg. eCryptFS)
711 tmpdir = d.getVar('TMPDIR', True)
712 status.addresult(check_create_long_filename(tmpdir, "TMPDIR"))
713 tmpdirmode = os.stat(tmpdir).st_mode
714 if (tmpdirmode & stat.S_ISGID):
715 status.addresult("TMPDIR is setgid, please don't build in a setgid directory")
716 if (tmpdirmode & stat.S_ISUID):
717 status.addresult("TMPDIR is setuid, please don't build in a setuid directory")
718
719 # Some third-party software apparently relies on chmod etc. being suid root (!!)
720 import stat
721 suid_check_bins = "chown chmod mknod".split()
722 for bin_cmd in suid_check_bins:
723 bin_path = bb.utils.which(os.environ["PATH"], bin_cmd)
724 if bin_path:
725 bin_stat = os.stat(bin_path)
726 if bin_stat.st_uid == 0 and bin_stat.st_mode & stat.S_ISUID:
727 status.addresult('%s has the setuid bit set. This interferes with pseudo and may cause other issues that break the build process.\n' % bin_path)
728
729 # Check that we can fetch from various network transports
730 netcheck = check_connectivity(d)
731 status.addresult(netcheck)
732 if netcheck:
733 status.network_error = True
734
735 nolibs = d.getVar('NO32LIBS', True)
736 if not nolibs:
737 lib32path = '/lib'
738 if os.path.exists('/lib64') and ( os.path.islink('/lib64') or os.path.islink('/lib') ):
739 lib32path = '/lib32'
740
741 if os.path.exists('%s/libc.so.6' % lib32path) and not os.path.exists('/usr/include/gnu/stubs-32.h'):
742 status.addresult("You have a 32-bit libc, but no 32-bit headers. You must install the 32-bit libc headers.\n")
743
744 bbpaths = d.getVar('BBPATH', True).split(":")
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600745 if ("." in bbpaths or "./" in bbpaths or "" in bbpaths):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500746 status.addresult("BBPATH references the current directory, either through " \
747 "an empty entry, a './' or a '.'.\n\t This is unsafe and means your "\
748 "layer configuration is adding empty elements to BBPATH.\n\t "\
749 "Please check your layer.conf files and other BBPATH " \
750 "settings to remove the current working directory " \
751 "references.\n" \
752 "Parsed BBPATH is" + str(bbpaths));
753
754 oes_bb_conf = d.getVar( 'OES_BITBAKE_CONF', True)
755 if not oes_bb_conf:
756 status.addresult('You are not using the OpenEmbedded version of conf/bitbake.conf. This means your environment is misconfigured, in particular check BBPATH.\n')
757
758 # The length of TMPDIR can't be longer than 410
759 status.addresult(check_path_length(tmpdir, "TMPDIR", 410))
760
761 # Check that TMPDIR isn't located on nfs
762 status.addresult(check_not_nfs(tmpdir, "TMPDIR"))
763
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600764def sanity_check_locale(d):
765 """
766 Currently bitbake switches locale to en_US.UTF-8 so check that this locale actually exists.
767 """
768 import locale
769 try:
770 locale.setlocale(locale.LC_ALL, "en_US.UTF-8")
771 except locale.Error:
772 raise_sanity_error("You system needs to support the en_US.UTF-8 locale.", d)
773
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500774def check_sanity_everybuild(status, d):
775 import os, stat
776 # Sanity tests which test the users environment so need to run at each build (or are so cheap
777 # it makes sense to always run them.
778
779 if 0 == os.getuid():
780 raise_sanity_error("Do not use Bitbake as root.", d)
781
782 # Check the Python version, we now have a minimum of Python 2.7.3
783 import sys
784 if sys.hexversion < 0x020703F0:
785 status.addresult('The system requires at least Python 2.7.3 to run. Please update your Python interpreter.\n')
786
787 # Check the bitbake version meets minimum requirements
788 from distutils.version import LooseVersion
789 minversion = d.getVar('BB_MIN_VERSION', True)
790 if (LooseVersion(bb.__version__) < LooseVersion(minversion)):
791 status.addresult('Bitbake version %s is required and version %s was found\n' % (minversion, bb.__version__))
792
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600793 sanity_check_locale(d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500794
795 paths = d.getVar('PATH', True).split(":")
796 if "." in paths or "./" in paths or "" in paths:
797 status.addresult("PATH contains '.', './' or '' (empty element), which will break the build, please remove this.\nParsed PATH is " + str(paths) + "\n")
798
799 # Check that the DISTRO is valid, if set
800 # need to take into account DISTRO renaming DISTRO
801 distro = d.getVar('DISTRO', True)
802 if distro and distro != "nodistro":
803 if not ( check_conf_exists("conf/distro/${DISTRO}.conf", d) or check_conf_exists("conf/distro/include/${DISTRO}.inc", d) ):
804 status.addresult("DISTRO '%s' not found. Please set a valid DISTRO in your local.conf\n" % d.getVar("DISTRO", True))
805
806 # Check that DL_DIR is set, exists and is writable. In theory, we should never even hit the check if DL_DIR isn't
807 # set, since so much relies on it being set.
808 dldir = d.getVar('DL_DIR', True)
809 if not dldir:
810 status.addresult("DL_DIR is not set. Your environment is misconfigured, check that DL_DIR is set, and if the directory exists, that it is writable. \n")
811 if os.path.exists(dldir) and not os.access(dldir, os.W_OK):
812 status.addresult("DL_DIR: %s exists but you do not appear to have write access to it. \n" % dldir)
813 check_symlink(dldir, d)
814
815 # Check that the MACHINE is valid, if it is set
816 machinevalid = True
817 if d.getVar('MACHINE', True):
818 if not check_conf_exists("conf/machine/${MACHINE}.conf", d):
819 status.addresult('Please set a valid MACHINE in your local.conf or environment\n')
820 machinevalid = False
821 else:
822 status.addresult(check_sanity_validmachine(d))
823 else:
824 status.addresult('Please set a MACHINE in your local.conf or environment\n')
825 machinevalid = False
826 if machinevalid:
827 status.addresult(check_toolchain(d))
828
829 # Check that the SDKMACHINE is valid, if it is set
830 if d.getVar('SDKMACHINE', True):
831 if not check_conf_exists("conf/machine-sdk/${SDKMACHINE}.conf", d):
832 status.addresult('Specified SDKMACHINE value is not valid\n')
833 elif d.getVar('SDK_ARCH', False) == "${BUILD_ARCH}":
834 status.addresult('SDKMACHINE is set, but SDK_ARCH has not been changed as a result - SDKMACHINE may have been set too late (e.g. in the distro configuration)\n')
835
836 check_supported_distro(d)
837
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600838 omask = os.umask(0o022)
839 if omask & 0o755:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500840 status.addresult("Please use a umask which allows a+rx and u+rwx\n")
841 os.umask(omask)
842
843 if d.getVar('TARGET_ARCH', True) == "arm":
844 # This path is no longer user-readable in modern (very recent) Linux
845 try:
846 if os.path.exists("/proc/sys/vm/mmap_min_addr"):
847 f = open("/proc/sys/vm/mmap_min_addr", "r")
848 try:
849 if (int(f.read().strip()) > 65536):
850 status.addresult("/proc/sys/vm/mmap_min_addr is not <= 65536. This will cause problems with qemu so please fix the value (as root).\n\nTo fix this in later reboots, set vm.mmap_min_addr = 65536 in /etc/sysctl.conf.\n")
851 finally:
852 f.close()
853 except:
854 pass
855
856 oeroot = d.getVar('COREBASE', True)
857 if oeroot.find('+') != -1:
858 status.addresult("Error, you have an invalid character (+) in your COREBASE directory path. Please move the installation to a directory which doesn't include any + characters.")
859 if oeroot.find('@') != -1:
860 status.addresult("Error, you have an invalid character (@) in your COREBASE directory path. Please move the installation to a directory which doesn't include any @ characters.")
861 if oeroot.find(' ') != -1:
862 status.addresult("Error, you have a space in your COREBASE directory path. Please move the installation to a directory which doesn't include a space since autotools doesn't support this.")
863
864 # Check the format of MIRRORS, PREMIRRORS and SSTATE_MIRRORS
865 import re
866 mirror_vars = ['MIRRORS', 'PREMIRRORS', 'SSTATE_MIRRORS']
867 protocols = ['http', 'ftp', 'file', 'https', \
868 'git', 'gitsm', 'hg', 'osc', 'p4', 'svn', \
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500869 'bzr', 'cvs', 'npm', 'sftp', 'ssh']
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500870 for mirror_var in mirror_vars:
871 mirrors = (d.getVar(mirror_var, True) or '').replace('\\n', '\n').split('\n')
872 for mirror_entry in mirrors:
873 mirror_entry = mirror_entry.strip()
874 if not mirror_entry:
875 # ignore blank lines
876 continue
877
878 try:
879 pattern, mirror = mirror_entry.split()
880 except ValueError:
881 bb.warn('Invalid %s: %s, should be 2 members.' % (mirror_var, mirror_entry.strip()))
882 continue
883
884 decoded = bb.fetch2.decodeurl(pattern)
885 try:
886 pattern_scheme = re.compile(decoded[0])
887 except re.error as exc:
888 bb.warn('Invalid scheme regex (%s) in %s; %s' % (pattern, mirror_var, mirror_entry))
889 continue
890
891 if not any(pattern_scheme.match(protocol) for protocol in protocols):
892 bb.warn('Invalid protocol (%s) in %s: %s' % (decoded[0], mirror_var, mirror_entry))
893 continue
894
895 if not any(mirror.startswith(protocol + '://') for protocol in protocols):
896 bb.warn('Invalid protocol in %s: %s' % (mirror_var, mirror_entry))
897 continue
898
899 if mirror.startswith('file://'):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600900 import urllib
901 check_symlink(urllib.parse.urlparse(mirror).path, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500902 # SSTATE_MIRROR ends with a /PATH string
903 if mirror.endswith('/PATH'):
904 # remove /PATH$ from SSTATE_MIRROR to get a working
905 # base directory path
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600906 mirror_base = urllib.parse.urlparse(mirror[:-1*len('/PATH')]).path
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500907 check_symlink(mirror_base, d)
908
909 # Check that TMPDIR hasn't changed location since the last time we were run
910 tmpdir = d.getVar('TMPDIR', True)
911 checkfile = os.path.join(tmpdir, "saved_tmpdir")
912 if os.path.exists(checkfile):
913 with open(checkfile, "r") as f:
914 saved_tmpdir = f.read().strip()
915 if (saved_tmpdir != tmpdir):
916 status.addresult("Error, TMPDIR has changed location. You need to either move it back to %s or rebuild\n" % saved_tmpdir)
917 else:
918 bb.utils.mkdirhier(tmpdir)
919 # Remove setuid, setgid and sticky bits from TMPDIR
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500920 try:
921 os.chmod(tmpdir, os.stat(tmpdir).st_mode & ~ stat.S_ISUID)
922 os.chmod(tmpdir, os.stat(tmpdir).st_mode & ~ stat.S_ISGID)
923 os.chmod(tmpdir, os.stat(tmpdir).st_mode & ~ stat.S_ISVTX)
924 except OSError as exc:
925 bb.warn("Unable to chmod TMPDIR: %s" % exc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500926 with open(checkfile, "w") as f:
927 f.write(tmpdir)
928
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600929 # If /bin/sh is a symlink, check that it points to dash or bash
930 if os.path.islink('/bin/sh'):
931 real_sh = os.path.realpath('/bin/sh')
932 if not real_sh.endswith('/dash') and not real_sh.endswith('/bash'):
933 status.addresult("Error, /bin/sh links to %s, must be dash or bash\n" % real_sh)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500934
935def check_sanity(sanity_data):
936 class SanityStatus(object):
937 def __init__(self):
938 self.messages = ""
939 self.network_error = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500940
941 def addresult(self, message):
942 if message:
943 self.messages = self.messages + message
944
945 status = SanityStatus()
946
947 tmpdir = sanity_data.getVar('TMPDIR', True)
948 sstate_dir = sanity_data.getVar('SSTATE_DIR', True)
949
950 check_symlink(sstate_dir, sanity_data)
951
952 # Check saved sanity info
953 last_sanity_version = 0
954 last_tmpdir = ""
955 last_sstate_dir = ""
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500956 last_nativelsbstr = ""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500957 sanityverfile = sanity_data.expand("${TOPDIR}/conf/sanity_info")
958 if os.path.exists(sanityverfile):
959 with open(sanityverfile, 'r') as f:
960 for line in f:
961 if line.startswith('SANITY_VERSION'):
962 last_sanity_version = int(line.split()[1])
963 if line.startswith('TMPDIR'):
964 last_tmpdir = line.split()[1]
965 if line.startswith('SSTATE_DIR'):
966 last_sstate_dir = line.split()[1]
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500967 if line.startswith('NATIVELSBSTRING'):
968 last_nativelsbstr = line.split()[1]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500969
970 check_sanity_everybuild(status, sanity_data)
971
972 sanity_version = int(sanity_data.getVar('SANITY_VERSION', True) or 1)
973 network_error = False
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500974 # NATIVELSBSTRING var may have been overridden with "universal", so
975 # get actual host distribution id and version
976 nativelsbstr = lsb_distro_identifier(sanity_data)
977 if last_sanity_version < sanity_version or last_nativelsbstr != nativelsbstr:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500978 check_sanity_version_change(status, sanity_data)
979 status.addresult(check_sanity_sstate_dir_change(sstate_dir, sanity_data))
980 else:
981 if last_sstate_dir != sstate_dir:
982 status.addresult(check_sanity_sstate_dir_change(sstate_dir, sanity_data))
983
984 if os.path.exists(os.path.dirname(sanityverfile)) and not status.messages:
985 with open(sanityverfile, 'w') as f:
986 f.write("SANITY_VERSION %s\n" % sanity_version)
987 f.write("TMPDIR %s\n" % tmpdir)
988 f.write("SSTATE_DIR %s\n" % sstate_dir)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500989 f.write("NATIVELSBSTRING %s\n" % nativelsbstr)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500990
991 sanity_handle_abichanges(status, sanity_data)
992
993 if status.messages != "":
994 raise_sanity_error(sanity_data.expand(status.messages), sanity_data, status.network_error)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500995
996# Create a copy of the datastore and finalise it to ensure appends and
997# overrides are set - the datastore has yet to be finalised at ConfigParsed
998def copy_data(e):
999 sanity_data = bb.data.createCopy(e.data)
1000 sanity_data.finalize()
1001 return sanity_data
1002
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001003addhandler config_reparse_eventhandler
1004config_reparse_eventhandler[eventmask] = "bb.event.ConfigParsed"
1005python config_reparse_eventhandler() {
1006 sanity_check_conffiles(e.data)
1007}
1008
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001009addhandler check_sanity_eventhandler
1010check_sanity_eventhandler[eventmask] = "bb.event.SanityCheck bb.event.NetworkTest"
1011python check_sanity_eventhandler() {
1012 if bb.event.getName(e) == "SanityCheck":
1013 sanity_data = copy_data(e)
Patrick Williamsc0f7c042017-02-23 20:41:17 -06001014 check_sanity(sanity_data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001015 if e.generateevents:
1016 sanity_data.setVar("SANITY_USE_EVENTS", "1")
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001017 bb.event.fire(bb.event.SanityCheckPassed(), e.data)
1018 elif bb.event.getName(e) == "NetworkTest":
1019 sanity_data = copy_data(e)
1020 if e.generateevents:
1021 sanity_data.setVar("SANITY_USE_EVENTS", "1")
1022 bb.event.fire(bb.event.NetworkTestFailed() if check_connectivity(sanity_data) else bb.event.NetworkTestPassed(), e.data)
1023
1024 return
1025}