[pve-devel] [PATCH 1/2] assistant: keep prepared iso bootable on uefi with flash drives

Stefan Sterz s.sterz at proxmox.com
Tue Apr 30 11:41:04 CEST 2024


On Tue Apr 30, 2024 at 10:54 AM CEST, Aaron Lauterer wrote:
> By mapping files into the ISO, the UUID for the partitions change as
> they depend on the timestamp. The result is, that grub cannot find its
> partition anymore and the user ends up on the grub shell.
>
> This only happens when booting from a blockdev in UEFI mode. E.g. a USB
> flash drive. Alternatively one can `dd` the ISO to a small (2GiB) VM
> disk and mark it as the first boot device.
>
> Booting in legacy mode or via CDROM (e.g. pass through via IPMI), it
> worked.
>
> Xorriso can report the commands needed to recreate the source ISO. The
> '-volume_date uuid' is the one needed to override the same UUIDs. We
> therefore read it first from the source iso and pass it as parameter
> whenever we inject a file into the iso.
>
> Signed-off-by: Aaron Lauterer <a.lauterer at proxmox.com>
> ---
>  proxmox-auto-install-assistant/src/main.rs | 44 ++++++++++++++++++++--
>  1 file changed, 41 insertions(+), 3 deletions(-)
>
> diff --git a/proxmox-auto-install-assistant/src/main.rs b/proxmox-auto-install-assistant/src/main.rs
> index 0debd29..e9213f7 100644
> --- a/proxmox-auto-install-assistant/src/main.rs
> +++ b/proxmox-auto-install-assistant/src/main.rs
> @@ -276,6 +276,7 @@ fn show_system_info(_args: &CommandSystemInfo) -> Result<()> {
>
>  fn prepare_iso(args: &CommandPrepareISO) -> Result<()> {
>      check_prepare_requirements(args)?;
> +    let uuid = get_iso_uuid(&args.input)?;
>
>      if args.fetch_from == FetchAnswerFrom::Iso && args.answer_file.is_none() {
>          bail!("Missing path to the answer file required for the fetch-from 'iso' mode.");
> @@ -331,10 +332,15 @@ fn prepare_iso(args: &CommandPrepareISO) -> Result<()> {
>      instmode_file_tmp.push("auto-installer-mode.toml");
>      fs::write(&instmode_file_tmp, toml::to_string_pretty(&config)?)?;
>
> -    inject_file_to_iso(&tmp_iso, &instmode_file_tmp, "/auto-installer-mode.toml")?;
> +    inject_file_to_iso(
> +        &tmp_iso,
> +        &instmode_file_tmp,
> +        "/auto-installer-mode.toml",
> +        &uuid,
> +    )?;
>
>      if let Some(answer_file) = &args.answer_file {
> -        inject_file_to_iso(&tmp_iso, answer_file, "/answer.toml")?;
> +        inject_file_to_iso(&tmp_iso, answer_file, "/answer.toml", &uuid)?;
>      }
>
>      println!("Moving prepared ISO to target location...");
> @@ -371,11 +377,14 @@ fn final_iso_location(args: &CommandPrepareISO) -> PathBuf {
>      target.to_path_buf()
>  }
>
> -fn inject_file_to_iso(iso: &PathBuf, file: &PathBuf, location: &str) -> Result<()> {
> +fn inject_file_to_iso(iso: &PathBuf, file: &PathBuf, location: &str, uuid: &String) -> Result<()> {
>      let result = Command::new("xorriso")
>          .arg("--boot_image")
>          .arg("any")
>          .arg("keep")
> +        .arg("-volume_date")
> +        .arg("uuid")
> +        .arg(uuid)
>          .arg("-dev")
>          .arg(iso)
>          .arg("-map")
> @@ -391,6 +400,35 @@ fn inject_file_to_iso(iso: &PathBuf, file: &PathBuf, location: &str) -> Result<(
>      Ok(())
>  }
>
> +fn get_iso_uuid(iso: &PathBuf) -> Result<String> {
> +    let result = Command::new("xorriso")
> +        .arg("-dev")
> +        .arg(iso)
> +        .arg("-report_system_area")
> +        .arg("cmd")
> +        .output()?;
> +    if !result.status.success() {
> +        bail!(
> +            "Error determining the UUID of the source ISO: {}",
> +            String::from_utf8_lossy(&result.stderr)
> +        );
> +    }
> +    let mut uuid = String::new();
> +    for line in String::from_utf8(result.stdout)?.lines() {
> +        if line.starts_with("-volume_date uuid") {
> +            uuid = line
> +                .split(' ')
> +                .last()
> +                .unwrap()

nit: while this probably won't happen, if xorriso ever starts returning
nothing to the above command, this unwrap may panic. it might be nice to
do a `ok_or_else(|| bail!("xorisso command behaved unexpectedly"))?` or
similar here.

> +                .replace('\'', "")
> +                .trim()
> +                .into();
> +            break;
> +        }
> +    }
> +    Ok(uuid)
> +}
> +
>  fn get_disks() -> Result<BTreeMap<String, BTreeMap<String, String>>> {
>      let unwantend_block_devs = vec![
>          "ram[0-9]*",





More information about the pve-devel mailing list