From: Zbigniew Jędrzejewski-Szmek Date: Tue, 20 Dec 2022 09:38:01 +0000 (+0100) Subject: ukify: check early if inputs exist and are readable X-Git-Tag: v253-rc1~226^2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=095ff238d064f7dfbf75c9cd13834ed892fe5fd9;p=thirdparty%2Fsystemd.git ukify: check early if inputs exist and are readable It's much nicer for the user if we fail early instead of doing partial processing if we cannot read some input. We can't do those checks immediately from argparse.Parser.parse_args(), because we want to fully process the commandline first. In particular, even with invalid args, if --help is specified somewhere, we want to handle that. Thus, we need to delay the checks after argparse.Parser.parse_args() returns. Ukify didn't have type annotations on functions, but it probably should. Jörg's suggested correction included them and we might just as well start here. --- diff --git a/src/ukify/ukify.py b/src/ukify/ukify.py index cd27f92a978..0c4461c9a92 100755 --- a/src/ukify/ukify.py +++ b/src/ukify/ukify.py @@ -64,6 +64,15 @@ def shell_join(cmd): return ' '.join(shlex.quote(str(x)) for x in cmd) +def path_is_readable(s: str | None) -> pathlib.Path | None: + """Convert a filename string to a Path and verify access.""" + if s is None: + return None + p = pathlib.Path(s) + p.open().close() + return p + + def pe_executable_size(filename): import pefile @@ -675,26 +684,36 @@ usage: ukify [options…] linux initrd… opts = p.parse_args(args) + path_is_readable(opts.linux) + for initrd in opts.initrd or (): + path_is_readable(initrd) + path_is_readable(opts.devicetree) + path_is_readable(opts.pcrpkey) + for key in opts.pcr_private_keys or (): + path_is_readable(key) + for key in opts.pcr_public_keys or (): + path_is_readable(key) + if opts.cmdline and opts.cmdline.startswith('@'): - opts.cmdline = pathlib.Path(opts.cmdline[1:]) + opts.cmdline = path_is_readable(opts.cmdline[1:]) if opts.os_release is not None and opts.os_release.startswith('@'): - opts.os_release = pathlib.Path(opts.os_release[1:]) + opts.os_release = path_is_readable(opts.os_release[1:]) elif opts.os_release is None: p = pathlib.Path('/etc/os-release') if not p.exists(): - p = pathlib.Path('/usr/lib/os-release') + p = path_is_readable('/usr/lib/os-release') opts.os_release = p if opts.efi_arch is None: opts.efi_arch = guess_efi_arch() if opts.stub is None: - opts.stub = f'/usr/lib/systemd/boot/efi/linux{opts.efi_arch}.efi.stub' + opts.stub = path_is_readable(f'/usr/lib/systemd/boot/efi/linux{opts.efi_arch}.efi.stub') if opts.signing_engine is None: - opts.sb_key = pathlib.Path(opts.sb_key) if opts.sb_key else None - opts.sb_cert = pathlib.Path(opts.sb_cert) if opts.sb_cert else None + opts.sb_key = path_is_readable(opts.sb_key) if opts.sb_key else None + opts.sb_cert = path_is_readable(opts.sb_cert) if opts.sb_cert else None if bool(opts.sb_key) ^ bool(opts.sb_cert): raise ValueError('--secureboot-private-key= and --secureboot-certificate= must be specified together')