From 3bed7c7aceba9457029bf8094fcffaed0d1a0a5a Mon Sep 17 00:00:00 2001 From: "Brian C. Lane" Date: Thu, 21 Nov 2024 13:13:56 -0800 Subject: [PATCH] grub2.inst: Add support for creating iso9660 boot image Don't include the "location" offset, and use just a path for the prefix section to set the path of the grub2 modules on the iso. eg. { "filename": "eltorito.img", "platform": "i386-pc", "core": { "type": "mkimage", "partlabel": "gpt", "filesystem": "iso9660" }, "prefix": { "path": "/boot/grub2/" } } --- stages/org.osbuild.grub2.inst | 46 +++++++++++++++++-------- stages/org.osbuild.grub2.inst.meta.json | 22 ++++++++++-- stages/test/test_grub2_inst.py | 19 ++++++++++ 3 files changed, 70 insertions(+), 17 deletions(-) diff --git a/stages/org.osbuild.grub2.inst b/stages/org.osbuild.grub2.inst index 2c740b8c..ecc9d2a8 100755 --- a/stages/org.osbuild.grub2.inst +++ b/stages/org.osbuild.grub2.inst @@ -70,11 +70,11 @@ def write_core_image(core_f, image_f, location, sector_size): shutil.copyfileobj(core_f, image_f) -def core_mkimage(platform: str, prefix: str, options: Dict,): +def core_mkimage(platform: str, prefix: str, options: Dict): pt_label = options["partlabel"] fs_type = options["filesystem"] - os.makedirs("/var/tmp", exist_ok=True) + os.makedirs("/var/tmp/", exist_ok=True) core_path = "/var/tmp/grub2-core.img" # Create the level-2 & 3 stages of the bootloader, aka the core @@ -88,8 +88,10 @@ def core_mkimage(platform: str, prefix: str, options: Dict,): if platform == "i386-pc": modules = ["biosdisk"] + gformat = "i386-pc" else: modules = [] + gformat = "i386-pc" if pt_label in ["dos", "mbr"]: modules += ["part_msdos"] @@ -102,6 +104,9 @@ def core_mkimage(platform: str, prefix: str, options: Dict,): modules += ["xfs"] elif fs_type == "btrfs": modules += ["btrfs"] + elif fs_type == "iso9660": + modules += ["iso9660"] + gformat = "i386-pc-eltorito" else: raise ValueError(f"unknown boot filesystem type: '{fs_type}'") @@ -110,7 +115,7 @@ def core_mkimage(platform: str, prefix: str, options: Dict,): "--verbose", "--directory", f"/usr/lib/grub/{platform}", "--prefix", prefix, - "--format", platform, + "--format", gformat, "--compression", "auto", "--output", core_path] + modules, @@ -133,18 +138,7 @@ def prefix_partition(options: Dict): return prefix -def main(tree, options): - filename = options["filename"] - platform = options["platform"] - location = options["location"] - sector_size = options.get("sector-size", 512) - - image = os.path.join(tree, filename.lstrip("/")) - - prefix = prefix_partition(options["prefix"]) - print(f"prefix: {prefix}") - core_path = core_mkimage(platform, prefix, options["core"]) - +def patch_core(location, core_path, image, sector_size, platform): with open(image, "rb+") as image_f: # Write the newly created grub2 core to the image @@ -168,6 +162,28 @@ def main(tree, options): with open(boot_path, "rb") as boot_f: write_boot_image(boot_f, image_f, location) + +def main(tree, options): + filename = options["filename"] + platform = options["platform"] + sector_size = options.get("sector-size", 512) + + image = os.path.join(tree, filename.lstrip("/")) + + if "number" in options["prefix"]: + prefix = prefix_partition(options["prefix"]) + else: + prefix = options["prefix"]["path"] + print(f"prefix: {prefix}") + core_path = core_mkimage(platform, prefix, options["core"]) + + location = options.get("location") + if location: + patch_core(location, core_path, image, sector_size, platform) + else: + # If location isn't set, use the image file as-is instead of with the MBR + shutil.copyfile(core_path, image) + return 0 diff --git a/stages/org.osbuild.grub2.inst.meta.json b/stages/org.osbuild.grub2.inst.meta.json index 400e9bdf..6f8e75d7 100644 --- a/stages/org.osbuild.grub2.inst.meta.json +++ b/stages/org.osbuild.grub2.inst.meta.json @@ -59,7 +59,8 @@ "enum": [ "ext4", "xfs", - "btrfs" + "btrfs", + "iso9660" ] }, "binary": { @@ -69,6 +70,21 @@ } } }, + "prefix-path": { + "type": "object", + "description": "Grub2 config path on iso9660 eg. /boot/grub2", + "additionalProperties": false, + "required": [ + "path" + ], + "properties": { + "path": { + "description": "location of grub config inside the partition", + "type": "string", + "pattern": "/.*" + } + } + }, "prefix-partition": { "type": "object", "description": "Grub2 config on a specific partition, e.g. (,gpt3)/boot", @@ -108,7 +124,6 @@ "required": [ "filename", "platform", - "location", "core", "prefix" ], @@ -138,6 +153,9 @@ "oneOf": [ { "$ref": "#/definitions/prefix-partition" + }, + { + "$ref": "#/definitions/prefix-path" } ] }, diff --git a/stages/test/test_grub2_inst.py b/stages/test/test_grub2_inst.py index 9b278271..b6c217bd 100644 --- a/stages/test/test_grub2_inst.py +++ b/stages/test/test_grub2_inst.py @@ -31,3 +31,22 @@ def test_grub2_partition(tmp_path, stage_module): with open(treedir / "disk.img", "rb") as f: msg = f.read(12) assert msg != b"Just testing" + +def test_grub2_iso9660(tmp_path, stage_module): + treedir = tmp_path / "tree" + os.makedirs(treedir, exist_ok=True) + + options = { + "filename": "eltorito.img", + "platform": "i386-pc", + "core": { + "type": "mkimage", + "partlabel": "gpt", + "filesystem": "iso9660", + }, + "prefix": { + "path": "/boot/grub2/", + }, + } + stage_module.main(treedir, options) + assert os.path.exists(treedir / "eltorito.img")