pmbootstrap install --ondev: new option

Add initial support for the on-device installer in pmbootstrap. Let
pmbootstrap create a regular split image, then prepare a new installer
rootfs and copy the previously generated rootfs image into the installer
rootfs. Put the installer rootfs into a new image, with reserved space.

There is more to do from here, such as disabling the generation of the
user account when using --ondev. But this requires support in
postmarketos-ondev first, so let's build that iteratively.

Related: https://wiki.postmarketos.org/wiki/On-device_installer
Related: https://gitlab.com/postmarketOS/postmarketos-ondev/-/issues
This commit is contained in:
Oliver Smith 2020-06-06 23:38:34 +02:00
parent 8d0f3a1c55
commit ed4072956d
No known key found for this signature in database
GPG Key ID: 5AE7F5513E0885CB
6 changed files with 90 additions and 8 deletions

View File

@ -67,10 +67,11 @@ def shutdown(args, only_install_related=False):
path = path_outside[len(chroot):]
pmb.install.losetup.umount(args, path, auto_init=False)
# Umount device rootfs chroot
chroot_rootfs = args.work + "/chroot_rootfs_" + args.device
if os.path.exists(chroot_rootfs):
pmb.helpers.mount.umount_all(args, chroot_rootfs)
# Umount device rootfs and installer chroots
for prefix in ["rootfs", "installer"]:
path = f"{args.work}/chroot_{prefix}_{args.device}"
if os.path.exists(path):
pmb.helpers.mount.umount_all(args, path)
if not only_install_related:
# Umount all folders inside args.work

View File

@ -53,6 +53,7 @@ def zap(args, confirm=True, dry=False, pkgs_local=False, http=False,
patterns = [
"chroot_native",
"chroot_buildroot_*",
"chroot_installer_*",
"chroot_rootfs_*",
]
if pkgs_local:

View File

@ -204,6 +204,24 @@ def install(args):
if args.rsync and not args.sdcard:
raise ValueError("Installation using rsync only works on sdcard.")
# On-device installer checks
# Note that this can't be in the mutually exclusive group that has most of
# the conflicting options, because then it would not work with --sdcard.
if args.on_device_installer:
if args.full_disk_encryption:
raise ValueError("--on-device-installer cannot be combined with"
" --fde. The user can choose to encrypt their"
" installation later in the on-device installer.")
if args.android_recovery_zip:
raise ValueError("--on-device-installer cannot be combined with"
" --android-recovery-zip (patches welcome)")
if args.no_image:
raise ValueError("--on-device-installer cannot be combined with"
" --no-image")
if args.rsync:
raise ValueError("--on-device-installer cannot be combined with"
" --rsync")
if not args.sdcard and args.split is None:
# Default to split if the flash method requires it
flasher = pmb.config.flashers.get(args.deviceinfo["flash_method"], {})

View File

@ -11,6 +11,7 @@ import pmb.chroot.apk
import pmb.chroot.other
import pmb.chroot.initfs
import pmb.config
import pmb.config.pmaports
import pmb.helpers.devices
import pmb.helpers.run
import pmb.install.blockdevice
@ -500,6 +501,56 @@ def install_recovery_zip(args):
logging.info("<https://postmarketos.org/recoveryzip>")
def install_on_device_installer(args, step, steps):
# Generate the rootfs image
suffix_rootfs = f"rootfs_{args.device}"
install_system_image(args, 0, suffix_rootfs, step=step, steps=steps,
split=True)
step += 2
# Prepare the installer chroot
logging.info(f"*** ({step}/{steps}) CREATE ON-DEVICE INSTALLER ROOTFS ***")
step += 1
packages = ([f"device-{args.device}",
"postmarketos-ondev"] +
get_kernel_package(args, args.device) +
get_nonfree_packages(args, args.device))
suffix_installer = f"installer_{args.device}"
pmb.chroot.apk.install(args, packages, suffix_installer)
# Move rootfs image into installer chroot
img = f"{args.device}-root.img"
img_path_src = f"{args.work}/chroot_native/home/pmos/rootfs/{img}"
img_path_dest = f"{args.work}/chroot_{suffix_installer}/var/lib/rootfs.img"
logging.info(f"({suffix_installer}) add {img} as /var/lib/rootfs.img")
pmb.install.losetup.umount(args, img_path_src)
pmb.helpers.run.root(args, ["mv", img_path_src, img_path_dest])
# Run ondev-prepare, so it may generate nice configs from the channel
# properties (e.g. to display the version number), or transform the image
# file into another format. This can all be done without pmbootstrap
# changes in the postmarketos-ondev package.
logging.info(f"({suffix_installer}) ondev-prepare-image")
channel = pmb.config.pmaports.read_config(args)["channel"]
channel_cfg = pmb.config.pmaports.read_config_channel(args)
pmb.chroot.root(args, ["ondev-prepare", channel,
channel_cfg["description"],
channel_cfg["branch_pmaports"],
channel_cfg["branch_aports"],
channel_cfg["mirrordir_alpine"]], suffix_installer)
# Remove $DEVICE-boot.img (we will generate a new one if --split was
# specified, otherwise the separate boot image is not needed)
img_boot = f"{args.device}-boot.img"
logging.info(f"(native) rm {img_boot}")
pmb.chroot.root(args, ["rm", f"/home/pmos/rootfs/{img_boot}"])
# Generate installer image
size_reserve = round(os.path.getsize(img_path_dest) / 1024 / 1024) + 200
install_system_image(args, size_reserve, suffix_installer, "pmOS_install",
step, steps, args.split, args.sdcard)
def install(args):
# Sanity checks
if not args.android_recovery_zip and args.sdcard:
@ -510,6 +561,8 @@ def install(args):
steps = 2
elif args.android_recovery_zip:
steps = 4
elif args.on_device_installer:
steps = 8
else:
steps = 5
@ -572,6 +625,10 @@ def install(args):
elif args.android_recovery_zip:
return install_recovery_zip(args)
install_system_image(args, 0, f"rootfs_{args.device}", split=args.split,
sdcard=args.sdcard)
print_flash_info(args)
if args.on_device_installer:
# Runs install_system_image twice
install_on_device_installer(args, 3, steps)
else:
install_system_image(args, 0, f"rootfs_{args.device}",
split=args.split, sdcard=args.sdcard)
print_flash_info(args, steps)

View File

@ -25,7 +25,7 @@ def alpine_native():
def from_chroot_suffix(args, suffix):
if suffix == "native":
return args.arch_native
if suffix == "rootfs_" + args.device:
if suffix in [f"rootfs_{args.device}", f"installer_{args.device}"]:
return args.deviceinfo["arch"]
if suffix.startswith("buildroot_"):
return suffix.split("_", 1)[1]

View File

@ -557,6 +557,11 @@ def arguments():
install.add_argument("--no-base",
help="do not install postmarketos-base (advanced)",
action="store_false", dest="install_base")
install.add_argument("--on-device-installer", "--ondev",
action="store_true",
help="wrap the resulting image in a graphical"
" on-device installer, so the installation can"
" be customized after flashing")
group = install.add_mutually_exclusive_group()
group.add_argument("--sparse", help="generate sparse image file"
" (even if unsupported by device)", default=None,