diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f179c51..3dc9e77 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,10 +1,16 @@ -# Run shellcheck and shfmt on all shell files and yapf on all Python files in this repository +# Run shellcheck and shfmt on all shell files and several Python linters on all Python files in this repository name: Lint checks on: [push, pull_request] jobs: + python: + strategy: + fail-fast: false + matrix: + version: ['3.11', '3.10', '3.9', '3.8'] + uses: ClangBuiltLinux/actions-workflows/.github/workflows/python_lint.yml@main + with: + python_version: ${{ matrix.version }} shellcheck: uses: ClangBuiltLinux/actions-workflows/.github/workflows/shellcheck.yml@main shfmt: uses: ClangBuiltLinux/actions-workflows/.github/workflows/shfmt.yml@main - yapf: - uses: ClangBuiltLinux/actions-workflows/.github/workflows/yapf.yml@main diff --git a/boot-qemu.py b/boot-qemu.py index 43ef6e5..7c99bbb 100755 --- a/boot-qemu.py +++ b/boot-qemu.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +# pylint: disable=invalid-name import argparse import os @@ -7,6 +8,7 @@ import re import shutil import subprocess +import sys import utils @@ -54,7 +56,7 @@ def parse_arguments(): "--interactive", "--shell", action="store_true", - help= + help= # noqa: E251 "Instead of immediately shutting down the machine upon successful boot, pass 'rdinit=/bin/sh' on the kernel command line to allow interacting with the machine via a shell." ) parser.add_argument( @@ -62,20 +64,20 @@ def parse_arguments(): "--kernel-location", required=True, type=str, - help= + help= # noqa: E251 "Path to kernel image or kernel build folder to search for image in. Can be an absolute or relative path." ) parser.add_argument( "--no-kvm", action="store_true", - help= + help= # noqa: E251 "Do not use KVM for acceleration even when supported (only recommended for debugging)." ) parser.add_argument( "-s", "--smp", type=int, - help= + help= # noqa: E251 "Number of processors for virtual machine. By default, only machines spawned with KVM will use multiple vCPUS." ) parser.add_argument( @@ -112,7 +114,6 @@ def can_use_kvm(can_test_for_kvm, guest_arch): if can_test_for_kvm: # /dev/kvm must exist to use KVM with QEMU if Path("/dev/kvm").exists(): - guest_arch = args.architecture host_arch = platform.machine() if host_arch == "aarch64": @@ -120,16 +121,18 @@ def can_use_kvm(can_test_for_kvm, guest_arch): if "arm64" in guest_arch: return True # 32-bit EL1 is not always supported, test for it first - if guest_arch == "arm" or guest_arch == "arm32_v7": - check_32_bit_el1_exec = base_folder.joinpath( + if guest_arch in ("arm", "arm32_v7"): + check_32_bit_el1 = base_folder.joinpath( "utils", "aarch64_32_bit_el1_supported") - check_32_bit_el1 = subprocess.run([check_32_bit_el1_exec]) - return check_32_bit_el1.returncode == 0 + try: + subprocess.run([check_32_bit_el1], check=True) + except subprocess.CalledSubprocessError: + return False + return True if host_arch == "x86_64" and "x86" in guest_arch: # Check /proc/cpuinfo for whether or not the machine supports hardware virtualization - with open("/proc/cpuinfo") as f: - cpuinfo = f.read() + cpuinfo = Path("/proc/cpuinfo").read_text(encoding='utf-8') # SVM is AMD, VMX is Intel return cpuinfo.count("svm") > 0 or cpuinfo.count("vmx") > 0 @@ -186,8 +189,8 @@ def get_smp_value(args): # CONFIG_NR_CPUS then get the actual value if possible. config_nr_cpus = 8 if config_file: - with open(config_file) as f: - for line in f: + with open(config_file, encoding='utf-8') as file: + for line in file: if "CONFIG_NR_CPUS=" in line: config_nr_cpus = int(line.split("=", 1)[1]) break @@ -400,7 +403,7 @@ def get_qemu_args(cfg): qemu = "qemu-system-arm" qemu_args += ["-machine", "romulus-bmc"] - elif arch == "arm" or arch == "arm32_v7": + elif arch in ("arm", "arm32_v7"): append += " console=ttyAMA0 earlycon" kernel_arch = "arm" qemu_args += ["-machine", "virt"] @@ -410,7 +413,7 @@ def get_qemu_args(cfg): else: qemu = "qemu-system-arm" - elif arch == "arm64" or arch == "arm64be": + elif arch in ("arm64", "arm64be"): append += " console=ttyAMA0 earlycon" kernel_arch = "arm64" kernel_image = "Image.gz" @@ -452,7 +455,7 @@ def get_qemu_args(cfg): qemu_args += ["-cpu", "m68040"] qemu_args += ["-M", "q800"] - elif arch == "mips" or arch == "mipsel": + elif arch in ("mips", "mipsel"): kernel_arch = "mips" kernel_image = "vmlinux" qemu = f"qemu-system-{arch}" @@ -658,23 +661,22 @@ def launch_qemu(cfg): utils.check_cmd("lsof") lsof = subprocess.run(["lsof", "-i:1234"], stdout=subprocess.DEVNULL, - stderr=subprocess.DEVNULL) + stderr=subprocess.DEVNULL, + check=False) if lsof.returncode == 0: utils.die("Port 1234 is already in use, is QEMU running?") utils.green("Starting QEMU with GDB connection on port 1234...") - qemu_process = subprocess.Popen(qemu_cmd + ["-s", "-S"]) - - utils.green("Starting GDB...") - utils.check_cmd(gdb_bin) - gdb_cmd = [gdb_bin] - gdb_cmd += [kernel_location.joinpath("vmlinux")] - gdb_cmd += ["-ex", "target remote :1234"] - subprocess.run(gdb_cmd) + with subprocess.Popen(qemu_cmd + ["-s", "-S"]) as qemu_process: + utils.green("Starting GDB...") + utils.check_cmd(gdb_bin) + gdb_cmd = [gdb_bin] + gdb_cmd += [kernel_location.joinpath("vmlinux")] + gdb_cmd += ["-ex", "target remote :1234"] + subprocess.run(gdb_cmd, check=False) - utils.red("Killing QEMU...") - qemu_process.kill() - qemu_process.wait() + utils.red("Killing QEMU...") + qemu_process.kill() answer = input("Re-run QEMU + gdb? [y/n] ") if answer.lower() == "n": @@ -695,14 +697,14 @@ def launch_qemu(cfg): utils.red("ERROR: QEMU timed out!") else: utils.red("ERROR: QEMU did not exit cleanly!") - exit(ex.returncode) + sys.exit(ex.returncode) if __name__ == '__main__': - args = parse_arguments() + arguments = parse_arguments() # Build configuration from arguments and QEMU flags - cfg = setup_cfg(args) - cfg = get_qemu_args(cfg) + config = setup_cfg(arguments) + config = get_qemu_args(config) - launch_qemu(cfg) + launch_qemu(config) diff --git a/boot-uml.py b/boot-uml.py index 0169644..ff2860a 100755 --- a/boot-uml.py +++ b/boot-uml.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +# pylint: disable=invalid-name import argparse from pathlib import Path @@ -22,7 +23,7 @@ def parse_arguments(): "-i", "--interactive", action="store_true", - help= + help= # noqa: E251 "Instead of immediately shutting down upon successful boot, pass 'init=/bin/sh' to the UML executable to allow interacting with UML via a shell." ) parser.add_argument( @@ -30,7 +31,7 @@ def parse_arguments(): "--kernel-location", required=True, type=str, - help= + help= # noqa: E251 "Path to UML executable ('linux') or kernel build folder to search for executable in. Can be an absolute or relative path." ) @@ -57,17 +58,17 @@ def decomp_rootfs(): return rootfs -def run_kernel(kernel, rootfs, interactive): +def run_kernel(kernel_image, rootfs, interactive): """ Run UML command with path to rootfs and additional arguments based on user input. Parameters: - * kernel (Path): kernel Path object containing full path to kernel. + * kernel_image (Path): kernel Path object containing full path to kernel. * rootfs (Path): rootfs Path object containing full path to rootfs. * interactive (bool): Whether or not to run UML interactively. """ - uml_cmd = [kernel, f"ubd0={rootfs}"] + uml_cmd = [kernel_image, f"ubd0={rootfs}"] if interactive: uml_cmd += ["init=/bin/sh"] print(f"$ {' '.join([str(element) for element in uml_cmd])}") @@ -77,6 +78,5 @@ def run_kernel(kernel, rootfs, interactive): if __name__ == '__main__': args = parse_arguments() kernel = utils.get_full_kernel_path(args.kernel_location, "linux") - rootfs = decomp_rootfs() - run_kernel(kernel, rootfs, args.interactive) + run_kernel(kernel, decomp_rootfs(), args.interactive) diff --git a/utils.py b/utils.py index af2da94..b6d378b 100755 --- a/utils.py +++ b/utils.py @@ -2,6 +2,7 @@ from pathlib import Path import shutil +import sys def check_cmd(cmd): @@ -26,7 +27,7 @@ def die(string): automatically. """ red(f"ERROR: {string}") - exit(1) + sys.exit(1) def get_full_kernel_path(kernel_location, image, arch=None): @@ -51,7 +52,7 @@ def get_full_kernel_path(kernel_location, image, arch=None): else: # If the image is an uncompressed vmlinux or a UML image, it is in the # root of the build folder - if image == "vmlinux" or image == "linux": + if image in ("vmlinux", "linux"): kernel = kernel_location.joinpath(image) # Otherwise, it is in the architecture's boot directory else: