import-generator: add new option 'bootorigin' to derive URL from efi boot url

This commit is contained in:
Lennart Poettering
2025-02-21 10:03:32 +01:00
parent e15d18b4c6
commit 0c892214f7
2 changed files with 58 additions and 4 deletions
+28
View File
@@ -127,6 +127,23 @@
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
</varlistentry>
<varlistentry>
<term>bootorigin</term>
<listitem><para>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.</para>
<para>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.</para>
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
</varlistentry>
</variablelist>
<xi:include href="version-info.xml" xpointer="v257"/></listitem>
@@ -203,6 +220,17 @@
<literal>image</literal>, and attaches it to a loopback block device on completion. It then boots from
the 2nd partition in the image.</para>
</example>
<example>
<title>Boot into disk image (raw), with URL derived from UEFI HTTP network booting</title>
<programlisting>rd.systemd.pull=raw,machine,verify=no,blockdev,bootorigin:rootdisk:image.raw.xz root=/dev/disk/by-loop-ref/rootdisk.raw-part2</programlisting>
<para>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
<literal>http://example.com/image.efi</literal> this would result in a root disk being downloaded from
<literal>http://example.com/image.raw.xz</literal>.</para>
</example>
</refsect1>
<refsect1>
+30 -4
View File
@@ -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)