SourceFileTransfer,
Verb,
die,
- install_grub,
is_centos_variant,
is_epel_variant,
is_rpm_distribution,
nspawn_executable,
nspawn_knows_arg,
- nspawn_params_for_blockdev_access,
nspawn_rlimit_params,
nspawn_version,
patch_file,
var_tmp,
warn,
workspace,
- write_grub_config,
)
from .manifest import Manifest
from .syscall import ioctl_partition_add, ioctl_partition_remove, reflink
no_btrfs = args.output_format != OutputFormat.gpt_btrfs
for condition, label, size, type_uuid, name, read_only in (
- (args.bootable and "uefi" in args.boot_protocols,
+ (args.bootable,
PartitionIdentifier.esp, args.esp_size, GPT_ESP, "ESP System Partition", False),
- (args.bootable and "bios" in args.boot_protocols,
- PartitionIdentifier.bios, BIOS_PARTITION_SIZE, GPT_BIOS, "BIOS Boot Partition", False),
+ (args.bios_size is not None,
+ PartitionIdentifier.bios, args.bios_size, GPT_BIOS, "BIOS Boot Partition", False),
(args.xbootldr_size is not None,
PartitionIdentifier.xbootldr, args.xbootldr_size, GPT_XBOOTLDR, "Boot Loader Partition", False),
(args.swap_size is not None,
if args.output_format == OutputFormat.gpt_btrfs:
add_packages(args, packages, "btrfs-progs")
- if args.get_partition(PartitionIdentifier.bios):
- if args.distribution in (Distribution.mageia, Distribution.openmandriva):
- add_packages(args, packages, "grub2")
- else:
- add_packages(args, packages, "grub2-pc")
-
if not do_run_build_script and args.ssh:
add_packages(args, packages, "openssh-server")
if not any(package.startswith("linux-image") for package in extra_packages):
add_packages(args, extra_packages, f"linux-image-{DEBIAN_KERNEL_ARCHITECTURES[args.architecture]}")
- if args.get_partition(PartitionIdentifier.bios):
- add_packages(args, extra_packages, "grub-pc")
-
if args.output_format == OutputFormat.gpt_btrfs:
add_packages(args, extra_packages, "btrfs-progs")
root.joinpath("etc/resolv.conf").symlink_to("../run/systemd/resolve/resolv.conf")
run(["systemctl", "--root", root, "enable", "systemd-resolved"])
- # Make sure kernel-install actually runs when needed by creating the machine-id subdirectory under /boot.
- # In newer versions of systemd, this is already accomplished by running setting "layout=bls" in
- # /etc/kernel/install.conf but for older Debian and Ubuntu we have to nudge kernel-install by creating
- # this directory.
- if "bios" in args.boot_protocols or ("linux" in args.boot_protocols and "uefi" not in args.boot_protocols):
- root.joinpath("boot", args.machine_id).mkdir(mode=0o700)
-
write_resource(root / "etc/kernel/install.d/50-mkosi-dpkg-reconfigure-dracut.install",
"mkosi.resources", "dpkg-reconfigure-dracut.install", executable=True)
add_packages(args, packages, "xfsprogs")
if args.encrypt:
add_packages(args, packages, "cryptsetup", "device-mapper")
- if args.get_partition(PartitionIdentifier.bios):
- add_packages(args, packages, "grub")
add_packages(args, packages, "dracut")
# systemd-nspawn containers. See https://bugs.archlinux.org/task/45903.
disable_pam_securetty(root)
- # grub expects the kernel image and initramfs to be located in the /boot folder so let's create some
- # symlinks in /boot that point to where kernel-install will store the kernel image and initramfs.
- if "bios" in args.boot_protocols:
- for kver, _ in gen_kernel_images(args, root):
- boot_dir = Path("/") / boot_directory(args, kver)
- root.joinpath(f"boot/vmlinuz-{kver}").symlink_to(boot_dir / "linux")
- root.joinpath(f"boot/initramfs-{kver}.img").symlink_to(boot_dir / "initrd")
-
@complete_step("Installing openSUSE…")
def install_opensuse(args: MkosiArgs, root: Path, do_run_build_script: bool) -> None:
if not do_run_build_script and args.bootable:
add_packages(args, packages, "kernel-default", "dracut")
- if args.get_partition(PartitionIdentifier.bios):
- add_packages(args, packages, "grub2")
-
if not do_run_build_script and args.encrypt:
add_packages(args, packages, "device-mapper")
shutil.copy2(args.postinst_script, root_home(args, root) / "postinst")
- nspawn_params = []
- # in order to have full blockdev access, i.e. for making grub2 bootloader changes
- # we need to have these bind mounts for a proper chroot setup
- if args.bootable:
- if loopdev is None:
- raise ValueError("Parameter 'loopdev' required for bootable images.")
- nspawn_params += nspawn_params_for_blockdev_access(args, loopdev)
-
run_workspace_command(args, root, ["/root/postinst", verb],
network=(args.with_network is True),
- nspawn_params=nspawn_params,
env=args.environment)
root_home(args, root).joinpath("postinst").unlink()
if args.get_partition(PartitionIdentifier.esp):
run_workspace_command(args, root, ["bootctl", "install"])
- if args.get_partition(PartitionIdentifier.bios):
- install_grub(args, root, loopdev)
-
def install_extra_trees(args: MkosiArgs, root: Path, for_cache: bool) -> None:
if not args.extra_trees:
for_cache: bool,
mount: Callable[[], ContextManager[None]],
) -> Union[Tuple[BinaryIO, BinaryIO], Tuple[None, None]]:
- if do_run_build_script or for_cache or "linux" not in args.boot_protocols:
+ if do_run_build_script or for_cache or not args.bootable:
return None, None
with mount():
for_cache: bool,
mount: Callable[[], ContextManager[None]],
) -> Optional[TextIO]:
- if do_run_build_script or for_cache or "linux" not in args.boot_protocols:
+ if do_run_build_script or for_cache or not args.bootable:
return None
with mount():
group.add_argument(
"--boot-protocols",
action=CommaDelimitedListAction,
- help="Boot protocols to use on a bootable image",
- metavar="PROTOCOLS",
- default=[],
+ help=argparse.SUPPRESS,
)
group.add_argument(
"--kernel-command-line",
metavar="BYTES",
)
group.add_argument(
- "--home-size", help="Set size of /home partition (only gpt_ext4, gpt_xfs, gpt_squashfs)", metavar="BYTES"
+ "--home-size", help="Set size of /home partition (only for GPT images)", metavar="BYTES"
)
group.add_argument(
- "--srv-size", help="Set size of /srv partition (only gpt_ext4, gpt_xfs, gpt_squashfs)", metavar="BYTES"
+ "--srv-size", help="Set size of /srv partition (only for GPT images)", metavar="BYTES"
)
group.add_argument(
- "--var-size", help="Set size of /var partition (only gpt_ext4, gpt_xfs, gpt_squashfs)", metavar="BYTES"
+ "--var-size", help="Set size of /var partition (only for GPT images)", metavar="BYTES"
)
group.add_argument(
- "--tmp-size", help="Set size of /var/tmp partition (only gpt_ext4, gpt_xfs, gpt_squashfs)", metavar="BYTES"
+ "--tmp-size", help="Set size of /var/tmp partition (only for GPT images)", metavar="BYTES"
+ )
+ group.add_argument(
+ "--bios-size", help="Set size of BIOS boot partition (only for GPT images)", metavar="BYTES",
)
group.add_argument(
"--usr-only",
group.add_argument(
"--qemu-boot",
help="Configure which qemu boot protocol to use",
- choices=["uefi", "bios", "linux", None],
+ choices=["uefi", "linux", None],
metavar="PROTOCOL",
+ default="uefi",
)
group.add_argument(
"--network-veth", # Compatibility option
unlink_try_hard(args.output_split_verity_sig)
unlink_try_hard(args.output_split_kernel)
- if "linux" in args.boot_protocols:
- unlink_try_hard(build_auxiliary_output_path(args, ".vmlinuz"))
- unlink_try_hard(build_auxiliary_output_path(args, ".initrd"))
- unlink_try_hard(build_auxiliary_output_path(args, ".cmdline"))
+ unlink_try_hard(build_auxiliary_output_path(args, ".vmlinuz"))
+ unlink_try_hard(build_auxiliary_output_path(args, ".initrd"))
+ unlink_try_hard(build_auxiliary_output_path(args, ".cmdline"))
if args.nspawn_settings is not None:
unlink_try_hard(args.output_nspawn_settings)
):
die("Directory, subvolume, tar, cpio, and plain squashfs images cannot be booted.", MkosiNotSupportedException)
- if not args.boot_protocols:
- args.boot_protocols = ["uefi"]
-
- if not {"uefi", "bios", "linux"}.issuperset(args.boot_protocols):
- die("Not a valid boot protocol")
-
if is_centos_variant(args.distribution):
epel_release = parse_epel_release(args.release)
if epel_release <= 9 and args.output_format == OutputFormat.gpt_btrfs:
args.esp_size = parse_bytes(args.esp_size)
args.xbootldr_size = parse_bytes(args.xbootldr_size)
args.swap_size = parse_bytes(args.swap_size)
+ args.bios_size = parse_bytes(args.bios_size)
if args.root_size is None:
args.root_size = 3 * 1024 * 1024 * 1024
if not args.read_only:
args.kernel_command_line.append("rw")
- if is_generated_root(args) and "bios" in args.boot_protocols:
- die("Sorry, BIOS cannot be combined with --minimize or squashfs filesystems", MkosiNotSupportedException)
-
if args.verity and not args.with_unified_kernel_images:
die("Sorry, --verity can only be used with unified kernel images", MkosiNotSupportedException)
if args.qemu_kvm and not qemu_check_kvm_support():
die("Sorry, the host machine does not support KVM acceleration.")
+ if args.boot_protocols is not None:
+ warn("The --boot-protocols is deprecated and has no effect anymore")
+ delattr(args, "boot_protocols")
+
return MkosiArgs(**vars(args))
MkosiPrinter.info(" Kernel Command Line: " + " ".join(args.kernel_command_line))
MkosiPrinter.info(" UEFI SecureBoot: " + yes_no(args.secure_boot))
- MkosiPrinter.info(" Boot Protocols: " + line_join_list(args.boot_protocols))
MkosiPrinter.info(" Unified Kernel Images: " + yes_no(args.with_unified_kernel_images))
MkosiPrinter.info(" GPT First LBA: " + str(args.gpt_first_lba))
MkosiPrinter.info(" Hostonly Initrd: " + yes_no(args.hostonly_initrd))
MkosiPrinter.info("\nPARTITIONS:")
MkosiPrinter.info(" Root Partition: " + format_bytes_or_auto(args.root_size))
MkosiPrinter.info(" Swap Partition: " + format_bytes_or_disabled(args.swap_size))
- if "uefi" in args.boot_protocols:
- MkosiPrinter.info(" ESP: " + format_bytes_or_disabled(args.esp_size))
- if "bios" in args.boot_protocols:
- MkosiPrinter.info(" BIOS: " + format_bytes_or_disabled(BIOS_PARTITION_SIZE))
+ MkosiPrinter.info(" EFI Partition: " + format_bytes_or_disabled(args.esp_size))
MkosiPrinter.info(" XBOOTLDR Partition: " + format_bytes_or_disabled(args.xbootldr_size))
MkosiPrinter.info(" /home Partition: " + format_bytes_or_disabled(args.home_size))
MkosiPrinter.info(" /srv Partition: " + format_bytes_or_disabled(args.srv_size))
MkosiPrinter.info(" /var Partition: " + format_bytes_or_disabled(args.var_size))
MkosiPrinter.info(" /var/tmp Partition: " + format_bytes_or_disabled(args.tmp_size))
+ MkosiPrinter.info(" BIOS Partition: " + format_bytes_or_disabled(args.bios_size))
MkosiPrinter.info(" /usr only: " + yes_no(args.usr_only))
MkosiPrinter.info("\nVALIDATION:")
def run_qemu_cmdline(args: MkosiArgs) -> Iterator[List[str]]:
accel = "kvm" if args.qemu_kvm else "tcg"
- if args.qemu_boot:
- mode = args.qemu_boot
- elif "uefi" in args.boot_protocols:
- mode = "uefi"
- elif "bios" in args.boot_protocols:
- mode = "bios"
- elif "linux" in args.boot_protocols:
- mode = "linux"
- else:
- mode = "uefi"
-
firmware, fw_supports_sb = find_qemu_firmware(args)
- smm = "on" if fw_supports_sb and mode == "uefi" else "off"
+ smm = "on" if fw_supports_sb and args.qemu_boot == "uefi" else "off"
cmdline = [
find_qemu_binary(args),
# -nodefaults removes the default CDROM device which avoids an error message during boot
# -serial mon:stdio adds back the serial device removed by -nodefaults.
cmdline += ["-nographic", "-nodefaults", "-serial", "mon:stdio"]
- # Fix for https://github.com/systemd/mkosi/issues/559. QEMU gets stuck in a boot loop when using BIOS
- # if there's no vga device.
-
- if not args.qemu_headless or (args.qemu_headless and mode == "bios"):
+ else:
cmdline += ["-vga", "virtio"]
if args.netdev:
# after it is created.
cmdline += ["-nic", f"tap,script=no,downscript=no,ifname={ifname},model=virtio-net-pci"]
- if mode == "uefi":
+ if args.qemu_boot == "uefi":
cmdline += ["-drive", f"if=pflash,format=raw,readonly=on,file={firmware}"]
- if mode == "linux":
+ if args.qemu_boot == "linux":
cmdline += [
"-kernel", str(build_auxiliary_output_path(args, ".vmlinuz")),
"-initrd", str(build_auxiliary_output_path(args, ".initrd")),
]
with contextlib.ExitStack() as stack:
- if mode == "uefi" and fw_supports_sb:
+ if args.qemu_boot == "uefi" and fw_supports_sb:
ovmf_vars = stack.enter_context(copy_file_temporary(src=find_ovmf_vars(args), dir=tmp_dir()))
cmdline += [
"-global",
output: Path
output_dir: Optional[Path]
bootable: bool
- boot_protocols: List[str]
kernel_command_line: List[str]
secure_boot: bool
secure_boot_key: Path
srv_size: Optional[int]
var_size: Optional[int]
tmp_size: Optional[int]
+ bios_size: Optional[int]
usr_only: bool
split_artifacts: bool
checksum: bool
return "unrecognized option" not in run([nspawn_executable(), arg], stderr=subprocess.PIPE, check=False, text=True).stderr
-def nspawn_params_for_blockdev_access(args: MkosiArgs, loopdev: Path) -> List[str]:
- assert args.partition_table is not None
-
- params = [
- f"--bind-ro={loopdev}",
- f"--property=DeviceAllow={loopdev}",
- "--bind-ro=/dev/block",
- "--bind-ro=/dev/disk",
- ]
-
- for ident in (PartitionIdentifier.esp,
- PartitionIdentifier.bios,
- PartitionIdentifier.root,
- PartitionIdentifier.xbootldr):
- path = args.partition_table.partition_path(ident, loopdev)
- if path and path.exists():
- params += [f"--bind-ro={path}", f"--property=DeviceAllow={path}"]
-
- params += [f"--setenv={env}={value}" for env, value in args.environment.items()]
-
- return params
-
-
def format_rlimit(rlimit: int) -> str:
limits = resource.getrlimit(rlimit)
soft = "infinity" if limits[0] == resource.RLIM_INFINITY else str(limits[0])
return path
-def write_grub_config(args: MkosiArgs, root: Path) -> None:
- kernel_cmd_line = " ".join(args.kernel_command_line)
- grub_cmdline = f'GRUB_CMDLINE_LINUX="{kernel_cmd_line}"\n'
- os.makedirs(root / "etc/default", exist_ok=True, mode=0o755)
- grub_config = root / "etc/default/grub"
- if not os.path.exists(grub_config):
- grub_config.write_text(grub_cmdline)
- else:
-
- def jj(line: str) -> str:
- if line.startswith(("GRUB_CMDLINE_LINUX=", "#GRUB_CMDLINE_LINUX=")): # GENTOO:
- return grub_cmdline
- if args.qemu_headless:
- if "GRUB_TERMINAL" in line:
- return line.strip('#').split('=')[0] + '="console serial"'
- return line
-
- patch_file(grub_config, jj)
-
- if args.qemu_headless:
- with open(grub_config, "a") as f:
- f.write('GRUB_SERIAL_COMMAND="serial --unit=0 --speed 115200"\n')
-
-
-def install_grub(args: MkosiArgs, root: Path, loopdev: Path) -> None:
- assert args.partition_table is not None
-
- part = args.get_partition(PartitionIdentifier.bios)
- if not part:
- return
-
- write_grub_config(args, root)
-
- nspawn_params = nspawn_params_for_blockdev_access(args, loopdev)
-
- grub = "/usr/sbin/grub" if root.joinpath("usr/sbin/grub-install").exists() else "/usr/sbin/grub2"
-
- cmdline: Sequence[PathString] = [f"{grub}-install", "--modules=ext2 part_gpt", "--target=i386-pc", loopdev]
- run_workspace_command(args, root, cmdline, nspawn_params=nspawn_params)
-
- # TODO: Remove os.path.basename once https://github.com/systemd/systemd/pull/16645 is widely available.
- cmdline = [f"{grub}-mkconfig", f"--output=/boot/{os.path.basename(grub)}/grub.cfg"]
- run_workspace_command(args, root, cmdline, nspawn_params=nspawn_params)
-
-
def die(message: str, exception: Type[MkosiException] = MkosiException) -> NoReturn:
MkosiPrinter.warn(f"Error: {message}")
raise exception(message)