#!/usr/bin/env python3 """Run the actual ARM programs against disposable metadata and sysfs fixtures.""" import json from pathlib import Path import subprocess import tempfile project = Path(__file__).resolve().parents[2] def run(binary, *args, ok=True): result = subprocess.run([str(project/'tools/in-void'), 'qemu-aarch64', str(project/'out'/binary), *map(str, args)], capture_output=True, text=True, timeout=20) assert (result.returncode == 0) == ok, (args, result.returncode, result.stdout, result.stderr) return result.stdout with tempfile.TemporaryDirectory(prefix='m3-', dir=project/'out') as directory: work = Path(directory) sysfs = work/'sys' blocks = sysfs/'class/block' blocks.mkdir(parents=True) for helper in ['fds', 'fds-burn', 'fds-inspect', 'fds-eject', 'fds-power', 'fds-stage0', 'fds-boottrace', 'fds-cartridged', 'fds-profile', 'fds-release']: assert f'Usage: {helper}' in run(helper, '--help') assert '0.1.0' in run(helper, '--version') assert 'activate windowmaker' in run('fds-profile', '--help') run('fds-profile', 'activate', 'windowmaker', ok=False) assert '0.1.0' in run('fds', '--version') assert '0.1.0' in run('fds-stage0', '--version') run('fds-stage0', ok=False) # Must refuse root-switch operations outside PID 1. assert json.loads(run('fds', '--json', 'info'))['target'] == 'aarch64 static-musl' fixture = project/'tests/fixtures/manifests/windowmaker.toml' assert json.loads(run('fds', '--json', 'inspect', fixture))['activation']['profile'] == 'windowmaker' assert json.loads(run('fds-inspect', fixture, '--json'))['activation']['profile'] == 'windowmaker' assert json.loads(run('fds', 'inspect', fixture, '--json'))['activation']['profile'] == 'windowmaker' assert 'BAY' in run('fds', 'format', 'data', '--help') assert 'TOKEN' in run('fds', 'recovery', 'repair', '--help') # Parse the legacy image form with global options in both positions. The # deliberately absent regular file reaches the operation's filesystem check. for binary, arguments in [ ('fds', ['inspect', '--json', 'image']), ('fds-inspect', ['--json', 'image']), ('fds-inspect', ['image', '--json']), ]: result = subprocess.run([str(project/'tools/in-void'), 'qemu-aarch64', str(project/'out'/binary), *arguments, str(work/'absent.img')], capture_output=True, text=True, timeout=20) assert result.returncode == 2 and result.stderr.startswith('fds: No such file'), result for binary, arguments in [ ('fds', ['run', '1', '/bin/app']), ('fds', ['recovery', 'repair', '1', '--confirm']), ('fds', ['format', 'system', 'root', '1', '--label', 'wrong']), ('fds-burn', ['data', '1', '--label', 'one', '--label', 'two']), ('fds-burn', ['--worker', '--unknown']), ('fds-cartridged', ['--notify', '--topology', '/sys']), ('fds-stage0', ['--probe', '/sys', '--check-cmdline', 'cmdline']), ('fds-profile', ['--session', 'activate', 'cli']), ('fds-power', ['--record-final', 'invalid']), ('fds-release', ['sign', 'directory']), ]: result = subprocess.run([str(project/'tools/in-void'), 'qemu-aarch64', str(project/'out'/binary), *arguments], capture_output=True, text=True, timeout=20) assert result.returncode == 2, (binary, arguments, result) assert 'error:' in result.stderr and '--help' in result.stderr, result malformed = work/'bad.toml' malformed.write_text(fixture.read_text().replace('profile = "windowmaker"', 'run = "/FDS/autorun.sh"')) run('fds', 'inspect', malformed, ok=False) malformed.write_bytes(b' ' * 65537) run('fds', 'inspect', malformed, ok=False) run('fds', 'eject', '99', ok=False) assert json.loads(run('fds-stage0', '--probe', sysfs))['state'] == 'missing' for name, major, minor in [('sdz1', 8, 241), ('nvme0n1p2', 259, 2)]: path = blocks/name path.mkdir() (path/'uevent').write_text(f'DEVTYPE=partition\nDEVNAME={name}\nMAJOR={major}\nMINOR={minor}\nPARTNAME=FDS_SYSTEM\n') result = json.loads(run('fds-stage0', '--probe', sysfs)) assert result['state'] == ('unique' if name == 'sdz1' else 'ambiguous') # A path escape must not turn a kernel identity into an arbitrary device path. (blocks/'sdz1/uevent').write_text('DEVTYPE=partition\nDEVNAME=../../etc/shadow\nMAJOR=8\nMINOR=241\nPARTNAME=FDS_SYSTEM\n') run('fds-stage0', '--probe', sysfs, ok=False) cmdline = work/'cmdline' cmdline.write_text('console=ttyAMA0 fds.boot=recovery fds.debug=1\n') assert json.loads(run('fds-stage0', '--check-cmdline', cmdline)) == {'mode': 'recovery', 'debug': True, 'emulator': False} cmdline.write_text('fds.emulator=1') assert json.loads(run('fds-stage0', '--check-cmdline', cmdline)) == {'mode': 'normal', 'debug': False, 'emulator': True} cmdline.write_text('fds.emulator=2') run('fds-stage0', '--check-cmdline', cmdline, ok=False) cmdline.write_text('fds.boot=normal fds.boot=recovery') run('fds-stage0', '--check-cmdline', cmdline, ok=False) print('PASS: real ARM CLI, bounded/strict manifests, missing/unique/ambiguous discovery and boot options')