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:
Christian Kellner 2019-12-11 17:27:34 +01:00 committed by Tom Gundersen
parent ce5f3c4331
commit b85e8ea673

View file

@ -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