From: Lennart Poettering Date: Sun, 9 Feb 2025 23:23:21 +0000 (+0100) Subject: import-generator: add new option 'bootorigin' to derive URL from efi boot url X-Git-Tag: v258-rc1~1280^2~21 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0c892214f73584e55bfa3fd8f0d54f631cb527b0;p=thirdparty%2Fsystemd.git import-generator: add new option 'bootorigin' to derive URL from efi boot url --- diff --git a/man/systemd-import-generator.xml b/man/systemd-import-generator.xml index f140873552b..d60c9c96fed 100644 --- a/man/systemd-import-generator.xml +++ b/man/systemd-import-generator.xml @@ -127,6 +127,23 @@ + + + bootorigin + + If this option is specified, in place of the URL a simple filename may be + specified. If the system is booted via UEFI HTTP network booting the last component of the + network boot origin URL is replaced by this filename and used as download source. This hence + allows to automatically derive the URLs for disk images from the original boot URL used to invoke + the kernel or boot loader. + + If this option is used and the system is not actually booted via UEFI HTTP network booting, + the download is gracefully skipped. Or in other words without other modifications it is possible + to put together an initrd image that will boot from a local disk if available, or from downloaded + disk image if used via network booting. + + + @@ -203,6 +220,17 @@ image, and attaches it to a loopback block device on completion. It then boots from the 2nd partition in the image. + + + Boot into disk image (raw), with URL derived from UEFI HTTP network booting + + rd.systemd.pull=raw,machine,verify=no,blockdev,bootorigin:rootdisk:image.raw.xz root=/dev/disk/by-loop-ref/rootdisk.raw-part2 + + This is similar to the previous example, but this time the source URL is automatically derived + from the UEFI HTTP network boot URL. For example, if an UKI is booted from an URL + http://example.com/image.efi this would result in a root disk being downloaded from + http://example.com/image.raw.xz. + diff --git a/src/import/import-generator.c b/src/import/import-generator.c index a778d064a93..5d2f37107e8 100644 --- a/src/import/import-generator.c +++ b/src/import/import-generator.c @@ -4,6 +4,7 @@ #include "creds-util.h" #include "discover-image.h" +#include "efivars.h" #include "fd-util.h" #include "fileio.h" #include "generator.h" @@ -65,8 +66,6 @@ static int parse_pull_expression(const char *v) { if (r == 0) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No local string in pull expression '%s': %m", v); - if (!http_url_is_valid(p) && !file_url_is_valid(p)) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Not a valid URL, refusing: %s", p); _cleanup_free_ char *remote = strdup(p); if (!remote) return log_oom(); @@ -79,7 +78,7 @@ static int parse_pull_expression(const char *v) { ImportType type = _IMPORT_TYPE_INVALID; ImageClass class = _IMAGE_CLASS_INVALID; ImportVerify verify = IMPORT_VERIFY_SIGNATURE; - bool ro = false, blockdev = false; + bool ro = false, blockdev = false, bootorigin = false; const char *o = options; for (;;) { @@ -99,8 +98,9 @@ static int parse_pull_expression(const char *v) { ro = false; else if (streq(opt, "blockdev")) blockdev = true; + else if (streq(opt, "bootorigin")) + bootorigin = true; else if ((suffix = startswith(opt, "verify="))) { - ImportVerify w = import_verify_from_string(suffix); if (w < 0) @@ -124,6 +124,32 @@ static int parse_pull_expression(const char *v) { } } + if (bootorigin) { + _cleanup_free_ char *stub_url = NULL; + + r = efi_get_variable_string(EFI_LOADER_VARIABLE_STR("StubDeviceURL"), &stub_url); + if (r == -ENOENT) { + log_debug("Option 'bootorigin' specified, but StubDeviceURL EFI variable not set, not scheduling import job for '%s'.", remote); + return 0; + } + if (r < 0) + return log_error_errno(r, "Failed to read 'StubDeviceURL' EFI variable: %m"); + + if (!http_url_is_valid(stub_url)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Value of 'StubDeviceURL' is not a valid URL, refusing: %s", stub_url); + + _cleanup_free_ char *result = NULL; + r = import_url_change_last_component(stub_url, remote, &result); + if (r < 0) + return log_error_errno(r, "Failed to replace last component of URL '%s': %m", stub_url); + + log_info("URL reported by StubDeviceURL is '%s', derived download URL '%s' from it.", stub_url, result); + free_and_replace(remote, result); + } + + if (!http_url_is_valid(remote) && !file_url_is_valid(remote)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Not a valid URL, refusing: %s", remote); + if (type < 0) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No image type (raw, tar) specified in pull expression, refusing: %s", v); if (class < 0)