blob: e8064ac483dc0d394747816849942e339e52016a [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 \
Brad Bishop6e60e8b2018-02-01 10:27:11 -05006 gzip gawk chrpath wget cpio perl file which"
Patrick Williamsc124f4f2015-09-15 14:41:29 -05007
8def bblayers_conf_file(d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -05009 return os.path.join(d.getVar('TOPDIR'), 'conf/bblayers.conf')
Patrick Williamsc124f4f2015-09-15 14:41:29 -050010
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
Brad Bishop6e60e8b2018-02-01 10:27:11 -050042 current_conf = d.getVar('CONF_VERSION')
43 conf_version = d.getVar('LOCALCONF_VERSION')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050044
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
Brad Bishop6e60e8b2018-02-01 10:27:11 -050062 current_sconf = d.getVar('SCONF_VERSION')
63 sconf_version = d.getVar('SITE_CONF_VERSION')
Patrick Williamsd8c66bc2016-06-20 12:57:21 -050064
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
Brad Bishop6e60e8b2018-02-01 10:27:11 -050083 current_lconf = int(d.getVar('LCONF_VERSION'))
84 lconf_version = int(d.getVar('LAYER_CONF_VERSION'))
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.
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500144 layers = d.getVar('BBLAYERS').split()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500145 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):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500175 if d.getVar("SANITY_USE_EVENTS") == "1":
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500176 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):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500201 args_set = (data.getVar("TUNE_%s" % which) or "").split()
202 args_wanted = (data.getVar("TUNEABI_REQUIRED_%s_tune-%s" % (which, tune)) or "").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500203 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)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500229 bb.debug(2, "Sanity-checking tuning '%s' (%s) features:" % (tune, multilib))
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500230 features = (localdata.getVar("TUNE_FEATURES_tune-%s" % tune) or "").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500231 if not features:
232 return "Tuning '%s' has no defined features, and cannot be used." % tune
233 valid_tunes = localdata.getVarFlags('TUNEVALID') or {}
234 conflicts = localdata.getVarFlags('TUNECONFLICTS') or {}
235 # [doc] is the documentation for the variable, not a real feature
236 if 'doc' in valid_tunes:
237 del valid_tunes['doc']
238 if 'doc' in conflicts:
239 del conflicts['doc']
240 for feature in features:
241 if feature in conflicts:
242 for conflict in conflicts[feature].split():
243 if conflict in features:
244 tune_errors.append("Feature '%s' conflicts with '%s'." %
245 (feature, conflict))
246 if feature in valid_tunes:
247 bb.debug(2, " %s: %s" % (feature, valid_tunes[feature]))
248 else:
249 tune_errors.append("Feature '%s' is not defined." % feature)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500250 whitelist = localdata.getVar("TUNEABI_WHITELIST")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500251 if whitelist:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500252 tuneabi = localdata.getVar("TUNEABI_tune-%s" % tune)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500253 if not tuneabi:
254 tuneabi = tune
255 if True not in [x in whitelist.split() for x in tuneabi.split()]:
256 tune_errors.append("Tuning '%s' (%s) cannot be used with any supported tuning/ABI." %
257 (tune, tuneabi))
258 else:
259 if not check_toolchain_tune_args(localdata, tuneabi, multilib, tune_errors):
260 bb.debug(2, "Sanity check: Compiler args OK for %s." % tune)
261 if tune_errors:
262 return "Tuning '%s' has the following errors:\n" % tune + '\n'.join(tune_errors)
263
264def check_toolchain(data):
265 tune_error_set = []
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500266 deftune = data.getVar("DEFAULTTUNE")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500267 tune_errors = check_toolchain_tune(data, deftune, 'default')
268 if tune_errors:
269 tune_error_set.append(tune_errors)
270
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500271 multilibs = (data.getVar("MULTILIB_VARIANTS") or "").split()
272 global_multilibs = (data.getVar("MULTILIB_GLOBAL_VARIANTS") or "").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500273
274 if multilibs:
275 seen_libs = []
276 seen_tunes = []
277 for lib in multilibs:
278 if lib in seen_libs:
279 tune_error_set.append("The multilib '%s' appears more than once." % lib)
280 else:
281 seen_libs.append(lib)
282 if not lib in global_multilibs:
283 tune_error_set.append("Multilib %s is not present in MULTILIB_GLOBAL_VARIANTS" % lib)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500284 tune = data.getVar("DEFAULTTUNE_virtclass-multilib-%s" % lib)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500285 if tune in seen_tunes:
286 tune_error_set.append("The tuning '%s' appears in more than one multilib." % tune)
287 else:
288 seen_libs.append(tune)
289 if tune == deftune:
290 tune_error_set.append("Multilib '%s' (%s) is also the default tuning." % (lib, deftune))
291 else:
292 tune_errors = check_toolchain_tune(data, tune, lib)
293 if tune_errors:
294 tune_error_set.append(tune_errors)
295 if tune_error_set:
296 return "Toolchain tunings invalid:\n" + '\n'.join(tune_error_set) + "\n"
297
298 return ""
299
300def check_conf_exists(fn, data):
301 bbpath = []
302 fn = data.expand(fn)
303 vbbpath = data.getVar("BBPATH", False)
304 if vbbpath:
305 bbpath += vbbpath.split(":")
306 for p in bbpath:
307 currname = os.path.join(data.expand(p), fn)
308 if os.access(currname, os.R_OK):
309 return True
310 return False
311
312def check_create_long_filename(filepath, pathname):
313 import string, random
314 testfile = os.path.join(filepath, ''.join(random.choice(string.ascii_letters) for x in range(200)))
315 try:
316 if not os.path.exists(filepath):
317 bb.utils.mkdirhier(filepath)
318 f = open(testfile, "w")
319 f.close()
320 os.remove(testfile)
321 except IOError as e:
322 import errno
323 err, strerror = e.args
324 if err == errno.ENAMETOOLONG:
325 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
326 else:
327 return "Failed to create a file in %s: %s.\n" % (pathname, strerror)
328 except OSError as e:
329 errno, strerror = e.args
330 return "Failed to create %s directory in which to run long name sanity check: %s.\n" % (pathname, strerror)
331 return ""
332
333def check_path_length(filepath, pathname, limit):
334 if len(filepath) > limit:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500335 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 -0500336 return ""
337
338def get_filesystem_id(path):
339 status, result = oe.utils.getstatusoutput("stat -f -c '%s' %s" % ("%t", path))
340 if status == 0:
341 return result
342 else:
343 bb.warn("Can't get the filesystem id of: %s" % path)
344 return None
345
346# Check that the path isn't located on nfs.
347def check_not_nfs(path, name):
348 # The nfs' filesystem id is 6969
349 if get_filesystem_id(path) == "6969":
350 return "The %s: %s can't be located on nfs.\n" % (name, path)
351 return ""
352
353# Check that path isn't a broken symlink
354def check_symlink(lnk, data):
355 if os.path.islink(lnk) and not os.path.exists(lnk):
356 raise_sanity_error("%s is a broken symlink." % lnk, data)
357
358def check_connectivity(d):
359 # URI's to check can be set in the CONNECTIVITY_CHECK_URIS variable
360 # using the same syntax as for SRC_URI. If the variable is not set
361 # the check is skipped
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500362 test_uris = (d.getVar('CONNECTIVITY_CHECK_URIS') or "").split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500363 retval = ""
364
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500365 bbn = d.getVar('BB_NO_NETWORK')
366 if bbn not in (None, '0', '1'):
367 return 'BB_NO_NETWORK should be "0" or "1", but it is "%s"' % bbn
368
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500369 # Only check connectivity if network enabled and the
370 # CONNECTIVITY_CHECK_URIS are set
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500371 network_enabled = not (bbn == '1')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500372 check_enabled = len(test_uris)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500373 if check_enabled and network_enabled:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500374 # Take a copy of the data store and unset MIRRORS and PREMIRRORS
375 data = bb.data.createCopy(d)
376 data.delVar('PREMIRRORS')
377 data.delVar('MIRRORS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500378 try:
379 fetcher = bb.fetch2.Fetch(test_uris, data)
380 fetcher.checkstatus()
381 except Exception as err:
382 # Allow the message to be configured so that users can be
383 # pointed to a support mechanism.
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500384 msg = data.getVar('CONNECTIVITY_CHECK_MSG') or ""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500385 if len(msg) == 0:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500386 msg = "%s.\n" % err
387 msg += " Please ensure your host's network is configured correctly,\n"
388 msg += " or set BB_NO_NETWORK = \"1\" to disable network access if\n"
389 msg += " all required sources are on local disk.\n"
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500390 retval = msg
391
392 return retval
393
394def check_supported_distro(sanity_data):
395 from fnmatch import fnmatch
396
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500397 tested_distros = sanity_data.getVar('SANITY_TESTED_DISTROS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500398 if not tested_distros:
399 return
400
401 try:
402 distro = oe.lsb.distro_identifier()
403 except Exception:
404 distro = None
405
406 if not distro:
407 bb.warn('Host distribution could not be determined; you may possibly experience unexpected failures. It is recommended that you use a tested distribution.')
408
409 for supported in [x.strip() for x in tested_distros.split('\\n')]:
410 if fnmatch(distro, supported):
411 return
412
413 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)
414
415# Checks we should only make if MACHINE is set correctly
416def check_sanity_validmachine(sanity_data):
417 messages = ""
418
419 # Check TUNE_ARCH is set
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500420 if sanity_data.getVar('TUNE_ARCH') == 'INVALID':
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500421 messages = messages + 'TUNE_ARCH is unset. Please ensure your MACHINE configuration includes a valid tune configuration file which will set this correctly.\n'
422
423 # Check TARGET_OS is set
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500424 if sanity_data.getVar('TARGET_OS') == 'INVALID':
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500425 messages = messages + 'Please set TARGET_OS directly, or choose a MACHINE or DISTRO that does so.\n'
426
427 # Check that we don't have duplicate entries in PACKAGE_ARCHS & that TUNE_PKGARCH is in PACKAGE_ARCHS
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500428 pkgarchs = sanity_data.getVar('PACKAGE_ARCHS')
429 tunepkg = sanity_data.getVar('TUNE_PKGARCH')
430 defaulttune = sanity_data.getVar('DEFAULTTUNE')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500431 tunefound = False
432 seen = {}
433 dups = []
434
435 for pa in pkgarchs.split():
436 if seen.get(pa, 0) == 1:
437 dups.append(pa)
438 else:
439 seen[pa] = 1
440 if pa == tunepkg:
441 tunefound = True
442
443 if len(dups):
444 messages = messages + "Error, the PACKAGE_ARCHS variable contains duplicates. The following archs are listed more than once: %s" % " ".join(dups)
445
446 if tunefound == False:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500447 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 -0500448
449 return messages
450
451# Checks if necessary to add option march to host gcc
452def check_gcc_march(sanity_data):
453 result = True
454 message = ""
455
456 # Check if -march not in BUILD_CFLAGS
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500457 if sanity_data.getVar("BUILD_CFLAGS").find("-march") < 0:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500458 result = False
459
460 # Construct a test file
461 f = open("gcc_test.c", "w")
462 f.write("int main (){ volatile int atomic = 2; __sync_bool_compare_and_swap (&atomic, 2, 3); return 0; }\n")
463 f.close()
464
465 # Check if GCC could work without march
466 if not result:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600467 status,res = oe.utils.getstatusoutput(sanity_data.expand("${BUILD_CC} gcc_test.c -o gcc_test"))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500468 if status == 0:
469 result = True;
470
471 if not result:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600472 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 -0500473 if status == 0:
474 message = "BUILD_CFLAGS_append = \" -march=native\""
475 result = True;
476
477 if not result:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500478 build_arch = sanity_data.getVar('BUILD_ARCH')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600479 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 -0500480 if status == 0:
481 message = "BUILD_CFLAGS_append = \" -march=%s\"" % build_arch
482 result = True;
483
484 os.remove("gcc_test.c")
485 if os.path.exists("gcc_test"):
486 os.remove("gcc_test")
487
488 return (result, message)
489
490# Unpatched versions of make 3.82 are known to be broken. See GNU Savannah Bug 30612.
491# Use a modified reproducer from http://savannah.gnu.org/bugs/?30612 to validate.
492def check_make_version(sanity_data):
493 from distutils.version import LooseVersion
494 status, result = oe.utils.getstatusoutput("make --version")
495 if status != 0:
496 return "Unable to execute make --version, exit code %s\n" % status
497 version = result.split()[2]
498 if LooseVersion(version) == LooseVersion("3.82"):
499 # Construct a test file
500 f = open("makefile_test", "w")
501 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")
502 f.write("\n")
503 f.write("makefile_test_a.c:\n")
504 f.write(" touch $@\n")
505 f.write("\n")
506 f.write("makefile_test_b.c:\n")
507 f.write(" touch $@\n")
508 f.close()
509
510 # Check if make 3.82 has been patched
511 status,result = oe.utils.getstatusoutput("make -f makefile_test")
512
513 os.remove("makefile_test")
514 if os.path.exists("makefile_test_a.c"):
515 os.remove("makefile_test_a.c")
516 if os.path.exists("makefile_test_b.c"):
517 os.remove("makefile_test_b.c")
518 if os.path.exists("makefile_test.a"):
519 os.remove("makefile_test.a")
520
521 if status != 0:
522 return "Your version of make 3.82 is broken. Please revert to 3.81 or install a patched version.\n"
523 return None
524
525
526# Tar version 1.24 and onwards handle overwriting symlinks correctly
527# but earlier versions do not; this needs to work properly for sstate
528def check_tar_version(sanity_data):
529 from distutils.version import LooseVersion
530 status, result = oe.utils.getstatusoutput("tar --version")
531 if status != 0:
532 return "Unable to execute tar --version, exit code %s\n" % status
533 version = result.split()[3]
534 if LooseVersion(version) < LooseVersion("1.24"):
535 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"
536 return None
537
538# We use git parameters and functionality only found in 1.7.8 or later
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500539# The kernel tools assume git >= 1.8.3.1 (verified needed > 1.7.9.5) see #6162
540# The git fetcher also had workarounds for git < 1.7.9.2 which we've dropped
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500541def check_git_version(sanity_data):
542 from distutils.version import LooseVersion
543 status, result = oe.utils.getstatusoutput("git --version 2> /dev/null")
544 if status != 0:
545 return "Unable to execute git --version, exit code %s\n" % status
546 version = result.split()[2]
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500547 if LooseVersion(version) < LooseVersion("1.8.3.1"):
548 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 -0500549 return None
550
551# Check the required perl modules which may not be installed by default
552def check_perl_modules(sanity_data):
553 ret = ""
554 modules = ( "Text::ParseWords", "Thread::Queue", "Data::Dumper" )
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500555 errresult = ''
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500556 for m in modules:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500557 status, result = oe.utils.getstatusoutput("perl -e 'use %s'" % m)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500558 if status != 0:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500559 errresult += result
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500560 ret += "%s " % m
561 if ret:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500562 return "Required perl module(s) not found: %s\n\n%s\n" % (ret, errresult)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500563 return None
564
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600565def sanity_check_conffiles(d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500566 funcs = d.getVar('BBLAYERS_CONF_UPDATE_FUNCS').split()
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500567 for func in funcs:
568 conffile, current_version, required_version, func = func.split(":")
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500569 if check_conf_exists(conffile, d) and d.getVar(current_version) is not None and \
570 d.getVar(current_version) != d.getVar(required_version):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500571 try:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500572 bb.build.exec_func(func, d, pythonexception=True)
573 except NotImplementedError as e:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500574 bb.fatal(str(e))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600575 d.setVar("BB_INVALIDCONF", True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500576
577def sanity_handle_abichanges(status, d):
578 #
579 # Check the 'ABI' of TMPDIR
580 #
581 import subprocess
582
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500583 current_abi = d.getVar('OELAYOUT_ABI')
584 abifile = d.getVar('SANITY_ABIFILE')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500585 if os.path.exists(abifile):
586 with open(abifile, "r") as f:
587 abi = f.read().strip()
588 if not abi.isdigit():
589 with open(abifile, "w") as f:
590 f.write(current_abi)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500591 elif int(abi) <= 11 and current_abi == "12":
592 status.addresult("The layout of TMPDIR changed for Recipe Specific Sysroots.\nConversion doesn't make sense and this change will rebuild everything so please delete TMPDIR (%s).\n" % d.getVar("TMPDIR"))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500593 elif (abi != current_abi):
594 # Code to convert from one ABI to another could go here if possible.
595 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))
596 else:
597 with open(abifile, "w") as f:
598 f.write(current_abi)
599
600def check_sanity_sstate_dir_change(sstate_dir, data):
601 # Sanity checks to be done when the value of SSTATE_DIR changes
602
603 # Check that SSTATE_DIR isn't on a filesystem with limited filename length (eg. eCryptFS)
604 testmsg = ""
605 if sstate_dir != "":
606 testmsg = check_create_long_filename(sstate_dir, "SSTATE_DIR")
607 # If we don't have permissions to SSTATE_DIR, suggest the user set it as an SSTATE_MIRRORS
608 try:
609 err = testmsg.split(': ')[1].strip()
610 if err == "Permission denied.":
611 testmsg = testmsg + "You could try using %s in SSTATE_MIRRORS rather than as an SSTATE_CACHE.\n" % (sstate_dir)
612 except IndexError:
613 pass
614 return testmsg
615
616def check_sanity_version_change(status, d):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500617 # Sanity checks to be done when SANITY_VERSION or NATIVELSBSTRING changes
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500618 # In other words, these tests run once in a given build directory and then
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500619 # never again until the sanity version or host distrubution id/version changes.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500620
621 # Check the python install is complete. glib-2.0-natives requries
622 # xml.parsers.expat
623 try:
624 import xml.parsers.expat
625 except ImportError:
626 status.addresult('Your python is not a full install. Please install the module xml.parsers.expat (python-xml on openSUSE and SUSE Linux).\n')
627 import stat
628
629 status.addresult(check_make_version(d))
630 status.addresult(check_tar_version(d))
631 status.addresult(check_git_version(d))
632 status.addresult(check_perl_modules(d))
633
634 missing = ""
635
636 if not check_app_exists("${MAKE}", d):
637 missing = missing + "GNU make,"
638
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600639 if not check_app_exists('${BUILD_CC}', d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500640 missing = missing + "C Compiler (%s)," % d.getVar("BUILD_CC")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500641
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600642 if not check_app_exists('${BUILD_CXX}', d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500643 missing = missing + "C++ Compiler (%s)," % d.getVar("BUILD_CXX")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500644
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500645 required_utilities = d.getVar('SANITY_REQUIRED_UTILITIES')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500646
647 for util in required_utilities.split():
648 if not check_app_exists(util, d):
649 missing = missing + "%s," % util
650
651 if missing:
652 missing = missing.rstrip(',')
653 status.addresult("Please install the following missing utilities: %s\n" % missing)
654
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500655 assume_provided = d.getVar('ASSUME_PROVIDED').split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500656 # Check user doesn't have ASSUME_PROVIDED = instead of += in local.conf
657 if "diffstat-native" not in assume_provided:
658 status.addresult('Please use ASSUME_PROVIDED +=, not ASSUME_PROVIDED = in your local.conf\n')
659
660 if "qemu-native" in assume_provided:
661 if not check_app_exists("qemu-arm", d):
662 status.addresult("qemu-native was in ASSUME_PROVIDED but the QEMU binaries (qemu-arm) can't be found in PATH")
663
664 if "libsdl-native" in assume_provided:
665 if not check_app_exists("sdl-config", d):
666 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.")
667
668 (result, message) = check_gcc_march(d)
669 if result and message:
670 status.addresult("Your gcc version is older than 4.5, please add the following param to local.conf\n \
671 %s\n" % message)
672 if not result:
673 status.addresult("Your gcc version is older than 4.5 or is not working properly. Please verify you can build")
674 status.addresult(" and link something that uses atomic operations, such as: \n")
675 status.addresult(" __sync_bool_compare_and_swap (&atomic, 2, 3);\n")
676
677 # Check that TMPDIR isn't on a filesystem with limited filename length (eg. eCryptFS)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500678 tmpdir = d.getVar('TMPDIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500679 status.addresult(check_create_long_filename(tmpdir, "TMPDIR"))
680 tmpdirmode = os.stat(tmpdir).st_mode
681 if (tmpdirmode & stat.S_ISGID):
682 status.addresult("TMPDIR is setgid, please don't build in a setgid directory")
683 if (tmpdirmode & stat.S_ISUID):
684 status.addresult("TMPDIR is setuid, please don't build in a setuid directory")
685
686 # Some third-party software apparently relies on chmod etc. being suid root (!!)
687 import stat
688 suid_check_bins = "chown chmod mknod".split()
689 for bin_cmd in suid_check_bins:
690 bin_path = bb.utils.which(os.environ["PATH"], bin_cmd)
691 if bin_path:
692 bin_stat = os.stat(bin_path)
693 if bin_stat.st_uid == 0 and bin_stat.st_mode & stat.S_ISUID:
694 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)
695
696 # Check that we can fetch from various network transports
697 netcheck = check_connectivity(d)
698 status.addresult(netcheck)
699 if netcheck:
700 status.network_error = True
701
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500702 nolibs = d.getVar('NO32LIBS')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500703 if not nolibs:
704 lib32path = '/lib'
705 if os.path.exists('/lib64') and ( os.path.islink('/lib64') or os.path.islink('/lib') ):
706 lib32path = '/lib32'
707
708 if os.path.exists('%s/libc.so.6' % lib32path) and not os.path.exists('/usr/include/gnu/stubs-32.h'):
709 status.addresult("You have a 32-bit libc, but no 32-bit headers. You must install the 32-bit libc headers.\n")
710
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500711 bbpaths = d.getVar('BBPATH').split(":")
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600712 if ("." in bbpaths or "./" in bbpaths or "" in bbpaths):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500713 status.addresult("BBPATH references the current directory, either through " \
714 "an empty entry, a './' or a '.'.\n\t This is unsafe and means your "\
715 "layer configuration is adding empty elements to BBPATH.\n\t "\
716 "Please check your layer.conf files and other BBPATH " \
717 "settings to remove the current working directory " \
718 "references.\n" \
719 "Parsed BBPATH is" + str(bbpaths));
720
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500721 oes_bb_conf = d.getVar( 'OES_BITBAKE_CONF')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500722 if not oes_bb_conf:
723 status.addresult('You are not using the OpenEmbedded version of conf/bitbake.conf. This means your environment is misconfigured, in particular check BBPATH.\n')
724
725 # The length of TMPDIR can't be longer than 410
726 status.addresult(check_path_length(tmpdir, "TMPDIR", 410))
727
728 # Check that TMPDIR isn't located on nfs
729 status.addresult(check_not_nfs(tmpdir, "TMPDIR"))
730
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600731def sanity_check_locale(d):
732 """
733 Currently bitbake switches locale to en_US.UTF-8 so check that this locale actually exists.
734 """
735 import locale
736 try:
737 locale.setlocale(locale.LC_ALL, "en_US.UTF-8")
738 except locale.Error:
739 raise_sanity_error("You system needs to support the en_US.UTF-8 locale.", d)
740
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500741def check_sanity_everybuild(status, d):
742 import os, stat
743 # Sanity tests which test the users environment so need to run at each build (or are so cheap
744 # it makes sense to always run them.
745
746 if 0 == os.getuid():
747 raise_sanity_error("Do not use Bitbake as root.", d)
748
749 # Check the Python version, we now have a minimum of Python 2.7.3
750 import sys
751 if sys.hexversion < 0x020703F0:
752 status.addresult('The system requires at least Python 2.7.3 to run. Please update your Python interpreter.\n')
753
754 # Check the bitbake version meets minimum requirements
755 from distutils.version import LooseVersion
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500756 minversion = d.getVar('BB_MIN_VERSION')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500757 if (LooseVersion(bb.__version__) < LooseVersion(minversion)):
758 status.addresult('Bitbake version %s is required and version %s was found\n' % (minversion, bb.__version__))
759
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600760 sanity_check_locale(d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500761
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500762 paths = d.getVar('PATH').split(":")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500763 if "." in paths or "./" in paths or "" in paths:
764 status.addresult("PATH contains '.', './' or '' (empty element), which will break the build, please remove this.\nParsed PATH is " + str(paths) + "\n")
765
766 # Check that the DISTRO is valid, if set
767 # need to take into account DISTRO renaming DISTRO
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500768 distro = d.getVar('DISTRO')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500769 if distro and distro != "nodistro":
770 if not ( check_conf_exists("conf/distro/${DISTRO}.conf", d) or check_conf_exists("conf/distro/include/${DISTRO}.inc", d) ):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500771 status.addresult("DISTRO '%s' not found. Please set a valid DISTRO in your local.conf\n" % d.getVar("DISTRO"))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500772
773 # Check that DL_DIR is set, exists and is writable. In theory, we should never even hit the check if DL_DIR isn't
774 # set, since so much relies on it being set.
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500775 dldir = d.getVar('DL_DIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500776 if not dldir:
777 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")
778 if os.path.exists(dldir) and not os.access(dldir, os.W_OK):
779 status.addresult("DL_DIR: %s exists but you do not appear to have write access to it. \n" % dldir)
780 check_symlink(dldir, d)
781
782 # Check that the MACHINE is valid, if it is set
783 machinevalid = True
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500784 if d.getVar('MACHINE'):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500785 if not check_conf_exists("conf/machine/${MACHINE}.conf", d):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500786 status.addresult('MACHINE=%s is invalid. Please set a valid MACHINE in your local.conf, environment or other configuration file.\n' % (d.getVar('MACHINE')))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500787 machinevalid = False
788 else:
789 status.addresult(check_sanity_validmachine(d))
790 else:
791 status.addresult('Please set a MACHINE in your local.conf or environment\n')
792 machinevalid = False
793 if machinevalid:
794 status.addresult(check_toolchain(d))
795
796 # Check that the SDKMACHINE is valid, if it is set
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500797 if d.getVar('SDKMACHINE'):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500798 if not check_conf_exists("conf/machine-sdk/${SDKMACHINE}.conf", d):
799 status.addresult('Specified SDKMACHINE value is not valid\n')
800 elif d.getVar('SDK_ARCH', False) == "${BUILD_ARCH}":
801 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')
802
803 check_supported_distro(d)
804
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600805 omask = os.umask(0o022)
806 if omask & 0o755:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500807 status.addresult("Please use a umask which allows a+rx and u+rwx\n")
808 os.umask(omask)
809
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500810 if d.getVar('TARGET_ARCH') == "arm":
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500811 # This path is no longer user-readable in modern (very recent) Linux
812 try:
813 if os.path.exists("/proc/sys/vm/mmap_min_addr"):
814 f = open("/proc/sys/vm/mmap_min_addr", "r")
815 try:
816 if (int(f.read().strip()) > 65536):
817 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")
818 finally:
819 f.close()
820 except:
821 pass
822
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500823 oeroot = d.getVar('COREBASE')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500824 if oeroot.find('+') != -1:
825 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.")
826 if oeroot.find('@') != -1:
827 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.")
828 if oeroot.find(' ') != -1:
829 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.")
830
831 # Check the format of MIRRORS, PREMIRRORS and SSTATE_MIRRORS
832 import re
833 mirror_vars = ['MIRRORS', 'PREMIRRORS', 'SSTATE_MIRRORS']
834 protocols = ['http', 'ftp', 'file', 'https', \
835 'git', 'gitsm', 'hg', 'osc', 'p4', 'svn', \
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500836 'bzr', 'cvs', 'npm', 'sftp', 'ssh', 's3' ]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500837 for mirror_var in mirror_vars:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500838 mirrors = (d.getVar(mirror_var) or '').replace('\\n', ' ').split()
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500839
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500840 # Split into pairs
841 if len(mirrors) % 2 != 0:
842 bb.warn('Invalid mirror variable value for %s: %s, should contain paired members.' % (mirror_var, mirrors.strip()))
843 continue
844 mirrors = list(zip(*[iter(mirrors)]*2))
845
846 for mirror_entry in mirrors:
847 pattern, mirror = mirror_entry
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500848
849 decoded = bb.fetch2.decodeurl(pattern)
850 try:
851 pattern_scheme = re.compile(decoded[0])
852 except re.error as exc:
853 bb.warn('Invalid scheme regex (%s) in %s; %s' % (pattern, mirror_var, mirror_entry))
854 continue
855
856 if not any(pattern_scheme.match(protocol) for protocol in protocols):
857 bb.warn('Invalid protocol (%s) in %s: %s' % (decoded[0], mirror_var, mirror_entry))
858 continue
859
860 if not any(mirror.startswith(protocol + '://') for protocol in protocols):
861 bb.warn('Invalid protocol in %s: %s' % (mirror_var, mirror_entry))
862 continue
863
864 if mirror.startswith('file://'):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600865 import urllib
866 check_symlink(urllib.parse.urlparse(mirror).path, d)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500867 # SSTATE_MIRROR ends with a /PATH string
868 if mirror.endswith('/PATH'):
869 # remove /PATH$ from SSTATE_MIRROR to get a working
870 # base directory path
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600871 mirror_base = urllib.parse.urlparse(mirror[:-1*len('/PATH')]).path
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500872 check_symlink(mirror_base, d)
873
874 # Check that TMPDIR hasn't changed location since the last time we were run
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500875 tmpdir = d.getVar('TMPDIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500876 checkfile = os.path.join(tmpdir, "saved_tmpdir")
877 if os.path.exists(checkfile):
878 with open(checkfile, "r") as f:
879 saved_tmpdir = f.read().strip()
880 if (saved_tmpdir != tmpdir):
881 status.addresult("Error, TMPDIR has changed location. You need to either move it back to %s or rebuild\n" % saved_tmpdir)
882 else:
883 bb.utils.mkdirhier(tmpdir)
884 # Remove setuid, setgid and sticky bits from TMPDIR
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500885 try:
886 os.chmod(tmpdir, os.stat(tmpdir).st_mode & ~ stat.S_ISUID)
887 os.chmod(tmpdir, os.stat(tmpdir).st_mode & ~ stat.S_ISGID)
888 os.chmod(tmpdir, os.stat(tmpdir).st_mode & ~ stat.S_ISVTX)
889 except OSError as exc:
890 bb.warn("Unable to chmod TMPDIR: %s" % exc)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500891 with open(checkfile, "w") as f:
892 f.write(tmpdir)
893
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600894 # If /bin/sh is a symlink, check that it points to dash or bash
895 if os.path.islink('/bin/sh'):
896 real_sh = os.path.realpath('/bin/sh')
Brad Bishop37a0e4d2017-12-04 01:01:44 -0500897 # Due to update-alternatives, the shell name may take various
898 # forms, such as /bin/dash, bin/bash, /bin/bash.bash ...
899 if '/dash' not in real_sh and '/bash' not in real_sh:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600900 status.addresult("Error, /bin/sh links to %s, must be dash or bash\n" % real_sh)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500901
902def check_sanity(sanity_data):
903 class SanityStatus(object):
904 def __init__(self):
905 self.messages = ""
906 self.network_error = False
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500907
908 def addresult(self, message):
909 if message:
910 self.messages = self.messages + message
911
912 status = SanityStatus()
913
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500914 tmpdir = sanity_data.getVar('TMPDIR')
915 sstate_dir = sanity_data.getVar('SSTATE_DIR')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500916
917 check_symlink(sstate_dir, sanity_data)
918
919 # Check saved sanity info
920 last_sanity_version = 0
921 last_tmpdir = ""
922 last_sstate_dir = ""
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500923 last_nativelsbstr = ""
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500924 sanityverfile = sanity_data.expand("${TOPDIR}/conf/sanity_info")
925 if os.path.exists(sanityverfile):
926 with open(sanityverfile, 'r') as f:
927 for line in f:
928 if line.startswith('SANITY_VERSION'):
929 last_sanity_version = int(line.split()[1])
930 if line.startswith('TMPDIR'):
931 last_tmpdir = line.split()[1]
932 if line.startswith('SSTATE_DIR'):
933 last_sstate_dir = line.split()[1]
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500934 if line.startswith('NATIVELSBSTRING'):
935 last_nativelsbstr = line.split()[1]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500936
937 check_sanity_everybuild(status, sanity_data)
938
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500939 sanity_version = int(sanity_data.getVar('SANITY_VERSION') or 1)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500940 network_error = False
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500941 # NATIVELSBSTRING var may have been overridden with "universal", so
942 # get actual host distribution id and version
943 nativelsbstr = lsb_distro_identifier(sanity_data)
944 if last_sanity_version < sanity_version or last_nativelsbstr != nativelsbstr:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500945 check_sanity_version_change(status, sanity_data)
946 status.addresult(check_sanity_sstate_dir_change(sstate_dir, sanity_data))
947 else:
948 if last_sstate_dir != sstate_dir:
949 status.addresult(check_sanity_sstate_dir_change(sstate_dir, sanity_data))
950
951 if os.path.exists(os.path.dirname(sanityverfile)) and not status.messages:
952 with open(sanityverfile, 'w') as f:
953 f.write("SANITY_VERSION %s\n" % sanity_version)
954 f.write("TMPDIR %s\n" % tmpdir)
955 f.write("SSTATE_DIR %s\n" % sstate_dir)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500956 f.write("NATIVELSBSTRING %s\n" % nativelsbstr)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500957
958 sanity_handle_abichanges(status, sanity_data)
959
960 if status.messages != "":
961 raise_sanity_error(sanity_data.expand(status.messages), sanity_data, status.network_error)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500962
963# Create a copy of the datastore and finalise it to ensure appends and
964# overrides are set - the datastore has yet to be finalised at ConfigParsed
965def copy_data(e):
966 sanity_data = bb.data.createCopy(e.data)
967 sanity_data.finalize()
968 return sanity_data
969
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600970addhandler config_reparse_eventhandler
971config_reparse_eventhandler[eventmask] = "bb.event.ConfigParsed"
972python config_reparse_eventhandler() {
973 sanity_check_conffiles(e.data)
974}
975
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500976addhandler check_sanity_eventhandler
977check_sanity_eventhandler[eventmask] = "bb.event.SanityCheck bb.event.NetworkTest"
978python check_sanity_eventhandler() {
979 if bb.event.getName(e) == "SanityCheck":
980 sanity_data = copy_data(e)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600981 check_sanity(sanity_data)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500982 if e.generateevents:
983 sanity_data.setVar("SANITY_USE_EVENTS", "1")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500984 bb.event.fire(bb.event.SanityCheckPassed(), e.data)
985 elif bb.event.getName(e) == "NetworkTest":
986 sanity_data = copy_data(e)
987 if e.generateevents:
988 sanity_data.setVar("SANITY_USE_EVENTS", "1")
989 bb.event.fire(bb.event.NetworkTestFailed() if check_connectivity(sanity_data) else bb.event.NetworkTestPassed(), e.data)
990
991 return
992}