assembler/qemu: refactor to prepare for uefi/gpt
Prepare the stage for uefi/gpt support by extracting the code that installs GRUB and creates the partitions into its own functions. Should not have any effect on the actual data written to the image.
This commit is contained in:
parent
ce5f3c4331
commit
b85e8ea673
1 changed files with 50 additions and 37 deletions
|
|
@ -77,6 +77,53 @@ def mkfs_xfs(device, uuid):
|
|||
subprocess.run(["mkfs.xfs", "-m", f"uuid={uuid}", device], encoding='utf-8', check=True)
|
||||
|
||||
|
||||
def create_partition_table(image, ptuuid):
|
||||
"""Set up the partition table of the image"""
|
||||
partition_table = f"label: mbr\nlabel-id: {ptuuid}\nbootable, type=83"
|
||||
subprocess.run(["sfdisk", "-q", image], input=partition_table, encoding='utf-8', check=True)
|
||||
|
||||
r = subprocess.run(["sfdisk", "--json", image], stdout=subprocess.PIPE, encoding='utf-8', check=True)
|
||||
partition_table = json.loads(r.stdout)
|
||||
return partition_table
|
||||
|
||||
|
||||
def install_grub2(image, fs_module, partition_offset):
|
||||
"""Install grub2 to image"""
|
||||
grub2_core = "/var/tmp/grub2-core.img"
|
||||
|
||||
# Create the level-2 bootloader
|
||||
# The purpose of this is to find the grub modules and configuration
|
||||
# to be able to start the level-3 bootloader. It contains the modules
|
||||
# necessary to do this, but nothing else.
|
||||
subprocess.run(["grub2-mkimage",
|
||||
"--verbose",
|
||||
"--directory", "/usr/lib/grub/i386-pc",
|
||||
"--prefix", "(,msdos1)/boot/grub2",
|
||||
"--format", "i386-pc",
|
||||
"--compression", "auto",
|
||||
"--output", grub2_core,
|
||||
"part_msdos", fs_module, "biosdisk"],
|
||||
check=True)
|
||||
|
||||
assert os.path.getsize(grub2_core) < partition_offset - 512
|
||||
|
||||
with open(image, "rb+") as image_f:
|
||||
# Install the level-1 bootloader into the start of the MBR
|
||||
# The purpose of this is simply to jump into the level-2 bootloader.
|
||||
with open("/usr/lib/grub/i386-pc/boot.img", "rb") as boot_f:
|
||||
# The boot.img file is 512 bytes, but we must only copy the first 440
|
||||
# bytes, as these contain the bootstrapping code. The rest of the
|
||||
# first sector contains the partition table, and must not be
|
||||
# overwritten.
|
||||
image_f.write(boot_f.read(440))
|
||||
|
||||
# Install the level-2 bootloader into the space after the MBR, before
|
||||
# the first partition.
|
||||
with open(grub2_core, "rb") as core_f:
|
||||
image_f.seek(512)
|
||||
shutil.copyfileobj(core_f, image_f)
|
||||
|
||||
|
||||
def main(tree, output_dir, options, loop_client):
|
||||
fmt = options["format"]
|
||||
filename = options["filename"]
|
||||
|
|
@ -102,52 +149,18 @@ def main(tree, output_dir, options, loop_client):
|
|||
raise ValueError("`root_fs_type` must be either ext4 or xfs")
|
||||
|
||||
image = "/var/tmp/osbuild-image.raw"
|
||||
grub2_core = "/var/tmp/grub2-core.img"
|
||||
|
||||
# Create an empty image file
|
||||
subprocess.run(["truncate", "--size", str(size), image], check=True)
|
||||
|
||||
# Set up the partition table of the image
|
||||
partition_table = f"label: mbr\nlabel-id: {ptuuid}\nbootable, type=83"
|
||||
subprocess.run(["sfdisk", "-q", image], input=partition_table, encoding='utf-8', check=True)
|
||||
|
||||
r = subprocess.run(["sfdisk", "--json", image], stdout=subprocess.PIPE, encoding='utf-8', check=True)
|
||||
partition_table = json.loads(r.stdout)
|
||||
# The partition table
|
||||
partition_table = create_partition_table(image, ptuuid)
|
||||
partition = partition_table["partitiontable"]["partitions"][0]
|
||||
partition_offset = partition["start"] * 512
|
||||
partition_size = partition["size"] * 512
|
||||
|
||||
# Create the level-2 bootloader
|
||||
# The purpose of this is to find the grub modules and configuration
|
||||
# to be able to start the level-3 bootloader. It contains the modules
|
||||
# necessary to do this, but nothing else.
|
||||
subprocess.run(["grub2-mkimage",
|
||||
"--verbose",
|
||||
"--directory", "/usr/lib/grub/i386-pc",
|
||||
"--prefix", "(,msdos1)/boot/grub2",
|
||||
"--format", "i386-pc",
|
||||
"--compression", "auto",
|
||||
"--output", grub2_core,
|
||||
"part_msdos", grub2_fs_module, "biosdisk"],
|
||||
check=True)
|
||||
|
||||
assert os.path.getsize(grub2_core) < partition_offset - 512
|
||||
|
||||
with open(image, "rb+") as image_f:
|
||||
# Install the level-1 bootloader into the start of the MBR
|
||||
# The purpose of this is simply to jump into the level-2 bootloader.
|
||||
with open("/usr/lib/grub/i386-pc/boot.img", "rb") as boot_f:
|
||||
# The boot.img file is 512 bytes, but we must only copy the first 440
|
||||
# bytes, as these contain the bootstrapping code. The rest of the
|
||||
# first sector contains the partition table, and must not be
|
||||
# overwritten.
|
||||
image_f.write(boot_f.read(440))
|
||||
|
||||
# Install the level-2 bootloader into the space after the MBR, before
|
||||
# the first partition.
|
||||
with open(grub2_core, "rb") as core_f:
|
||||
image_f.seek(512)
|
||||
shutil.copyfileobj(core_f, image_f)
|
||||
install_grub2(image, grub2_fs_module, partition_offset)
|
||||
|
||||
with loop_client.device(image, partition_offset, partition_size) as loop:
|
||||
# Populate the first partition of the image with a filesystem
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue