From 28da03326794f93b7880558c06f00fdcfad30205 Mon Sep 17 00:00:00 2001 From: Antoine Fontaine Date: Mon, 13 Apr 2020 10:51:56 +0200 Subject: [PATCH] pmb.parse.kconfig: implement anbox kconfig check (MR 1916) fixes https://gitlab.com/postmarketOS/pmbootstrap/-/issues/1891. --- pmb/build/menuconfig.py | 3 +- pmb/config/__init__.py | 27 ++++++++++ pmb/helpers/frontend.py | 8 ++- pmb/parse/arguments.py | 2 + pmb/parse/kconfig.py | 106 ++++++++++++++++++++++++++++++---------- 5 files changed, 116 insertions(+), 30 deletions(-) diff --git a/pmb/build/menuconfig.py b/pmb/build/menuconfig.py index 620555de..3eec46b9 100644 --- a/pmb/build/menuconfig.py +++ b/pmb/build/menuconfig.py @@ -146,4 +146,5 @@ def menuconfig(args, pkgname): pmb.build.checksum.update(args, pkgname) # Check config - pmb.parse.kconfig.check(args, apkbuild["_flavor"], details=True) + pmb.parse.kconfig.check(args, apkbuild["_flavor"], force_anbox_check=False, + details=True) diff --git a/pmb/config/__init__.py b/pmb/config/__init__.py index 5f5e4884..0246a54c 100644 --- a/pmb/config/__init__.py +++ b/pmb/config/__init__.py @@ -208,6 +208,32 @@ necessary_kconfig_options = { } } +# Necessary anbox kernel config options +necessary_kconfig_options_anbox = { + ">=0.0.0": { # all versions + "all": { # all arches + "SQUASHFS": True, + "SQUASHFS_XZ": True, + "SQUASHFS_XATTR": True, + "TMPFS_XATTR": True, + "ASHMEM": True, + "ANDROID_BINDER_IPC": True, + "ANDROID_BINDERFS": False, + "ANDROID_BINDER_DEVICES": ["binder", "hwbinder"], + "NETFILTER_XTABLES": True, + "NETFILTER_XT_MATCH_COMMENT": True, + "IP_NF_MANGLE": True, + "FUSE_FS": True, + "BLK_DEV_LOOP": True, + "TUN": True, + "VETH": True, + "VLAN_8021Q": True, # prerequisite for bridge + "BRIDGE": True, + "BRIDGE_VLAN_FILTERING": True, + } + }, +} + # # PARSE # @@ -260,6 +286,7 @@ apkbuild_attributes = { apkbuild_custom_valid_options = [ "!pmb:crossdirect", "!pmb:kconfig-check", + "pmb:kconfigcheck-anbox", "pmb:cross-native", "pmb:strict", ] diff --git a/pmb/helpers/frontend.py b/pmb/helpers/frontend.py index 1dcfbf2e..b39aebb4 100644 --- a/pmb/helpers/frontend.py +++ b/pmb/helpers/frontend.py @@ -247,7 +247,9 @@ def kconfig(args): if args.action_kconfig == "check": # Handle passing a file directly if args.file: - if pmb.parse.kconfig.check_file(args, args.package, details=True): + if pmb.parse.kconfig.check_file(args, args.package, + force_anbox_check=args.anbox, + details=True): logging.info("kconfig check succeeded!") return raise RuntimeError("kconfig check failed!") @@ -273,7 +275,9 @@ def kconfig(args): if "!pmb:kconfigcheck" in apkbuild["options"]: skipped += 1 continue - if not pmb.parse.kconfig.check(args, package, details=True): + if not pmb.parse.kconfig.check(args, package, + force_anbox_check=args.anbox, + details=True): error = True # At least one failure diff --git a/pmb/parse/arguments.py b/pmb/parse/arguments.py index 4b91e47a..c3d2bef5 100644 --- a/pmb/parse/arguments.py +++ b/pmb/parse/arguments.py @@ -258,6 +258,8 @@ def arguments_kconfig(subparser): check.add_argument("--arch", choices=arch_choices, dest="arch") check.add_argument("--file", action="store_true", help="check a file" " directly instead of a config in a package") + check.add_argument("--anbox", action="store_true", help="check" + " options needed for anbox too") check_package = check.add_argument("package", default="", nargs='?') if argcomplete: check_package.completer = kernel_completer diff --git a/pmb/parse/kconfig.py b/pmb/parse/kconfig.py index 0dd169fe..c8a0450d 100644 --- a/pmb/parse/kconfig.py +++ b/pmb/parse/kconfig.py @@ -19,15 +19,67 @@ def is_set(config, option): return re.search("^CONFIG_" + option + "=[ym]$", config, re.M) is not None -def check_config(config_path, config_path_pretty, config_arch, pkgver, details=False): +def is_in_array(config, option, string): + """ + Check, whether a config option contains string as an array element + """ + match = re.search("^CONFIG_" + option + "=\"(.*)\"$", config, re.M) + if match: + values = match.group(1).split(",") + return string in values + else: + return False + + +def check_option(component, details, config, config_path_pretty, option, option_value): + link = (f"https://wiki.postmarketos.org/wiki/kconfig#CONFIG_{option}") + warning_no_details = (f"WARNING: {config_path_pretty} isn't" + f" configured properly for {component}, run" + f" 'pmbootstrap kconfig check' for details!") + if isinstance(option_value, list): + for string in option_value: + if not is_in_array(config, option, string): + if details: + logging.info(f"WARNING: {config_path_pretty}:" + f' CONFIG_{option} should contain "{string}".' + f" See <{link}> for details.") + else: + logging.warning(warning_no_details) + return False + elif option_value in [True, False]: + if option_value != is_set(config, option): + if details: + should = "should" if option_value else "should *not*" + logging.info(f"WARNING: {config_path_pretty}: CONFIG_{option}" + f" {should} be set. See <{link}> for details.") + else: + logging.warning(warning_no_details) + return False + else: + raise RuntimeError("kconfig check code can only handle True/False and" + " arrays now, given value '" + str(option_value) + + "' is not supported. If you need this, please open" + " an issue.") + return True + + +def check_config(config_path, config_path_pretty, config_arch, pkgver, + anbox=False, details=False): logging.debug("Check kconfig: " + config_path) with open(config_path) as handle: config = handle.read() + if anbox: + options = pmb.config.necessary_kconfig_options_anbox + component = "anbox" + else: + options = pmb.config.necessary_kconfig_options + component = "postmarketOS" + # Loop through necessary config options, and print a warning, # if any is missing ret = True - for rule, archs_options in pmb.config.necessary_kconfig_options.items(): + for rule, archs_options in options.items(): # Skip options irrelevant for the current kernel's version if not pmb.parse.version.check_string(pkgver, rule): continue @@ -42,32 +94,16 @@ def check_config(config_path, config_path_pretty, config_arch, pkgver, details=F continue for option, option_value in options.items(): - if option_value not in [True, False]: - raise RuntimeError("kconfig check code can only handle" - " True/False right now, given value '" + - str(option_value) + "' is not supported. If you" - " need this, please open an issue.") - if option_value != is_set(config, option): + if not check_option(component, details, config, config_path_pretty, option, option_value): ret = False - if details: - should = "should" if option_value else "should *not*" - link = ("https://wiki.postmarketos.org/wiki/" - "Kernel_configuration#CONFIG_" + option) - logging.info("WARNING: " + config_path_pretty + ": CONFIG_" + option + " " + - should + " be set. See <" + link + - "> for details.") - else: - logging.warning("WARNING: " + config_path_pretty + " isn't configured" - " properly for postmarketOS, run" - " 'pmbootstrap kconfig check' for" - " details!") - break + if not details: + break # do not give too much error messages return ret -def check(args, pkgname, details=False): +def check(args, pkgname, force_anbox_check=False, details=False): """ - Check for necessary kernel config options. + Check for necessary kernel config options in a package. :returns: True when the check was successful, False otherwise """ @@ -82,13 +118,19 @@ def check(args, pkgname, details=False): # Read all kernel configs in the aport ret = True aport = pmb.helpers.pmaports.find(args, "linux-" + flavor) - pkgver = pmb.parse.apkbuild(args, aport + "/APKBUILD")["pkgver"] + apkbuild = pmb.parse.apkbuild(args, aport + "/APKBUILD") + pkgver = apkbuild["pkgver"] + check_anbox = force_anbox_check or ("pmb:kconfigcheck-anbox" in apkbuild["options"]) for config_path in glob.glob(aport + "/config-*"): # The architecture of the config is in the name, so it just needs to be # extracted config_arch = os.path.basename(config_path).split(".")[1] config_path_pretty = "linux-" + flavor + "/" + os.path.basename(config_path) - ret &= check_config(config_path, config_path_pretty, config_arch, pkgver, details) + ret &= check_config(config_path, config_path_pretty, config_arch, + pkgver, details=details) + if check_anbox: + ret &= check_config(config_path, config_path_pretty, config_arch, + pkgver, anbox=True, details=details) return ret @@ -124,9 +166,19 @@ def extract_version(config_file): return "unknown" -def check_file(args, config_file, details=False): +def check_file(args, config_file, anbox=False, details=False): + """ + Check for necessary kernel config options in a kconfig file. + + :returns: True when the check was successful, False otherwise + """ arch = extract_arch(config_file) version = extract_version(config_file) logging.debug("Check kconfig: parsed arch=" + arch + ", version=" + version + " from file: " + config_file) - return check_config(config_file, config_file, arch, version, details) + ret = check_config(config_file, config_file, arch, version, anbox=False, + details=details) + if anbox: + ret &= check_config(config_file, config_file, arch, version, anbox=True, + details=details) + return ret