1*4882a593Smuzhiyun# 2*4882a593Smuzhiyun# Sanity check the users setup for common misconfigurations 3*4882a593Smuzhiyun# 4*4882a593Smuzhiyun 5*4882a593SmuzhiyunSANITY_REQUIRED_UTILITIES ?= "patch diffstat git bzip2 tar \ 6*4882a593Smuzhiyun gzip gawk chrpath wget cpio perl file which" 7*4882a593Smuzhiyun 8*4882a593Smuzhiyundef bblayers_conf_file(d): 9*4882a593Smuzhiyun return os.path.join(d.getVar('TOPDIR'), 'conf/bblayers.conf') 10*4882a593Smuzhiyun 11*4882a593Smuzhiyundef sanity_conf_read(fn): 12*4882a593Smuzhiyun with open(fn, 'r') as f: 13*4882a593Smuzhiyun lines = f.readlines() 14*4882a593Smuzhiyun return lines 15*4882a593Smuzhiyun 16*4882a593Smuzhiyundef sanity_conf_find_line(pattern, lines): 17*4882a593Smuzhiyun import re 18*4882a593Smuzhiyun return next(((index, line) 19*4882a593Smuzhiyun for index, line in enumerate(lines) 20*4882a593Smuzhiyun if re.search(pattern, line)), (None, None)) 21*4882a593Smuzhiyun 22*4882a593Smuzhiyundef sanity_conf_update(fn, lines, version_var_name, new_version): 23*4882a593Smuzhiyun index, line = sanity_conf_find_line(r"^%s" % version_var_name, lines) 24*4882a593Smuzhiyun lines[index] = '%s = "%d"\n' % (version_var_name, new_version) 25*4882a593Smuzhiyun with open(fn, "w") as f: 26*4882a593Smuzhiyun f.write(''.join(lines)) 27*4882a593Smuzhiyun 28*4882a593Smuzhiyun# Functions added to this variable MUST throw a NotImplementedError exception unless 29*4882a593Smuzhiyun# they successfully changed the config version in the config file. Exceptions 30*4882a593Smuzhiyun# are used since exec_func doesn't handle return values. 31*4882a593SmuzhiyunBBLAYERS_CONF_UPDATE_FUNCS += " \ 32*4882a593Smuzhiyun conf/bblayers.conf:LCONF_VERSION:LAYER_CONF_VERSION:oecore_update_bblayers \ 33*4882a593Smuzhiyun conf/local.conf:CONF_VERSION:LOCALCONF_VERSION:oecore_update_localconf \ 34*4882a593Smuzhiyun conf/site.conf:SCONF_VERSION:SITE_CONF_VERSION:oecore_update_siteconf \ 35*4882a593Smuzhiyun" 36*4882a593Smuzhiyun 37*4882a593SmuzhiyunSANITY_DIFF_TOOL ?= "meld" 38*4882a593Smuzhiyun 39*4882a593SmuzhiyunSANITY_LOCALCONF_SAMPLE ?= "${COREBASE}/meta*/conf/local.conf.sample" 40*4882a593Smuzhiyunpython oecore_update_localconf() { 41*4882a593Smuzhiyun # Check we are using a valid local.conf 42*4882a593Smuzhiyun current_conf = d.getVar('CONF_VERSION') 43*4882a593Smuzhiyun conf_version = d.getVar('LOCALCONF_VERSION') 44*4882a593Smuzhiyun 45*4882a593Smuzhiyun failmsg = """Your version of local.conf was generated from an older/newer version of 46*4882a593Smuzhiyunlocal.conf.sample and there have been updates made to this file. Please compare the two 47*4882a593Smuzhiyunfiles and merge any changes before continuing. 48*4882a593Smuzhiyun 49*4882a593SmuzhiyunMatching the version numbers will remove this message. 50*4882a593Smuzhiyun 51*4882a593Smuzhiyun\"${SANITY_DIFF_TOOL} conf/local.conf ${SANITY_LOCALCONF_SAMPLE}\" 52*4882a593Smuzhiyun 53*4882a593Smuzhiyunis a good way to visualise the changes.""" 54*4882a593Smuzhiyun failmsg = d.expand(failmsg) 55*4882a593Smuzhiyun 56*4882a593Smuzhiyun raise NotImplementedError(failmsg) 57*4882a593Smuzhiyun} 58*4882a593Smuzhiyun 59*4882a593SmuzhiyunSANITY_SITECONF_SAMPLE ?= "${COREBASE}/meta*/conf/site.conf.sample" 60*4882a593Smuzhiyunpython oecore_update_siteconf() { 61*4882a593Smuzhiyun # If we have a site.conf, check it's valid 62*4882a593Smuzhiyun current_sconf = d.getVar('SCONF_VERSION') 63*4882a593Smuzhiyun sconf_version = d.getVar('SITE_CONF_VERSION') 64*4882a593Smuzhiyun 65*4882a593Smuzhiyun failmsg = """Your version of site.conf was generated from an older version of 66*4882a593Smuzhiyunsite.conf.sample and there have been updates made to this file. Please compare the two 67*4882a593Smuzhiyunfiles and merge any changes before continuing. 68*4882a593Smuzhiyun 69*4882a593SmuzhiyunMatching the version numbers will remove this message. 70*4882a593Smuzhiyun 71*4882a593Smuzhiyun\"${SANITY_DIFF_TOOL} conf/site.conf ${SANITY_SITECONF_SAMPLE}\" 72*4882a593Smuzhiyun 73*4882a593Smuzhiyunis a good way to visualise the changes.""" 74*4882a593Smuzhiyun failmsg = d.expand(failmsg) 75*4882a593Smuzhiyun 76*4882a593Smuzhiyun raise NotImplementedError(failmsg) 77*4882a593Smuzhiyun} 78*4882a593Smuzhiyun 79*4882a593SmuzhiyunSANITY_BBLAYERCONF_SAMPLE ?= "${COREBASE}/meta*/conf/bblayers.conf.sample" 80*4882a593Smuzhiyunpython oecore_update_bblayers() { 81*4882a593Smuzhiyun # bblayers.conf is out of date, so see if we can resolve that 82*4882a593Smuzhiyun 83*4882a593Smuzhiyun current_lconf = int(d.getVar('LCONF_VERSION')) 84*4882a593Smuzhiyun lconf_version = int(d.getVar('LAYER_CONF_VERSION')) 85*4882a593Smuzhiyun 86*4882a593Smuzhiyun failmsg = """Your version of bblayers.conf has the wrong LCONF_VERSION (has ${LCONF_VERSION}, expecting ${LAYER_CONF_VERSION}). 87*4882a593SmuzhiyunPlease compare your file against bblayers.conf.sample and merge any changes before continuing. 88*4882a593Smuzhiyun"${SANITY_DIFF_TOOL} conf/bblayers.conf ${SANITY_BBLAYERCONF_SAMPLE}" 89*4882a593Smuzhiyun 90*4882a593Smuzhiyunis a good way to visualise the changes.""" 91*4882a593Smuzhiyun failmsg = d.expand(failmsg) 92*4882a593Smuzhiyun 93*4882a593Smuzhiyun if not current_lconf: 94*4882a593Smuzhiyun raise NotImplementedError(failmsg) 95*4882a593Smuzhiyun 96*4882a593Smuzhiyun lines = [] 97*4882a593Smuzhiyun 98*4882a593Smuzhiyun if current_lconf < 4: 99*4882a593Smuzhiyun raise NotImplementedError(failmsg) 100*4882a593Smuzhiyun 101*4882a593Smuzhiyun bblayers_fn = bblayers_conf_file(d) 102*4882a593Smuzhiyun lines = sanity_conf_read(bblayers_fn) 103*4882a593Smuzhiyun 104*4882a593Smuzhiyun if current_lconf == 4 and lconf_version > 4: 105*4882a593Smuzhiyun topdir_var = '$' + '{TOPDIR}' 106*4882a593Smuzhiyun index, bbpath_line = sanity_conf_find_line('BBPATH', lines) 107*4882a593Smuzhiyun if bbpath_line: 108*4882a593Smuzhiyun start = bbpath_line.find('"') 109*4882a593Smuzhiyun if start != -1 and (len(bbpath_line) != (start + 1)): 110*4882a593Smuzhiyun if bbpath_line[start + 1] == '"': 111*4882a593Smuzhiyun lines[index] = (bbpath_line[:start + 1] + 112*4882a593Smuzhiyun topdir_var + bbpath_line[start + 1:]) 113*4882a593Smuzhiyun else: 114*4882a593Smuzhiyun if not topdir_var in bbpath_line: 115*4882a593Smuzhiyun lines[index] = (bbpath_line[:start + 1] + 116*4882a593Smuzhiyun topdir_var + ':' + bbpath_line[start + 1:]) 117*4882a593Smuzhiyun else: 118*4882a593Smuzhiyun raise NotImplementedError(failmsg) 119*4882a593Smuzhiyun else: 120*4882a593Smuzhiyun index, bbfiles_line = sanity_conf_find_line('BBFILES', lines) 121*4882a593Smuzhiyun if bbfiles_line: 122*4882a593Smuzhiyun lines.insert(index, 'BBPATH = "' + topdir_var + '"\n') 123*4882a593Smuzhiyun else: 124*4882a593Smuzhiyun raise NotImplementedError(failmsg) 125*4882a593Smuzhiyun 126*4882a593Smuzhiyun current_lconf += 1 127*4882a593Smuzhiyun sanity_conf_update(bblayers_fn, lines, 'LCONF_VERSION', current_lconf) 128*4882a593Smuzhiyun bb.note("Your conf/bblayers.conf has been automatically updated.") 129*4882a593Smuzhiyun return 130*4882a593Smuzhiyun 131*4882a593Smuzhiyun elif current_lconf == 5 and lconf_version > 5: 132*4882a593Smuzhiyun # Null update, to avoid issues with people switching between poky and other distros 133*4882a593Smuzhiyun current_lconf = 6 134*4882a593Smuzhiyun sanity_conf_update(bblayers_fn, lines, 'LCONF_VERSION', current_lconf) 135*4882a593Smuzhiyun bb.note("Your conf/bblayers.conf has been automatically updated.") 136*4882a593Smuzhiyun return 137*4882a593Smuzhiyun 138*4882a593Smuzhiyun status.addresult() 139*4882a593Smuzhiyun 140*4882a593Smuzhiyun elif current_lconf == 6 and lconf_version > 6: 141*4882a593Smuzhiyun # Handle rename of meta-yocto -> meta-poky 142*4882a593Smuzhiyun # This marks the start of separate version numbers but code is needed in OE-Core 143*4882a593Smuzhiyun # for the migration, one last time. 144*4882a593Smuzhiyun layers = d.getVar('BBLAYERS').split() 145*4882a593Smuzhiyun layers = [ os.path.basename(path) for path in layers ] 146*4882a593Smuzhiyun if 'meta-yocto' in layers: 147*4882a593Smuzhiyun found = False 148*4882a593Smuzhiyun while True: 149*4882a593Smuzhiyun index, meta_yocto_line = sanity_conf_find_line(r'.*meta-yocto[\'"\s\n]', lines) 150*4882a593Smuzhiyun if meta_yocto_line: 151*4882a593Smuzhiyun lines[index] = meta_yocto_line.replace('meta-yocto', 'meta-poky') 152*4882a593Smuzhiyun found = True 153*4882a593Smuzhiyun else: 154*4882a593Smuzhiyun break 155*4882a593Smuzhiyun if not found: 156*4882a593Smuzhiyun raise NotImplementedError(failmsg) 157*4882a593Smuzhiyun index, meta_yocto_line = sanity_conf_find_line('LCONF_VERSION.*\n', lines) 158*4882a593Smuzhiyun if meta_yocto_line: 159*4882a593Smuzhiyun lines[index] = 'POKY_BBLAYERS_CONF_VERSION = "1"\n' 160*4882a593Smuzhiyun else: 161*4882a593Smuzhiyun raise NotImplementedError(failmsg) 162*4882a593Smuzhiyun with open(bblayers_fn, "w") as f: 163*4882a593Smuzhiyun f.write(''.join(lines)) 164*4882a593Smuzhiyun bb.note("Your conf/bblayers.conf has been automatically updated.") 165*4882a593Smuzhiyun return 166*4882a593Smuzhiyun current_lconf += 1 167*4882a593Smuzhiyun sanity_conf_update(bblayers_fn, lines, 'LCONF_VERSION', current_lconf) 168*4882a593Smuzhiyun bb.note("Your conf/bblayers.conf has been automatically updated.") 169*4882a593Smuzhiyun return 170*4882a593Smuzhiyun 171*4882a593Smuzhiyun raise NotImplementedError(failmsg) 172*4882a593Smuzhiyun} 173*4882a593Smuzhiyun 174*4882a593Smuzhiyundef raise_sanity_error(msg, d, network_error=False): 175*4882a593Smuzhiyun if d.getVar("SANITY_USE_EVENTS") == "1": 176*4882a593Smuzhiyun try: 177*4882a593Smuzhiyun bb.event.fire(bb.event.SanityCheckFailed(msg, network_error), d) 178*4882a593Smuzhiyun except TypeError: 179*4882a593Smuzhiyun bb.event.fire(bb.event.SanityCheckFailed(msg), d) 180*4882a593Smuzhiyun return 181*4882a593Smuzhiyun 182*4882a593Smuzhiyun bb.fatal(""" OE-core's config sanity checker detected a potential misconfiguration. 183*4882a593Smuzhiyun Either fix the cause of this error or at your own risk disable the checker (see sanity.conf). 184*4882a593Smuzhiyun Following is the list of potential problems / advisories: 185*4882a593Smuzhiyun 186*4882a593Smuzhiyun %s""" % msg) 187*4882a593Smuzhiyun 188*4882a593Smuzhiyun# Check a single tune for validity. 189*4882a593Smuzhiyundef check_toolchain_tune(data, tune, multilib): 190*4882a593Smuzhiyun tune_errors = [] 191*4882a593Smuzhiyun if not tune: 192*4882a593Smuzhiyun return "No tuning found for %s multilib." % multilib 193*4882a593Smuzhiyun localdata = bb.data.createCopy(data) 194*4882a593Smuzhiyun if multilib != "default": 195*4882a593Smuzhiyun # Apply the overrides so we can look at the details. 196*4882a593Smuzhiyun overrides = localdata.getVar("OVERRIDES", False) + ":virtclass-multilib-" + multilib 197*4882a593Smuzhiyun localdata.setVar("OVERRIDES", overrides) 198*4882a593Smuzhiyun bb.debug(2, "Sanity-checking tuning '%s' (%s) features:" % (tune, multilib)) 199*4882a593Smuzhiyun features = (localdata.getVar("TUNE_FEATURES:tune-%s" % tune) or "").split() 200*4882a593Smuzhiyun if not features: 201*4882a593Smuzhiyun return "Tuning '%s' has no defined features, and cannot be used." % tune 202*4882a593Smuzhiyun valid_tunes = localdata.getVarFlags('TUNEVALID') or {} 203*4882a593Smuzhiyun conflicts = localdata.getVarFlags('TUNECONFLICTS') or {} 204*4882a593Smuzhiyun # [doc] is the documentation for the variable, not a real feature 205*4882a593Smuzhiyun if 'doc' in valid_tunes: 206*4882a593Smuzhiyun del valid_tunes['doc'] 207*4882a593Smuzhiyun if 'doc' in conflicts: 208*4882a593Smuzhiyun del conflicts['doc'] 209*4882a593Smuzhiyun for feature in features: 210*4882a593Smuzhiyun if feature in conflicts: 211*4882a593Smuzhiyun for conflict in conflicts[feature].split(): 212*4882a593Smuzhiyun if conflict in features: 213*4882a593Smuzhiyun tune_errors.append("Feature '%s' conflicts with '%s'." % 214*4882a593Smuzhiyun (feature, conflict)) 215*4882a593Smuzhiyun if feature in valid_tunes: 216*4882a593Smuzhiyun bb.debug(2, " %s: %s" % (feature, valid_tunes[feature])) 217*4882a593Smuzhiyun else: 218*4882a593Smuzhiyun tune_errors.append("Feature '%s' is not defined." % feature) 219*4882a593Smuzhiyun if tune_errors: 220*4882a593Smuzhiyun return "Tuning '%s' has the following errors:\n" % tune + '\n'.join(tune_errors) 221*4882a593Smuzhiyun 222*4882a593Smuzhiyundef check_toolchain(data): 223*4882a593Smuzhiyun tune_error_set = [] 224*4882a593Smuzhiyun deftune = data.getVar("DEFAULTTUNE") 225*4882a593Smuzhiyun tune_errors = check_toolchain_tune(data, deftune, 'default') 226*4882a593Smuzhiyun if tune_errors: 227*4882a593Smuzhiyun tune_error_set.append(tune_errors) 228*4882a593Smuzhiyun 229*4882a593Smuzhiyun multilibs = (data.getVar("MULTILIB_VARIANTS") or "").split() 230*4882a593Smuzhiyun global_multilibs = (data.getVar("MULTILIB_GLOBAL_VARIANTS") or "").split() 231*4882a593Smuzhiyun 232*4882a593Smuzhiyun if multilibs: 233*4882a593Smuzhiyun seen_libs = [] 234*4882a593Smuzhiyun seen_tunes = [] 235*4882a593Smuzhiyun for lib in multilibs: 236*4882a593Smuzhiyun if lib in seen_libs: 237*4882a593Smuzhiyun tune_error_set.append("The multilib '%s' appears more than once." % lib) 238*4882a593Smuzhiyun else: 239*4882a593Smuzhiyun seen_libs.append(lib) 240*4882a593Smuzhiyun if not lib in global_multilibs: 241*4882a593Smuzhiyun tune_error_set.append("Multilib %s is not present in MULTILIB_GLOBAL_VARIANTS" % lib) 242*4882a593Smuzhiyun tune = data.getVar("DEFAULTTUNE:virtclass-multilib-%s" % lib) 243*4882a593Smuzhiyun if tune in seen_tunes: 244*4882a593Smuzhiyun tune_error_set.append("The tuning '%s' appears in more than one multilib." % tune) 245*4882a593Smuzhiyun else: 246*4882a593Smuzhiyun seen_libs.append(tune) 247*4882a593Smuzhiyun if tune == deftune: 248*4882a593Smuzhiyun tune_error_set.append("Multilib '%s' (%s) is also the default tuning." % (lib, deftune)) 249*4882a593Smuzhiyun else: 250*4882a593Smuzhiyun tune_errors = check_toolchain_tune(data, tune, lib) 251*4882a593Smuzhiyun if tune_errors: 252*4882a593Smuzhiyun tune_error_set.append(tune_errors) 253*4882a593Smuzhiyun if tune_error_set: 254*4882a593Smuzhiyun return "Toolchain tunings invalid:\n" + '\n'.join(tune_error_set) + "\n" 255*4882a593Smuzhiyun 256*4882a593Smuzhiyun return "" 257*4882a593Smuzhiyun 258*4882a593Smuzhiyundef check_conf_exists(fn, data): 259*4882a593Smuzhiyun bbpath = [] 260*4882a593Smuzhiyun fn = data.expand(fn) 261*4882a593Smuzhiyun vbbpath = data.getVar("BBPATH", False) 262*4882a593Smuzhiyun if vbbpath: 263*4882a593Smuzhiyun bbpath += vbbpath.split(":") 264*4882a593Smuzhiyun for p in bbpath: 265*4882a593Smuzhiyun currname = os.path.join(data.expand(p), fn) 266*4882a593Smuzhiyun if os.access(currname, os.R_OK): 267*4882a593Smuzhiyun return True 268*4882a593Smuzhiyun return False 269*4882a593Smuzhiyun 270*4882a593Smuzhiyundef check_create_long_filename(filepath, pathname): 271*4882a593Smuzhiyun import string, random 272*4882a593Smuzhiyun testfile = os.path.join(filepath, ''.join(random.choice(string.ascii_letters) for x in range(200))) 273*4882a593Smuzhiyun try: 274*4882a593Smuzhiyun if not os.path.exists(filepath): 275*4882a593Smuzhiyun bb.utils.mkdirhier(filepath) 276*4882a593Smuzhiyun f = open(testfile, "w") 277*4882a593Smuzhiyun f.close() 278*4882a593Smuzhiyun os.remove(testfile) 279*4882a593Smuzhiyun except IOError as e: 280*4882a593Smuzhiyun import errno 281*4882a593Smuzhiyun err, strerror = e.args 282*4882a593Smuzhiyun if err == errno.ENAMETOOLONG: 283*4882a593Smuzhiyun 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 284*4882a593Smuzhiyun else: 285*4882a593Smuzhiyun return "Failed to create a file in %s: %s.\n" % (pathname, strerror) 286*4882a593Smuzhiyun except OSError as e: 287*4882a593Smuzhiyun errno, strerror = e.args 288*4882a593Smuzhiyun return "Failed to create %s directory in which to run long name sanity check: %s.\n" % (pathname, strerror) 289*4882a593Smuzhiyun return "" 290*4882a593Smuzhiyun 291*4882a593Smuzhiyundef check_path_length(filepath, pathname, limit): 292*4882a593Smuzhiyun if len(filepath) > limit: 293*4882a593Smuzhiyun return "The length of %s is longer than %s, this would cause unexpected errors, please use a shorter path.\n" % (pathname, limit) 294*4882a593Smuzhiyun return "" 295*4882a593Smuzhiyun 296*4882a593Smuzhiyundef get_filesystem_id(path): 297*4882a593Smuzhiyun import subprocess 298*4882a593Smuzhiyun try: 299*4882a593Smuzhiyun return subprocess.check_output(["stat", "-f", "-c", "%t", path]).decode('utf-8').strip() 300*4882a593Smuzhiyun except subprocess.CalledProcessError: 301*4882a593Smuzhiyun bb.warn("Can't get filesystem id of: %s" % path) 302*4882a593Smuzhiyun return None 303*4882a593Smuzhiyun 304*4882a593Smuzhiyun# Check that the path isn't located on nfs. 305*4882a593Smuzhiyundef check_not_nfs(path, name): 306*4882a593Smuzhiyun # The nfs' filesystem id is 6969 307*4882a593Smuzhiyun if get_filesystem_id(path) == "6969": 308*4882a593Smuzhiyun return "The %s: %s can't be located on nfs.\n" % (name, path) 309*4882a593Smuzhiyun return "" 310*4882a593Smuzhiyun 311*4882a593Smuzhiyun# Check that the path is on a case-sensitive file system 312*4882a593Smuzhiyundef check_case_sensitive(path, name): 313*4882a593Smuzhiyun import tempfile 314*4882a593Smuzhiyun with tempfile.NamedTemporaryFile(prefix='TmP', dir=path) as tmp_file: 315*4882a593Smuzhiyun if os.path.exists(tmp_file.name.lower()): 316*4882a593Smuzhiyun return "The %s (%s) can't be on a case-insensitive file system.\n" % (name, path) 317*4882a593Smuzhiyun return "" 318*4882a593Smuzhiyun 319*4882a593Smuzhiyun# Check that path isn't a broken symlink 320*4882a593Smuzhiyundef check_symlink(lnk, data): 321*4882a593Smuzhiyun if os.path.islink(lnk) and not os.path.exists(lnk): 322*4882a593Smuzhiyun raise_sanity_error("%s is a broken symlink." % lnk, data) 323*4882a593Smuzhiyun 324*4882a593Smuzhiyundef check_connectivity(d): 325*4882a593Smuzhiyun # URI's to check can be set in the CONNECTIVITY_CHECK_URIS variable 326*4882a593Smuzhiyun # using the same syntax as for SRC_URI. If the variable is not set 327*4882a593Smuzhiyun # the check is skipped 328*4882a593Smuzhiyun test_uris = (d.getVar('CONNECTIVITY_CHECK_URIS') or "").split() 329*4882a593Smuzhiyun retval = "" 330*4882a593Smuzhiyun 331*4882a593Smuzhiyun bbn = d.getVar('BB_NO_NETWORK') 332*4882a593Smuzhiyun if bbn not in (None, '0', '1'): 333*4882a593Smuzhiyun return 'BB_NO_NETWORK should be "0" or "1", but it is "%s"' % bbn 334*4882a593Smuzhiyun 335*4882a593Smuzhiyun # Only check connectivity if network enabled and the 336*4882a593Smuzhiyun # CONNECTIVITY_CHECK_URIS are set 337*4882a593Smuzhiyun network_enabled = not (bbn == '1') 338*4882a593Smuzhiyun check_enabled = len(test_uris) 339*4882a593Smuzhiyun if check_enabled and network_enabled: 340*4882a593Smuzhiyun # Take a copy of the data store and unset MIRRORS and PREMIRRORS 341*4882a593Smuzhiyun data = bb.data.createCopy(d) 342*4882a593Smuzhiyun data.delVar('PREMIRRORS') 343*4882a593Smuzhiyun data.delVar('MIRRORS') 344*4882a593Smuzhiyun try: 345*4882a593Smuzhiyun fetcher = bb.fetch2.Fetch(test_uris, data) 346*4882a593Smuzhiyun fetcher.checkstatus() 347*4882a593Smuzhiyun except Exception as err: 348*4882a593Smuzhiyun # Allow the message to be configured so that users can be 349*4882a593Smuzhiyun # pointed to a support mechanism. 350*4882a593Smuzhiyun msg = data.getVar('CONNECTIVITY_CHECK_MSG') or "" 351*4882a593Smuzhiyun if len(msg) == 0: 352*4882a593Smuzhiyun msg = "%s.\n" % err 353*4882a593Smuzhiyun msg += " Please ensure your host's network is configured correctly.\n" 354*4882a593Smuzhiyun msg += " Please ensure CONNECTIVITY_CHECK_URIS is correct and specified URIs are available.\n" 355*4882a593Smuzhiyun msg += " If your ISP or network is blocking the above URL,\n" 356*4882a593Smuzhiyun msg += " try with another domain name, for example by setting:\n" 357*4882a593Smuzhiyun msg += " CONNECTIVITY_CHECK_URIS = \"https://www.example.com/\"" 358*4882a593Smuzhiyun msg += " You could also set BB_NO_NETWORK = \"1\" to disable network\n" 359*4882a593Smuzhiyun msg += " access if all required sources are on local disk.\n" 360*4882a593Smuzhiyun retval = msg 361*4882a593Smuzhiyun 362*4882a593Smuzhiyun return retval 363*4882a593Smuzhiyun 364*4882a593Smuzhiyundef check_supported_distro(sanity_data): 365*4882a593Smuzhiyun from fnmatch import fnmatch 366*4882a593Smuzhiyun 367*4882a593Smuzhiyun tested_distros = sanity_data.getVar('SANITY_TESTED_DISTROS') 368*4882a593Smuzhiyun if not tested_distros: 369*4882a593Smuzhiyun return 370*4882a593Smuzhiyun 371*4882a593Smuzhiyun try: 372*4882a593Smuzhiyun distro = oe.lsb.distro_identifier() 373*4882a593Smuzhiyun except Exception: 374*4882a593Smuzhiyun distro = None 375*4882a593Smuzhiyun 376*4882a593Smuzhiyun if not distro: 377*4882a593Smuzhiyun bb.warn('Host distribution could not be determined; you may possibly experience unexpected failures. It is recommended that you use a tested distribution.') 378*4882a593Smuzhiyun 379*4882a593Smuzhiyun for supported in [x.strip() for x in tested_distros.split('\\n')]: 380*4882a593Smuzhiyun if fnmatch(distro, supported): 381*4882a593Smuzhiyun return 382*4882a593Smuzhiyun 383*4882a593Smuzhiyun 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) 384*4882a593Smuzhiyun 385*4882a593Smuzhiyun# Checks we should only make if MACHINE is set correctly 386*4882a593Smuzhiyundef check_sanity_validmachine(sanity_data): 387*4882a593Smuzhiyun messages = "" 388*4882a593Smuzhiyun 389*4882a593Smuzhiyun # Check TUNE_ARCH is set 390*4882a593Smuzhiyun if sanity_data.getVar('TUNE_ARCH') == 'INVALID': 391*4882a593Smuzhiyun messages = messages + 'TUNE_ARCH is unset. Please ensure your MACHINE configuration includes a valid tune configuration file which will set this correctly.\n' 392*4882a593Smuzhiyun 393*4882a593Smuzhiyun # Check TARGET_OS is set 394*4882a593Smuzhiyun if sanity_data.getVar('TARGET_OS') == 'INVALID': 395*4882a593Smuzhiyun messages = messages + 'Please set TARGET_OS directly, or choose a MACHINE or DISTRO that does so.\n' 396*4882a593Smuzhiyun 397*4882a593Smuzhiyun # Check that we don't have duplicate entries in PACKAGE_ARCHS & that TUNE_PKGARCH is in PACKAGE_ARCHS 398*4882a593Smuzhiyun pkgarchs = sanity_data.getVar('PACKAGE_ARCHS') 399*4882a593Smuzhiyun tunepkg = sanity_data.getVar('TUNE_PKGARCH') 400*4882a593Smuzhiyun defaulttune = sanity_data.getVar('DEFAULTTUNE') 401*4882a593Smuzhiyun tunefound = False 402*4882a593Smuzhiyun seen = {} 403*4882a593Smuzhiyun dups = [] 404*4882a593Smuzhiyun 405*4882a593Smuzhiyun for pa in pkgarchs.split(): 406*4882a593Smuzhiyun if seen.get(pa, 0) == 1: 407*4882a593Smuzhiyun dups.append(pa) 408*4882a593Smuzhiyun else: 409*4882a593Smuzhiyun seen[pa] = 1 410*4882a593Smuzhiyun if pa == tunepkg: 411*4882a593Smuzhiyun tunefound = True 412*4882a593Smuzhiyun 413*4882a593Smuzhiyun if len(dups): 414*4882a593Smuzhiyun messages = messages + "Error, the PACKAGE_ARCHS variable contains duplicates. The following archs are listed more than once: %s" % " ".join(dups) 415*4882a593Smuzhiyun 416*4882a593Smuzhiyun if tunefound == False: 417*4882a593Smuzhiyun messages = messages + "Error, the PACKAGE_ARCHS variable (%s) for DEFAULTTUNE (%s) does not contain TUNE_PKGARCH (%s)." % (pkgarchs, defaulttune, tunepkg) 418*4882a593Smuzhiyun 419*4882a593Smuzhiyun return messages 420*4882a593Smuzhiyun 421*4882a593Smuzhiyun# Patch before 2.7 can't handle all the features in git-style diffs. Some 422*4882a593Smuzhiyun# patches may incorrectly apply, and others won't apply at all. 423*4882a593Smuzhiyundef check_patch_version(sanity_data): 424*4882a593Smuzhiyun import re, subprocess 425*4882a593Smuzhiyun 426*4882a593Smuzhiyun try: 427*4882a593Smuzhiyun result = subprocess.check_output(["patch", "--version"], stderr=subprocess.STDOUT).decode('utf-8') 428*4882a593Smuzhiyun version = re.search(r"[0-9.]+", result.splitlines()[0]).group() 429*4882a593Smuzhiyun if bb.utils.vercmp_string_op(version, "2.7", "<"): 430*4882a593Smuzhiyun return "Your version of patch is older than 2.7 and has bugs which will break builds. Please install a newer version of patch.\n" 431*4882a593Smuzhiyun else: 432*4882a593Smuzhiyun return None 433*4882a593Smuzhiyun except subprocess.CalledProcessError as e: 434*4882a593Smuzhiyun return "Unable to execute patch --version, exit code %d:\n%s\n" % (e.returncode, e.output) 435*4882a593Smuzhiyun 436*4882a593Smuzhiyun# Glibc needs make 4.0 or later, we may as well match at this point 437*4882a593Smuzhiyundef check_make_version(sanity_data): 438*4882a593Smuzhiyun import subprocess 439*4882a593Smuzhiyun 440*4882a593Smuzhiyun try: 441*4882a593Smuzhiyun result = subprocess.check_output(['make', '--version'], stderr=subprocess.STDOUT).decode('utf-8') 442*4882a593Smuzhiyun except subprocess.CalledProcessError as e: 443*4882a593Smuzhiyun return "Unable to execute make --version, exit code %d\n%s\n" % (e.returncode, e.output) 444*4882a593Smuzhiyun version = result.split()[2] 445*4882a593Smuzhiyun if bb.utils.vercmp_string_op(version, "4.0", "<"): 446*4882a593Smuzhiyun return "Please install a make version of 4.0 or later.\n" 447*4882a593Smuzhiyun 448*4882a593Smuzhiyun if bb.utils.vercmp_string_op(version, "4.2.1", "=="): 449*4882a593Smuzhiyun distro = oe.lsb.distro_identifier() 450*4882a593Smuzhiyun if "ubuntu" in distro or "debian" in distro or "linuxmint" in distro: 451*4882a593Smuzhiyun return None 452*4882a593Smuzhiyun return "make version 4.2.1 is known to have issues on Centos/OpenSUSE and other non-Ubuntu systems. Please use a buildtools-make-tarball or a newer version of make.\n" 453*4882a593Smuzhiyun return None 454*4882a593Smuzhiyun 455*4882a593Smuzhiyun 456*4882a593Smuzhiyun# Check if we're running on WSL (Windows Subsystem for Linux). 457*4882a593Smuzhiyun# WSLv1 is known not to work but WSLv2 should work properly as 458*4882a593Smuzhiyun# long as the VHDX file is optimized often, let the user know 459*4882a593Smuzhiyun# upfront. 460*4882a593Smuzhiyun# More information on installing WSLv2 at: 461*4882a593Smuzhiyun# https://docs.microsoft.com/en-us/windows/wsl/wsl2-install 462*4882a593Smuzhiyundef check_wsl(d): 463*4882a593Smuzhiyun with open("/proc/version", "r") as f: 464*4882a593Smuzhiyun verdata = f.readlines() 465*4882a593Smuzhiyun for l in verdata: 466*4882a593Smuzhiyun if "Microsoft" in l: 467*4882a593Smuzhiyun return "OpenEmbedded doesn't work under WSLv1, please upgrade to WSLv2 if you want to run builds on Windows" 468*4882a593Smuzhiyun elif "microsoft" in l: 469*4882a593Smuzhiyun bb.warn("You are running bitbake under WSLv2, this works properly but you should optimize your VHDX file eventually to avoid running out of storage space") 470*4882a593Smuzhiyun return None 471*4882a593Smuzhiyun 472*4882a593Smuzhiyun# Require at least gcc version 7.5. 473*4882a593Smuzhiyun# 474*4882a593Smuzhiyun# This can be fixed on CentOS-7 with devtoolset-6+ 475*4882a593Smuzhiyun# https://www.softwarecollections.org/en/scls/rhscl/devtoolset-6/ 476*4882a593Smuzhiyun# 477*4882a593Smuzhiyun# A less invasive fix is with scripts/install-buildtools (or with user 478*4882a593Smuzhiyun# built buildtools-extended-tarball) 479*4882a593Smuzhiyun# 480*4882a593Smuzhiyundef check_gcc_version(sanity_data): 481*4882a593Smuzhiyun import subprocess 482*4882a593Smuzhiyun 483*4882a593Smuzhiyun build_cc, version = oe.utils.get_host_compiler_version(sanity_data) 484*4882a593Smuzhiyun if build_cc.strip() == "gcc": 485*4882a593Smuzhiyun if bb.utils.vercmp_string_op(version, "7.5", "<"): 486*4882a593Smuzhiyun return "Your version of gcc is older than 7.5 and will break builds. Please install a newer version of gcc (you could use the project's buildtools-extended-tarball or use scripts/install-buildtools).\n" 487*4882a593Smuzhiyun return None 488*4882a593Smuzhiyun 489*4882a593Smuzhiyun# Tar version 1.24 and onwards handle overwriting symlinks correctly 490*4882a593Smuzhiyun# but earlier versions do not; this needs to work properly for sstate 491*4882a593Smuzhiyun# Version 1.28 is needed so opkg-build works correctly when reproducibile builds are enabled 492*4882a593Smuzhiyundef check_tar_version(sanity_data): 493*4882a593Smuzhiyun import subprocess 494*4882a593Smuzhiyun try: 495*4882a593Smuzhiyun result = subprocess.check_output(["tar", "--version"], stderr=subprocess.STDOUT).decode('utf-8') 496*4882a593Smuzhiyun except subprocess.CalledProcessError as e: 497*4882a593Smuzhiyun return "Unable to execute tar --version, exit code %d\n%s\n" % (e.returncode, e.output) 498*4882a593Smuzhiyun version = result.split()[3] 499*4882a593Smuzhiyun if bb.utils.vercmp_string_op(version, "1.28", "<"): 500*4882a593Smuzhiyun return "Your version of tar is older than 1.28 and does not have the support needed to enable reproducible builds. Please install a newer version of tar (you could use the project's buildtools-tarball from our last release or use scripts/install-buildtools).\n" 501*4882a593Smuzhiyun 502*4882a593Smuzhiyun try: 503*4882a593Smuzhiyun result = subprocess.check_output(["tar", "--help"], stderr=subprocess.STDOUT).decode('utf-8') 504*4882a593Smuzhiyun if "--xattrs" not in result: 505*4882a593Smuzhiyun return "Your tar doesn't support --xattrs, please use GNU tar.\n" 506*4882a593Smuzhiyun except subprocess.CalledProcessError as e: 507*4882a593Smuzhiyun return "Unable to execute tar --help, exit code %d\n%s\n" % (e.returncode, e.output) 508*4882a593Smuzhiyun 509*4882a593Smuzhiyun return None 510*4882a593Smuzhiyun 511*4882a593Smuzhiyun# We use git parameters and functionality only found in 1.7.8 or later 512*4882a593Smuzhiyun# The kernel tools assume git >= 1.8.3.1 (verified needed > 1.7.9.5) see #6162 513*4882a593Smuzhiyun# The git fetcher also had workarounds for git < 1.7.9.2 which we've dropped 514*4882a593Smuzhiyundef check_git_version(sanity_data): 515*4882a593Smuzhiyun import subprocess 516*4882a593Smuzhiyun try: 517*4882a593Smuzhiyun result = subprocess.check_output(["git", "--version"], stderr=subprocess.DEVNULL).decode('utf-8') 518*4882a593Smuzhiyun except subprocess.CalledProcessError as e: 519*4882a593Smuzhiyun return "Unable to execute git --version, exit code %d\n%s\n" % (e.returncode, e.output) 520*4882a593Smuzhiyun version = result.split()[2] 521*4882a593Smuzhiyun if bb.utils.vercmp_string_op(version, "1.8.3.1", "<"): 522*4882a593Smuzhiyun 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" 523*4882a593Smuzhiyun return None 524*4882a593Smuzhiyun 525*4882a593Smuzhiyun# Check the required perl modules which may not be installed by default 526*4882a593Smuzhiyundef check_perl_modules(sanity_data): 527*4882a593Smuzhiyun import subprocess 528*4882a593Smuzhiyun ret = "" 529*4882a593Smuzhiyun modules = ( "Text::ParseWords", "Thread::Queue", "Data::Dumper" ) 530*4882a593Smuzhiyun errresult = '' 531*4882a593Smuzhiyun for m in modules: 532*4882a593Smuzhiyun try: 533*4882a593Smuzhiyun subprocess.check_output(["perl", "-e", "use %s" % m]) 534*4882a593Smuzhiyun except subprocess.CalledProcessError as e: 535*4882a593Smuzhiyun errresult += bytes.decode(e.output) 536*4882a593Smuzhiyun ret += "%s " % m 537*4882a593Smuzhiyun if ret: 538*4882a593Smuzhiyun return "Required perl module(s) not found: %s\n\n%s\n" % (ret, errresult) 539*4882a593Smuzhiyun return None 540*4882a593Smuzhiyun 541*4882a593Smuzhiyundef sanity_check_conffiles(d): 542*4882a593Smuzhiyun funcs = d.getVar('BBLAYERS_CONF_UPDATE_FUNCS').split() 543*4882a593Smuzhiyun for func in funcs: 544*4882a593Smuzhiyun conffile, current_version, required_version, func = func.split(":") 545*4882a593Smuzhiyun if check_conf_exists(conffile, d) and d.getVar(current_version) is not None and \ 546*4882a593Smuzhiyun d.getVar(current_version) != d.getVar(required_version): 547*4882a593Smuzhiyun try: 548*4882a593Smuzhiyun bb.build.exec_func(func, d) 549*4882a593Smuzhiyun except NotImplementedError as e: 550*4882a593Smuzhiyun bb.fatal(str(e)) 551*4882a593Smuzhiyun d.setVar("BB_INVALIDCONF", True) 552*4882a593Smuzhiyun 553*4882a593Smuzhiyundef drop_v14_cross_builds(d): 554*4882a593Smuzhiyun import glob 555*4882a593Smuzhiyun indexes = glob.glob(d.expand("${SSTATE_MANIFESTS}/index-${BUILD_ARCH}_*")) 556*4882a593Smuzhiyun for i in indexes: 557*4882a593Smuzhiyun with open(i, "r") as f: 558*4882a593Smuzhiyun lines = f.readlines() 559*4882a593Smuzhiyun for l in reversed(lines): 560*4882a593Smuzhiyun try: 561*4882a593Smuzhiyun (stamp, manifest, workdir) = l.split() 562*4882a593Smuzhiyun except ValueError: 563*4882a593Smuzhiyun bb.fatal("Invalid line '%s' in sstate manifest '%s'" % (l, i)) 564*4882a593Smuzhiyun for m in glob.glob(manifest + ".*"): 565*4882a593Smuzhiyun if m.endswith(".postrm"): 566*4882a593Smuzhiyun continue 567*4882a593Smuzhiyun sstate_clean_manifest(m, d) 568*4882a593Smuzhiyun bb.utils.remove(stamp + "*") 569*4882a593Smuzhiyun bb.utils.remove(workdir, recurse = True) 570*4882a593Smuzhiyun 571*4882a593Smuzhiyundef sanity_handle_abichanges(status, d): 572*4882a593Smuzhiyun # 573*4882a593Smuzhiyun # Check the 'ABI' of TMPDIR 574*4882a593Smuzhiyun # 575*4882a593Smuzhiyun import subprocess 576*4882a593Smuzhiyun 577*4882a593Smuzhiyun current_abi = d.getVar('OELAYOUT_ABI') 578*4882a593Smuzhiyun abifile = d.getVar('SANITY_ABIFILE') 579*4882a593Smuzhiyun if os.path.exists(abifile): 580*4882a593Smuzhiyun with open(abifile, "r") as f: 581*4882a593Smuzhiyun abi = f.read().strip() 582*4882a593Smuzhiyun if not abi.isdigit(): 583*4882a593Smuzhiyun with open(abifile, "w") as f: 584*4882a593Smuzhiyun f.write(current_abi) 585*4882a593Smuzhiyun elif int(abi) <= 11 and current_abi == "12": 586*4882a593Smuzhiyun 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")) 587*4882a593Smuzhiyun elif int(abi) <= 13 and current_abi == "14": 588*4882a593Smuzhiyun status.addresult("TMPDIR changed to include path filtering from the pseudo database.\nIt is recommended to use a clean TMPDIR with the new pseudo path filtering so TMPDIR (%s) would need to be removed to continue.\n" % d.getVar("TMPDIR")) 589*4882a593Smuzhiyun elif int(abi) == 14 and current_abi == "15": 590*4882a593Smuzhiyun drop_v14_cross_builds(d) 591*4882a593Smuzhiyun with open(abifile, "w") as f: 592*4882a593Smuzhiyun f.write(current_abi) 593*4882a593Smuzhiyun elif (abi != current_abi): 594*4882a593Smuzhiyun # Code to convert from one ABI to another could go here if possible. 595*4882a593Smuzhiyun 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*4882a593Smuzhiyun else: 597*4882a593Smuzhiyun with open(abifile, "w") as f: 598*4882a593Smuzhiyun f.write(current_abi) 599*4882a593Smuzhiyun 600*4882a593Smuzhiyundef check_sanity_sstate_dir_change(sstate_dir, data): 601*4882a593Smuzhiyun # Sanity checks to be done when the value of SSTATE_DIR changes 602*4882a593Smuzhiyun 603*4882a593Smuzhiyun # Check that SSTATE_DIR isn't on a filesystem with limited filename length (eg. eCryptFS) 604*4882a593Smuzhiyun testmsg = "" 605*4882a593Smuzhiyun if sstate_dir != "": 606*4882a593Smuzhiyun testmsg = check_create_long_filename(sstate_dir, "SSTATE_DIR") 607*4882a593Smuzhiyun # If we don't have permissions to SSTATE_DIR, suggest the user set it as an SSTATE_MIRRORS 608*4882a593Smuzhiyun try: 609*4882a593Smuzhiyun err = testmsg.split(': ')[1].strip() 610*4882a593Smuzhiyun if err == "Permission denied.": 611*4882a593Smuzhiyun testmsg = testmsg + "You could try using %s in SSTATE_MIRRORS rather than as an SSTATE_CACHE.\n" % (sstate_dir) 612*4882a593Smuzhiyun except IndexError: 613*4882a593Smuzhiyun pass 614*4882a593Smuzhiyun return testmsg 615*4882a593Smuzhiyun 616*4882a593Smuzhiyundef check_sanity_version_change(status, d): 617*4882a593Smuzhiyun # Sanity checks to be done when SANITY_VERSION or NATIVELSBSTRING changes 618*4882a593Smuzhiyun # In other words, these tests run once in a given build directory and then 619*4882a593Smuzhiyun # never again until the sanity version or host distrubution id/version changes. 620*4882a593Smuzhiyun 621*4882a593Smuzhiyun # Check the python install is complete. Examples that are often removed in 622*4882a593Smuzhiyun # minimal installations: glib-2.0-natives requries # xml.parsers.expat and icu 623*4882a593Smuzhiyun # requires distutils.sysconfig. 624*4882a593Smuzhiyun try: 625*4882a593Smuzhiyun import xml.parsers.expat 626*4882a593Smuzhiyun import distutils.sysconfig 627*4882a593Smuzhiyun except ImportError as e: 628*4882a593Smuzhiyun status.addresult('Your Python 3 is not a full install. Please install the module %s (see the Getting Started guide for further information).\n' % e.name) 629*4882a593Smuzhiyun 630*4882a593Smuzhiyun status.addresult(check_gcc_version(d)) 631*4882a593Smuzhiyun status.addresult(check_make_version(d)) 632*4882a593Smuzhiyun status.addresult(check_patch_version(d)) 633*4882a593Smuzhiyun status.addresult(check_tar_version(d)) 634*4882a593Smuzhiyun status.addresult(check_git_version(d)) 635*4882a593Smuzhiyun status.addresult(check_perl_modules(d)) 636*4882a593Smuzhiyun status.addresult(check_wsl(d)) 637*4882a593Smuzhiyun 638*4882a593Smuzhiyun missing = "" 639*4882a593Smuzhiyun 640*4882a593Smuzhiyun if not check_app_exists("${MAKE}", d): 641*4882a593Smuzhiyun missing = missing + "GNU make," 642*4882a593Smuzhiyun 643*4882a593Smuzhiyun if not check_app_exists('${BUILD_CC}', d): 644*4882a593Smuzhiyun missing = missing + "C Compiler (%s)," % d.getVar("BUILD_CC") 645*4882a593Smuzhiyun 646*4882a593Smuzhiyun if not check_app_exists('${BUILD_CXX}', d): 647*4882a593Smuzhiyun missing = missing + "C++ Compiler (%s)," % d.getVar("BUILD_CXX") 648*4882a593Smuzhiyun 649*4882a593Smuzhiyun required_utilities = d.getVar('SANITY_REQUIRED_UTILITIES') 650*4882a593Smuzhiyun 651*4882a593Smuzhiyun for util in required_utilities.split(): 652*4882a593Smuzhiyun if not check_app_exists(util, d): 653*4882a593Smuzhiyun missing = missing + "%s," % util 654*4882a593Smuzhiyun 655*4882a593Smuzhiyun if missing: 656*4882a593Smuzhiyun missing = missing.rstrip(',') 657*4882a593Smuzhiyun status.addresult("Please install the following missing utilities: %s\n" % missing) 658*4882a593Smuzhiyun 659*4882a593Smuzhiyun assume_provided = d.getVar('ASSUME_PROVIDED').split() 660*4882a593Smuzhiyun # Check user doesn't have ASSUME_PROVIDED = instead of += in local.conf 661*4882a593Smuzhiyun if "diffstat-native" not in assume_provided: 662*4882a593Smuzhiyun status.addresult('Please use ASSUME_PROVIDED +=, not ASSUME_PROVIDED = in your local.conf\n') 663*4882a593Smuzhiyun 664*4882a593Smuzhiyun # Check that TMPDIR isn't on a filesystem with limited filename length (eg. eCryptFS) 665*4882a593Smuzhiyun import stat 666*4882a593Smuzhiyun tmpdir = d.getVar('TMPDIR') 667*4882a593Smuzhiyun status.addresult(check_create_long_filename(tmpdir, "TMPDIR")) 668*4882a593Smuzhiyun tmpdirmode = os.stat(tmpdir).st_mode 669*4882a593Smuzhiyun if (tmpdirmode & stat.S_ISGID): 670*4882a593Smuzhiyun status.addresult("TMPDIR is setgid, please don't build in a setgid directory") 671*4882a593Smuzhiyun if (tmpdirmode & stat.S_ISUID): 672*4882a593Smuzhiyun status.addresult("TMPDIR is setuid, please don't build in a setuid directory") 673*4882a593Smuzhiyun 674*4882a593Smuzhiyun # Check that a user isn't building in a path in PSEUDO_IGNORE_PATHS 675*4882a593Smuzhiyun pseudoignorepaths = d.getVar('PSEUDO_IGNORE_PATHS', expand=True).split(",") 676*4882a593Smuzhiyun workdir = d.getVar('WORKDIR', expand=True) 677*4882a593Smuzhiyun for i in pseudoignorepaths: 678*4882a593Smuzhiyun if i and workdir.startswith(i): 679*4882a593Smuzhiyun status.addresult("You are building in a path included in PSEUDO_IGNORE_PATHS " + str(i) + " please locate the build outside this path.\n") 680*4882a593Smuzhiyun 681*4882a593Smuzhiyun # Check if PSEUDO_IGNORE_PATHS and and paths under pseudo control overlap 682*4882a593Smuzhiyun pseudoignorepaths = d.getVar('PSEUDO_IGNORE_PATHS', expand=True).split(",") 683*4882a593Smuzhiyun pseudo_control_dir = "${D},${PKGD},${PKGDEST},${IMAGEROOTFS},${SDK_OUTPUT}" 684*4882a593Smuzhiyun pseudocontroldir = d.expand(pseudo_control_dir).split(",") 685*4882a593Smuzhiyun for i in pseudoignorepaths: 686*4882a593Smuzhiyun for j in pseudocontroldir: 687*4882a593Smuzhiyun if i and j: 688*4882a593Smuzhiyun if j.startswith(i): 689*4882a593Smuzhiyun status.addresult("A path included in PSEUDO_IGNORE_PATHS " + str(i) + " and the path " + str(j) + " overlap and this will break pseudo permission and ownership tracking. Please set the path " + str(j) + " to a different directory which does not overlap with pseudo controlled directories. \n") 690*4882a593Smuzhiyun 691*4882a593Smuzhiyun # Some third-party software apparently relies on chmod etc. being suid root (!!) 692*4882a593Smuzhiyun import stat 693*4882a593Smuzhiyun suid_check_bins = "chown chmod mknod".split() 694*4882a593Smuzhiyun for bin_cmd in suid_check_bins: 695*4882a593Smuzhiyun bin_path = bb.utils.which(os.environ["PATH"], bin_cmd) 696*4882a593Smuzhiyun if bin_path: 697*4882a593Smuzhiyun bin_stat = os.stat(bin_path) 698*4882a593Smuzhiyun if bin_stat.st_uid == 0 and bin_stat.st_mode & stat.S_ISUID: 699*4882a593Smuzhiyun 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) 700*4882a593Smuzhiyun 701*4882a593Smuzhiyun # Check that we can fetch from various network transports 702*4882a593Smuzhiyun netcheck = check_connectivity(d) 703*4882a593Smuzhiyun status.addresult(netcheck) 704*4882a593Smuzhiyun if netcheck: 705*4882a593Smuzhiyun status.network_error = True 706*4882a593Smuzhiyun 707*4882a593Smuzhiyun nolibs = d.getVar('NO32LIBS') 708*4882a593Smuzhiyun if not nolibs: 709*4882a593Smuzhiyun lib32path = '/lib' 710*4882a593Smuzhiyun if os.path.exists('/lib64') and ( os.path.islink('/lib64') or os.path.islink('/lib') ): 711*4882a593Smuzhiyun lib32path = '/lib32' 712*4882a593Smuzhiyun 713*4882a593Smuzhiyun if os.path.exists('%s/libc.so.6' % lib32path) and not os.path.exists('/usr/include/gnu/stubs-32.h'): 714*4882a593Smuzhiyun status.addresult("You have a 32-bit libc, but no 32-bit headers. You must install the 32-bit libc headers.\n") 715*4882a593Smuzhiyun 716*4882a593Smuzhiyun bbpaths = d.getVar('BBPATH').split(":") 717*4882a593Smuzhiyun if ("." in bbpaths or "./" in bbpaths or "" in bbpaths): 718*4882a593Smuzhiyun status.addresult("BBPATH references the current directory, either through " \ 719*4882a593Smuzhiyun "an empty entry, a './' or a '.'.\n\t This is unsafe and means your "\ 720*4882a593Smuzhiyun "layer configuration is adding empty elements to BBPATH.\n\t "\ 721*4882a593Smuzhiyun "Please check your layer.conf files and other BBPATH " \ 722*4882a593Smuzhiyun "settings to remove the current working directory " \ 723*4882a593Smuzhiyun "references.\n" \ 724*4882a593Smuzhiyun "Parsed BBPATH is" + str(bbpaths)); 725*4882a593Smuzhiyun 726*4882a593Smuzhiyun oes_bb_conf = d.getVar( 'OES_BITBAKE_CONF') 727*4882a593Smuzhiyun if not oes_bb_conf: 728*4882a593Smuzhiyun status.addresult('You are not using the OpenEmbedded version of conf/bitbake.conf. This means your environment is misconfigured, in particular check BBPATH.\n') 729*4882a593Smuzhiyun 730*4882a593Smuzhiyun # The length of TMPDIR can't be longer than 410 731*4882a593Smuzhiyun status.addresult(check_path_length(tmpdir, "TMPDIR", 410)) 732*4882a593Smuzhiyun 733*4882a593Smuzhiyun # Check that TMPDIR isn't located on nfs 734*4882a593Smuzhiyun status.addresult(check_not_nfs(tmpdir, "TMPDIR")) 735*4882a593Smuzhiyun 736*4882a593Smuzhiyun # Check for case-insensitive file systems (such as Linux in Docker on 737*4882a593Smuzhiyun # macOS with default HFS+ file system) 738*4882a593Smuzhiyun status.addresult(check_case_sensitive(tmpdir, "TMPDIR")) 739*4882a593Smuzhiyun 740*4882a593Smuzhiyundef sanity_check_locale(d): 741*4882a593Smuzhiyun """ 742*4882a593Smuzhiyun Currently bitbake switches locale to en_US.UTF-8 so check that this locale actually exists. 743*4882a593Smuzhiyun """ 744*4882a593Smuzhiyun import locale 745*4882a593Smuzhiyun try: 746*4882a593Smuzhiyun locale.setlocale(locale.LC_ALL, "en_US.UTF-8") 747*4882a593Smuzhiyun except locale.Error: 748*4882a593Smuzhiyun raise_sanity_error("Your system needs to support the en_US.UTF-8 locale.", d) 749*4882a593Smuzhiyun 750*4882a593Smuzhiyundef check_sanity_everybuild(status, d): 751*4882a593Smuzhiyun import os, stat 752*4882a593Smuzhiyun # Sanity tests which test the users environment so need to run at each build (or are so cheap 753*4882a593Smuzhiyun # it makes sense to always run them. 754*4882a593Smuzhiyun 755*4882a593Smuzhiyun if 0 == os.getuid(): 756*4882a593Smuzhiyun raise_sanity_error("Do not use Bitbake as root.", d) 757*4882a593Smuzhiyun 758*4882a593Smuzhiyun # Check the Python version, we now have a minimum of Python 3.6 759*4882a593Smuzhiyun import sys 760*4882a593Smuzhiyun if sys.hexversion < 0x030600F0: 761*4882a593Smuzhiyun status.addresult('The system requires at least Python 3.6 to run. Please update your Python interpreter.\n') 762*4882a593Smuzhiyun 763*4882a593Smuzhiyun # Check the bitbake version meets minimum requirements 764*4882a593Smuzhiyun minversion = d.getVar('BB_MIN_VERSION') 765*4882a593Smuzhiyun if bb.utils.vercmp_string_op(bb.__version__, minversion, "<"): 766*4882a593Smuzhiyun status.addresult('Bitbake version %s is required and version %s was found\n' % (minversion, bb.__version__)) 767*4882a593Smuzhiyun 768*4882a593Smuzhiyun sanity_check_locale(d) 769*4882a593Smuzhiyun 770*4882a593Smuzhiyun paths = d.getVar('PATH').split(":") 771*4882a593Smuzhiyun if "." in paths or "./" in paths or "" in paths: 772*4882a593Smuzhiyun status.addresult("PATH contains '.', './' or '' (empty element), which will break the build, please remove this.\nParsed PATH is " + str(paths) + "\n") 773*4882a593Smuzhiyun 774*4882a593Smuzhiyun #Check if bitbake is present in PATH environment variable 775*4882a593Smuzhiyun bb_check = bb.utils.which(d.getVar('PATH'), 'bitbake') 776*4882a593Smuzhiyun if not bb_check: 777*4882a593Smuzhiyun bb.warn("bitbake binary is not found in PATH, did you source the script?") 778*4882a593Smuzhiyun 779*4882a593Smuzhiyun # Check whether 'inherit' directive is found (used for a class to inherit) 780*4882a593Smuzhiyun # in conf file it's supposed to be uppercase INHERIT 781*4882a593Smuzhiyun inherit = d.getVar('inherit') 782*4882a593Smuzhiyun if inherit: 783*4882a593Smuzhiyun status.addresult("Please don't use inherit directive in your local.conf. The directive is supposed to be used in classes and recipes only to inherit of bbclasses. Here INHERIT should be used.\n") 784*4882a593Smuzhiyun 785*4882a593Smuzhiyun # Check that the DISTRO is valid, if set 786*4882a593Smuzhiyun # need to take into account DISTRO renaming DISTRO 787*4882a593Smuzhiyun distro = d.getVar('DISTRO') 788*4882a593Smuzhiyun if distro and distro != "nodistro": 789*4882a593Smuzhiyun if not ( check_conf_exists("conf/distro/${DISTRO}.conf", d) or check_conf_exists("conf/distro/include/${DISTRO}.inc", d) ): 790*4882a593Smuzhiyun status.addresult("DISTRO '%s' not found. Please set a valid DISTRO in your local.conf\n" % d.getVar("DISTRO")) 791*4882a593Smuzhiyun 792*4882a593Smuzhiyun # Check that these variables don't use tilde-expansion as we don't do that 793*4882a593Smuzhiyun for v in ("TMPDIR", "DL_DIR", "SSTATE_DIR"): 794*4882a593Smuzhiyun if d.getVar(v).startswith("~"): 795*4882a593Smuzhiyun status.addresult("%s uses ~ but Bitbake will not expand this, use an absolute path or variables." % v) 796*4882a593Smuzhiyun 797*4882a593Smuzhiyun # Check that DL_DIR is set, exists and is writable. In theory, we should never even hit the check if DL_DIR isn't 798*4882a593Smuzhiyun # set, since so much relies on it being set. 799*4882a593Smuzhiyun dldir = d.getVar('DL_DIR') 800*4882a593Smuzhiyun if not dldir: 801*4882a593Smuzhiyun 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") 802*4882a593Smuzhiyun if os.path.exists(dldir) and not os.access(dldir, os.W_OK): 803*4882a593Smuzhiyun status.addresult("DL_DIR: %s exists but you do not appear to have write access to it. \n" % dldir) 804*4882a593Smuzhiyun check_symlink(dldir, d) 805*4882a593Smuzhiyun 806*4882a593Smuzhiyun # Check that the MACHINE is valid, if it is set 807*4882a593Smuzhiyun machinevalid = True 808*4882a593Smuzhiyun if d.getVar('MACHINE'): 809*4882a593Smuzhiyun if not check_conf_exists("conf/machine/${MACHINE}.conf", d): 810*4882a593Smuzhiyun status.addresult('MACHINE=%s is invalid. Please set a valid MACHINE in your local.conf, environment or other configuration file.\n' % (d.getVar('MACHINE'))) 811*4882a593Smuzhiyun machinevalid = False 812*4882a593Smuzhiyun else: 813*4882a593Smuzhiyun status.addresult(check_sanity_validmachine(d)) 814*4882a593Smuzhiyun else: 815*4882a593Smuzhiyun status.addresult('Please set a MACHINE in your local.conf or environment\n') 816*4882a593Smuzhiyun machinevalid = False 817*4882a593Smuzhiyun if machinevalid: 818*4882a593Smuzhiyun status.addresult(check_toolchain(d)) 819*4882a593Smuzhiyun 820*4882a593Smuzhiyun # Check that the SDKMACHINE is valid, if it is set 821*4882a593Smuzhiyun if d.getVar('SDKMACHINE'): 822*4882a593Smuzhiyun if not check_conf_exists("conf/machine-sdk/${SDKMACHINE}.conf", d): 823*4882a593Smuzhiyun status.addresult('Specified SDKMACHINE value is not valid\n') 824*4882a593Smuzhiyun elif d.getVar('SDK_ARCH', False) == "${BUILD_ARCH}": 825*4882a593Smuzhiyun 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') 826*4882a593Smuzhiyun 827*4882a593Smuzhiyun # If SDK_VENDOR looks like "-my-sdk" then the triples are badly formed so fail early 828*4882a593Smuzhiyun sdkvendor = d.getVar("SDK_VENDOR") 829*4882a593Smuzhiyun if not (sdkvendor.startswith("-") and sdkvendor.count("-") == 1): 830*4882a593Smuzhiyun status.addresult("SDK_VENDOR should be of the form '-foosdk' with a single dash; found '%s'\n" % sdkvendor) 831*4882a593Smuzhiyun 832*4882a593Smuzhiyun check_supported_distro(d) 833*4882a593Smuzhiyun 834*4882a593Smuzhiyun omask = os.umask(0o022) 835*4882a593Smuzhiyun if omask & 0o755: 836*4882a593Smuzhiyun status.addresult("Please use a umask which allows a+rx and u+rwx\n") 837*4882a593Smuzhiyun os.umask(omask) 838*4882a593Smuzhiyun 839*4882a593Smuzhiyun if d.getVar('TARGET_ARCH') == "arm": 840*4882a593Smuzhiyun # This path is no longer user-readable in modern (very recent) Linux 841*4882a593Smuzhiyun try: 842*4882a593Smuzhiyun if os.path.exists("/proc/sys/vm/mmap_min_addr"): 843*4882a593Smuzhiyun f = open("/proc/sys/vm/mmap_min_addr", "r") 844*4882a593Smuzhiyun try: 845*4882a593Smuzhiyun if (int(f.read().strip()) > 65536): 846*4882a593Smuzhiyun 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") 847*4882a593Smuzhiyun finally: 848*4882a593Smuzhiyun f.close() 849*4882a593Smuzhiyun except: 850*4882a593Smuzhiyun pass 851*4882a593Smuzhiyun 852*4882a593Smuzhiyun for checkdir in ['COREBASE', 'TMPDIR']: 853*4882a593Smuzhiyun val = d.getVar(checkdir) 854*4882a593Smuzhiyun if val.find('..') != -1: 855*4882a593Smuzhiyun status.addresult("Error, you have '..' in your %s directory path. Please ensure the variable contains an absolute path as this can break some recipe builds in obtuse ways." % checkdir) 856*4882a593Smuzhiyun if val.find('+') != -1: 857*4882a593Smuzhiyun status.addresult("Error, you have an invalid character (+) in your %s directory path. Please move the installation to a directory which doesn't include any + characters." % checkdir) 858*4882a593Smuzhiyun if val.find('@') != -1: 859*4882a593Smuzhiyun status.addresult("Error, you have an invalid character (@) in your %s directory path. Please move the installation to a directory which doesn't include any @ characters." % checkdir) 860*4882a593Smuzhiyun if val.find(' ') != -1: 861*4882a593Smuzhiyun status.addresult("Error, you have a space in your %s directory path. Please move the installation to a directory which doesn't include a space since autotools doesn't support this." % checkdir) 862*4882a593Smuzhiyun if val.find('%') != -1: 863*4882a593Smuzhiyun status.addresult("Error, you have an invalid character (%) in your %s directory path which causes problems with python string formatting. Please move the installation to a directory which doesn't include any % characters." % checkdir) 864*4882a593Smuzhiyun 865*4882a593Smuzhiyun # Check the format of MIRRORS, PREMIRRORS and SSTATE_MIRRORS 866*4882a593Smuzhiyun import re 867*4882a593Smuzhiyun mirror_vars = ['MIRRORS', 'PREMIRRORS', 'SSTATE_MIRRORS'] 868*4882a593Smuzhiyun protocols = ['http', 'ftp', 'file', 'https', \ 869*4882a593Smuzhiyun 'git', 'gitsm', 'hg', 'osc', 'p4', 'svn', \ 870*4882a593Smuzhiyun 'bzr', 'cvs', 'npm', 'sftp', 'ssh', 's3', 'az', 'ftps', 'crate'] 871*4882a593Smuzhiyun for mirror_var in mirror_vars: 872*4882a593Smuzhiyun mirrors = (d.getVar(mirror_var) or '').replace('\\n', ' ').split() 873*4882a593Smuzhiyun 874*4882a593Smuzhiyun # Split into pairs 875*4882a593Smuzhiyun if len(mirrors) % 2 != 0: 876*4882a593Smuzhiyun bb.warn('Invalid mirror variable value for %s: %s, should contain paired members.' % (mirror_var, str(mirrors))) 877*4882a593Smuzhiyun continue 878*4882a593Smuzhiyun mirrors = list(zip(*[iter(mirrors)]*2)) 879*4882a593Smuzhiyun 880*4882a593Smuzhiyun for mirror_entry in mirrors: 881*4882a593Smuzhiyun pattern, mirror = mirror_entry 882*4882a593Smuzhiyun 883*4882a593Smuzhiyun decoded = bb.fetch2.decodeurl(pattern) 884*4882a593Smuzhiyun try: 885*4882a593Smuzhiyun pattern_scheme = re.compile(decoded[0]) 886*4882a593Smuzhiyun except re.error as exc: 887*4882a593Smuzhiyun bb.warn('Invalid scheme regex (%s) in %s; %s' % (pattern, mirror_var, mirror_entry)) 888*4882a593Smuzhiyun continue 889*4882a593Smuzhiyun 890*4882a593Smuzhiyun if not any(pattern_scheme.match(protocol) for protocol in protocols): 891*4882a593Smuzhiyun bb.warn('Invalid protocol (%s) in %s: %s' % (decoded[0], mirror_var, mirror_entry)) 892*4882a593Smuzhiyun continue 893*4882a593Smuzhiyun 894*4882a593Smuzhiyun if not any(mirror.startswith(protocol + '://') for protocol in protocols): 895*4882a593Smuzhiyun bb.warn('Invalid protocol in %s: %s' % (mirror_var, mirror_entry)) 896*4882a593Smuzhiyun continue 897*4882a593Smuzhiyun 898*4882a593Smuzhiyun if mirror.startswith('file://'): 899*4882a593Smuzhiyun import urllib 900*4882a593Smuzhiyun check_symlink(urllib.parse.urlparse(mirror).path, d) 901*4882a593Smuzhiyun # SSTATE_MIRROR ends with a /PATH string 902*4882a593Smuzhiyun if mirror.endswith('/PATH'): 903*4882a593Smuzhiyun # remove /PATH$ from SSTATE_MIRROR to get a working 904*4882a593Smuzhiyun # base directory path 905*4882a593Smuzhiyun mirror_base = urllib.parse.urlparse(mirror[:-1*len('/PATH')]).path 906*4882a593Smuzhiyun check_symlink(mirror_base, d) 907*4882a593Smuzhiyun 908*4882a593Smuzhiyun # Check sstate mirrors aren't being used with a local hash server and no remote 909*4882a593Smuzhiyun hashserv = d.getVar("BB_HASHSERVE") 910*4882a593Smuzhiyun if d.getVar("SSTATE_MIRRORS") and hashserv and hashserv.startswith("unix://") and not d.getVar("BB_HASHSERVE_UPSTREAM"): 911*4882a593Smuzhiyun bb.warn("You are using a local hash equivalence server but have configured an sstate mirror. This will likely mean no sstate will match from the mirror. You may wish to disable the hash equivalence use (BB_HASHSERVE), or use a hash equivalence server alongside the sstate mirror.") 912*4882a593Smuzhiyun 913*4882a593Smuzhiyun # Check that TMPDIR hasn't changed location since the last time we were run 914*4882a593Smuzhiyun tmpdir = d.getVar('TMPDIR') 915*4882a593Smuzhiyun checkfile = os.path.join(tmpdir, "saved_tmpdir") 916*4882a593Smuzhiyun if os.path.exists(checkfile): 917*4882a593Smuzhiyun with open(checkfile, "r") as f: 918*4882a593Smuzhiyun saved_tmpdir = f.read().strip() 919*4882a593Smuzhiyun if (saved_tmpdir != tmpdir): 920*4882a593Smuzhiyun status.addresult("Error, TMPDIR has changed location. You need to either move it back to %s or delete it and rebuild\n" % saved_tmpdir) 921*4882a593Smuzhiyun else: 922*4882a593Smuzhiyun bb.utils.mkdirhier(tmpdir) 923*4882a593Smuzhiyun # Remove setuid, setgid and sticky bits from TMPDIR 924*4882a593Smuzhiyun try: 925*4882a593Smuzhiyun os.chmod(tmpdir, os.stat(tmpdir).st_mode & ~ stat.S_ISUID) 926*4882a593Smuzhiyun os.chmod(tmpdir, os.stat(tmpdir).st_mode & ~ stat.S_ISGID) 927*4882a593Smuzhiyun os.chmod(tmpdir, os.stat(tmpdir).st_mode & ~ stat.S_ISVTX) 928*4882a593Smuzhiyun except OSError as exc: 929*4882a593Smuzhiyun bb.warn("Unable to chmod TMPDIR: %s" % exc) 930*4882a593Smuzhiyun with open(checkfile, "w") as f: 931*4882a593Smuzhiyun f.write(tmpdir) 932*4882a593Smuzhiyun 933*4882a593Smuzhiyun # If /bin/sh is a symlink, check that it points to dash or bash 934*4882a593Smuzhiyun if os.path.islink('/bin/sh'): 935*4882a593Smuzhiyun real_sh = os.path.realpath('/bin/sh') 936*4882a593Smuzhiyun # Due to update-alternatives, the shell name may take various 937*4882a593Smuzhiyun # forms, such as /bin/dash, bin/bash, /bin/bash.bash ... 938*4882a593Smuzhiyun if '/dash' not in real_sh and '/bash' not in real_sh: 939*4882a593Smuzhiyun status.addresult("Error, /bin/sh links to %s, must be dash or bash\n" % real_sh) 940*4882a593Smuzhiyun 941*4882a593Smuzhiyundef check_sanity(sanity_data): 942*4882a593Smuzhiyun class SanityStatus(object): 943*4882a593Smuzhiyun def __init__(self): 944*4882a593Smuzhiyun self.messages = "" 945*4882a593Smuzhiyun self.network_error = False 946*4882a593Smuzhiyun 947*4882a593Smuzhiyun def addresult(self, message): 948*4882a593Smuzhiyun if message: 949*4882a593Smuzhiyun self.messages = self.messages + message 950*4882a593Smuzhiyun 951*4882a593Smuzhiyun status = SanityStatus() 952*4882a593Smuzhiyun 953*4882a593Smuzhiyun tmpdir = sanity_data.getVar('TMPDIR') 954*4882a593Smuzhiyun sstate_dir = sanity_data.getVar('SSTATE_DIR') 955*4882a593Smuzhiyun 956*4882a593Smuzhiyun check_symlink(sstate_dir, sanity_data) 957*4882a593Smuzhiyun 958*4882a593Smuzhiyun # Check saved sanity info 959*4882a593Smuzhiyun last_sanity_version = 0 960*4882a593Smuzhiyun last_tmpdir = "" 961*4882a593Smuzhiyun last_sstate_dir = "" 962*4882a593Smuzhiyun last_nativelsbstr = "" 963*4882a593Smuzhiyun sanityverfile = sanity_data.expand("${TOPDIR}/cache/sanity_info") 964*4882a593Smuzhiyun if os.path.exists(sanityverfile): 965*4882a593Smuzhiyun with open(sanityverfile, 'r') as f: 966*4882a593Smuzhiyun for line in f: 967*4882a593Smuzhiyun if line.startswith('SANITY_VERSION'): 968*4882a593Smuzhiyun last_sanity_version = int(line.split()[1]) 969*4882a593Smuzhiyun if line.startswith('TMPDIR'): 970*4882a593Smuzhiyun last_tmpdir = line.split()[1] 971*4882a593Smuzhiyun if line.startswith('SSTATE_DIR'): 972*4882a593Smuzhiyun last_sstate_dir = line.split()[1] 973*4882a593Smuzhiyun if line.startswith('NATIVELSBSTRING'): 974*4882a593Smuzhiyun last_nativelsbstr = line.split()[1] 975*4882a593Smuzhiyun 976*4882a593Smuzhiyun check_sanity_everybuild(status, sanity_data) 977*4882a593Smuzhiyun 978*4882a593Smuzhiyun sanity_version = int(sanity_data.getVar('SANITY_VERSION') or 1) 979*4882a593Smuzhiyun network_error = False 980*4882a593Smuzhiyun # NATIVELSBSTRING var may have been overridden with "universal", so 981*4882a593Smuzhiyun # get actual host distribution id and version 982*4882a593Smuzhiyun nativelsbstr = lsb_distro_identifier(sanity_data) 983*4882a593Smuzhiyun if last_sanity_version < sanity_version or last_nativelsbstr != nativelsbstr: 984*4882a593Smuzhiyun check_sanity_version_change(status, sanity_data) 985*4882a593Smuzhiyun status.addresult(check_sanity_sstate_dir_change(sstate_dir, sanity_data)) 986*4882a593Smuzhiyun else: 987*4882a593Smuzhiyun if last_sstate_dir != sstate_dir: 988*4882a593Smuzhiyun status.addresult(check_sanity_sstate_dir_change(sstate_dir, sanity_data)) 989*4882a593Smuzhiyun 990*4882a593Smuzhiyun if os.path.exists(os.path.dirname(sanityverfile)) and not status.messages: 991*4882a593Smuzhiyun with open(sanityverfile, 'w') as f: 992*4882a593Smuzhiyun f.write("SANITY_VERSION %s\n" % sanity_version) 993*4882a593Smuzhiyun f.write("TMPDIR %s\n" % tmpdir) 994*4882a593Smuzhiyun f.write("SSTATE_DIR %s\n" % sstate_dir) 995*4882a593Smuzhiyun f.write("NATIVELSBSTRING %s\n" % nativelsbstr) 996*4882a593Smuzhiyun 997*4882a593Smuzhiyun sanity_handle_abichanges(status, sanity_data) 998*4882a593Smuzhiyun 999*4882a593Smuzhiyun if status.messages != "": 1000*4882a593Smuzhiyun raise_sanity_error(sanity_data.expand(status.messages), sanity_data, status.network_error) 1001*4882a593Smuzhiyun 1002*4882a593Smuzhiyunaddhandler config_reparse_eventhandler 1003*4882a593Smuzhiyunconfig_reparse_eventhandler[eventmask] = "bb.event.ConfigParsed" 1004*4882a593Smuzhiyunpython config_reparse_eventhandler() { 1005*4882a593Smuzhiyun sanity_check_conffiles(e.data) 1006*4882a593Smuzhiyun} 1007*4882a593Smuzhiyun 1008*4882a593Smuzhiyunaddhandler check_sanity_eventhandler 1009*4882a593Smuzhiyuncheck_sanity_eventhandler[eventmask] = "bb.event.SanityCheck bb.event.NetworkTest" 1010*4882a593Smuzhiyunpython check_sanity_eventhandler() { 1011*4882a593Smuzhiyun if bb.event.getName(e) == "SanityCheck": 1012*4882a593Smuzhiyun sanity_data = bb.data.createCopy(e.data) 1013*4882a593Smuzhiyun check_sanity(sanity_data) 1014*4882a593Smuzhiyun if e.generateevents: 1015*4882a593Smuzhiyun sanity_data.setVar("SANITY_USE_EVENTS", "1") 1016*4882a593Smuzhiyun bb.event.fire(bb.event.SanityCheckPassed(), e.data) 1017*4882a593Smuzhiyun elif bb.event.getName(e) == "NetworkTest": 1018*4882a593Smuzhiyun sanity_data = bb.data.createCopy(e.data) 1019*4882a593Smuzhiyun if e.generateevents: 1020*4882a593Smuzhiyun sanity_data.setVar("SANITY_USE_EVENTS", "1") 1021*4882a593Smuzhiyun bb.event.fire(bb.event.NetworkTestFailed() if check_connectivity(sanity_data) else bb.event.NetworkTestPassed(), e.data) 1022*4882a593Smuzhiyun 1023*4882a593Smuzhiyun return 1024*4882a593Smuzhiyun} 1025