Compare commits

...

14 Commits

Author SHA1 Message Date
Oliver Smith ed4072956d
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
2020-06-09 15:48:12 +02:00
Oliver Smith 8d0f3a1c55
install_system_image: add sdcard argument
The on-device installer will run install_system_image once with
sdcard=None and the second time with sdcard=args.sdcard.
2020-06-09 15:48:12 +02:00
Oliver Smith 9a0ef38ee3
install_system_image: add split argument 2020-06-09 15:48:11 +02:00
Oliver Smith 21a6c7189b
install_system_image: add step, steps parameters 2020-06-09 15:48:11 +02:00
Oliver Smith 4a5137064d
install_system_image: add root_label parameter
Prepare for on-device installer, so it can use something other than
"pmOS_root" as label.
2020-06-09 15:48:11 +02:00
Oliver Smith 4bebad987d
install_system_image: add suffix argument
Allow files to be copied from a different suffix than rootfs_$DEVICE.
The on-device installer will use this.
2020-06-09 15:48:11 +02:00
Oliver Smith fdc2fe309e
Cosmetics: install_system_image(): remove FDE msg
Full disk encryption (--fde) has not been the default for a long time,
so no need to warn the user about it.
2020-06-09 15:48:11 +02:00
Oliver Smith c940c96078
pmb.install._install.print_flash_info: cosmetics
Fix a typo and wrap lines at 80 characters (especially one extra long
line). Use f-strings in lines that were modified (as we're doing it
nowadays).
2020-06-09 15:48:11 +02:00
Oliver Smith 854c96f63f
pmb.install._install.print_flash_info: new func
Move code that prints flashing information from install_system_image()
to its own function. For the on-device installer, we'll need to call
install_system_image() twice, without printing the flashing information
each time. While at it, add a "step" parameter.
2020-06-09 15:48:11 +02:00
Oliver Smith 67e3c5ad1a
pmbootstrap install: support size_reserve
Create an empty partition between boot and root. This will be used by
the on-device installer, as explained in detail here:
https://wiki.postmarketos.org/wiki/On-device_installer
2020-06-09 15:48:11 +02:00
Oliver Smith d8c84c8912
Cosmetic: pmb.install.partition: fix comment 2020-06-09 15:48:11 +02:00
Oliver Smith 3f1f21add5
pmb/install: have size_boot, size_root in MB
Prepare for a future patch, that adds reserved space in MB, by changing
size_boot and size_root from bytes to MB everywhere. This is what we need
most of the time and allows to drop some /1024**2 statements.
2020-06-09 15:48:11 +02:00
Oliver Smith 9da12415b8
pmbootstrap chroot --install-blockdev: new option
Create /dev/install inside the chroot from a block device, just like
done during the installation. This is useful for testing the Calamares
installer.
2020-06-09 15:48:11 +02:00
Oliver Smith ac7d66fade
blockdevice.create_and_mount_image: add split arg
Add a "split" argument to the function, instead of using "args.split"
directly. "args.split" is only defined when calling "pmbootstrap install",
but the next patch will add a code path that calls the function from
"pmbootstrap chroot".
2020-06-09 15:48:06 +02:00
9 changed files with 265 additions and 109 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

@ -25,6 +25,7 @@ import pmb.helpers.run
import pmb.helpers.aportupgrade
import pmb.helpers.status
import pmb.install
import pmb.install.blockdevice
import pmb.parse
import pmb.qemu
@ -132,6 +133,14 @@ def chroot(args):
env["DISPLAY"] = os.environ.get("DISPLAY")
env["XAUTHORITY"] = "/home/pmos/.Xauthority"
# Install blockdevice
if args.install_blockdev:
size_boot = 128 # 128 MB
size_root = 4096 # 4 GB
size_reserve = 2048 # 2 GB
pmb.install.blockdevice.create_and_mount_image(args, size_boot,
size_root, size_reserve)
# Run the command as user/root
if args.user:
logging.info("(" + suffix + ") % su pmos -c '" +
@ -195,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
@ -19,32 +20,38 @@ import pmb.install.recovery
import pmb.install
def mount_device_rootfs(args, suffix="native"):
def mount_device_rootfs(args, suffix_rootfs, suffix_mount="native"):
"""
Mount the device rootfs.
:param suffix_rootfs: the chroot suffix, where the rootfs that will be
installed on the device has been created (e.g.
"rootfs_qemu-amd64")
:param suffix_mount: the chroot suffix, where the device rootfs will be
mounted (e.g. "native")
"""
mountpoint = "/mnt/rootfs_" + args.device
pmb.helpers.mount.bind(args, args.work + "/chroot_rootfs_" + args.device,
args.work + "/chroot_" + suffix + mountpoint)
mountpoint = f"/mnt/{suffix_rootfs}"
pmb.helpers.mount.bind(args, f"{args.work}/chroot_{suffix_rootfs}",
f"{args.work}/chroot_{suffix_mount}{mountpoint}")
return mountpoint
def get_subpartitions_size(args):
def get_subpartitions_size(args, suffix):
"""
Calculate the size of the boot and root subpartition.
:param suffix: the chroot suffix, e.g. "rootfs_qemu-amd64"
:returns: (boot, root) the size of the boot and root
partition as integer in bytes
partition as integer in MB
"""
boot = int(args.boot_size) * 1024 * 1024
boot = int(args.boot_size)
# Estimate root partition size, then add some free space. The size
# calculation is not as trivial as one may think, and depending on the
# file system etc it seems to be just impossible to get it right.
chroot = args.work + "/chroot_rootfs_" + args.device
root = pmb.helpers.other.folder_size(args, chroot)
chroot = f"{args.work}/chroot_{suffix}"
root = pmb.helpers.other.folder_size(args, chroot) / 1024 / 1024
root *= 1.20
root += 50 * 1024 * 1024
root += 50
return (boot, root)
@ -94,16 +101,17 @@ def get_kernel_package(args, device):
return ["device-" + device + "-kernel-" + args.kernel]
def copy_files_from_chroot(args):
def copy_files_from_chroot(args, suffix):
"""
Copy all files from the rootfs chroot to /mnt/install, except
for the home folder (because /home will contain some empty
mountpoint folders).
:param suffix: the chroot suffix, e.g. "rootfs_qemu-amd64"
"""
# Mount the device rootfs
logging.info("(native) copy rootfs_" + args.device + " to" +
" /mnt/install/")
mountpoint = mount_device_rootfs(args)
logging.info(f"(native) copy {suffix} to /mnt/install/")
mountpoint = mount_device_rootfs(args, suffix)
mountpoint_outside = args.work + "/chroot_native" + mountpoint
# Remove empty qemu-user binary stub (where the binary was bind-mounted)
@ -303,7 +311,7 @@ def embed_firmware(args):
"deviceinfo_sd_embed_firmware_step_size "
"is not valid: {}".format(step))
device_rootfs = mount_device_rootfs(args)
device_rootfs = mount_device_rootfs(args, f"rootfs_{args.device}")
binaries = args.deviceinfo["sd_embed_firmware"].split(",")
# Perform three checks prior to writing binaries to disk: 1) that binaries
@ -366,31 +374,36 @@ def sanity_check_sdcard(device):
raise RuntimeError("{} is read-only, is the sdcard locked?".format(device))
def install_system_image(args):
def install_system_image(args, size_reserve, suffix, root_label="pmOS_root",
step=3, steps=5, split=False, sdcard=None):
"""
:param size_reserve: empty partition between root and boot in MB (pma#463)
:param suffix: the chroot suffix, where the rootfs that will be installed
on the device has been created (e.g. "rootfs_qemu-amd64")
:param root_label: label of the root partition (e.g. "pmOS_root")
:param step: next installation step
:param steps: total installation steps
:param split: create separate images for boot and root partitions
:param sdcard: path to sdcard device (e.g. /dev/mmcblk0) or None
"""
# Partition and fill image/sdcard
logging.info("*** (3/5) PREPARE INSTALL BLOCKDEVICE ***")
logging.info(f"*** ({step}/{steps}) PREPARE INSTALL BLOCKDEVICE ***")
pmb.chroot.shutdown(args, True)
(size_boot, size_root) = get_subpartitions_size(args)
(size_boot, size_root) = get_subpartitions_size(args, suffix)
if not args.rsync:
pmb.install.blockdevice.create(args, size_boot, size_root)
if not args.split:
pmb.install.partition(args, size_boot)
if not args.split:
pmb.install.partitions_mount(args)
pmb.install.blockdevice.create(args, size_boot, size_root,
size_reserve, split, sdcard)
if not split:
pmb.install.partition(args, size_boot, size_reserve)
if not split:
root_id = 3 if size_reserve else 2
pmb.install.partitions_mount(args, root_id, sdcard)
if args.full_disk_encryption:
logging.info("WARNING: Full disk encryption is enabled!")
logging.info("Make sure that osk-sdl has been properly configured for your device")
logging.info("or else you will be unable to unlock the rootfs on boot!")
logging.info("If you started a device port, it is recommended you disable")
logging.info("FDE by re-running the install command without '--fde' until")
logging.info("you have properly configured osk-sdl. More information:")
logging.info("<https://postmarketos.org/osk-port>")
pmb.install.format(args)
pmb.install.format(args, size_reserve, root_label, sdcard)
# Just copy all the files
logging.info("*** (4/5) FILL INSTALL BLOCKDEVICE ***")
copy_files_from_chroot(args)
logging.info(f"*** ({step + 1}/{steps}) FILL INSTALL BLOCKDEVICE ***")
copy_files_from_chroot(args, suffix)
create_home_from_skel(args)
configure_apk(args)
copy_ssh_keys(args)
@ -402,7 +415,7 @@ def install_system_image(args):
if sparse is None:
sparse = args.deviceinfo["flash_sparse"] == "true"
if sparse and not args.split and not args.sdcard:
if sparse and not split and not sdcard:
logging.info("(native) make sparse rootfs")
pmb.chroot.apk.install(args, ["android-tools"])
sys_image = args.device + ".img"
@ -412,8 +425,13 @@ def install_system_image(args):
pmb.chroot.user(args, ["mv", "-f", sys_image_sparse, sys_image],
working_dir="/home/pmos/rootfs/")
# Kernel flash information
logging.info("*** (5/5) FLASHING TO DEVICE ***")
def print_flash_info(args, step=5):
""" Print flashing information, based on the deviceinfo data and the
pmbootstrap arguments.
:param step: installation step number """
logging.info(f"*** ({step}/{step}) FLASHING TO DEVICE ***")
logging.info("Run the following to flash your installation to the"
" target device:")
@ -428,16 +446,18 @@ def install_system_image(args):
logging.info("* pmbootstrap flasher flash_rootfs")
logging.info(" Flashes the generated rootfs image to your device:")
if args.split:
logging.info(" " + args.work + "/chroot_native/home/pmos/rootfs/" +
args.device + "-rootfs.img")
logging.info(f" {args.work}/chroot_native/home/pmos/rootfs/"
f"{args.device}-rootfs.img")
else:
logging.info(" " + args.work + "/chroot_native/home/pmos/rootfs/" +
args.device + ".img")
logging.info(" (NOTE: This file has a partition table, which contains"
" /boot and / subpartitions. That way we don't need to"
" change the partition layout on your device.)")
logging.info(f" {args.work}/chroot_native/home/pmos/rootfs/"
f"{args.device}.img")
logging.info(" (NOTE: This file has a partition table, which"
" contains /boot and / subpartitions. That way we"
" don't need to change the partition layout on your"
" device.)")
# if current flasher supports vbmeta and partition is explicitly spcified in deviceinfo
# if current flasher supports vbmeta and partition is explicitly specified
# in deviceinfo
if "flash_vbmeta" in flasher_actions and \
(args.deviceinfo["flash_fastboot_partition_vbmeta"] or
args.deviceinfo["flash_heimdall_partition_vbmeta"]):
@ -448,14 +468,15 @@ def install_system_image(args):
# (e.g. an Android boot image is generated). In that case, "flash_kernel"
# works even when partitions are split or installing for sdcard.
# This is not possible if the flash method requires split partitions.
if "flash_kernel" in flasher_actions and (not requires_split or args.split):
if "flash_kernel" in flasher_actions and \
(not requires_split or args.split):
logging.info("* pmbootstrap flasher flash_kernel")
logging.info(" Flashes the kernel + initramfs to your device:")
if requires_split:
logging.info(" " + args.work + "/chroot_native/home/pmos/rootfs/" +
args.device + "-boot.img")
logging.info(f" {args.work}/chroot_native/home/pmos/rootfs/"
f"{args.device}-boot.img")
else:
logging.info(" " + args.work + "/chroot_rootfs_" + args.device + "/boot")
logging.info(f" {args.work}/chroot_rootfs_{args.device}/boot")
if "boot" in flasher_actions:
logging.info(" (NOTE: " + method + " also supports booting"
@ -471,7 +492,7 @@ def install_system_image(args):
def install_recovery_zip(args):
logging.info("*** (3/4) CREATING RECOVERY-FLASHABLE ZIP ***")
suffix = "buildroot_" + args.deviceinfo["arch"]
mount_device_rootfs(args, suffix)
mount_device_rootfs(args, f"rootfs_{args.device}", suffix)
pmb.install.recovery.create_zip(args, suffix)
# Flash information
@ -480,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:
@ -490,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
@ -547,7 +620,15 @@ def install(args):
# Set the hostname as the device name
setup_hostname(args)
if args.android_recovery_zip:
install_recovery_zip(args)
elif not args.no_image:
install_system_image(args)
if args.no_image:
return
elif args.android_recovery_zip:
return install_recovery_zip(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

@ -9,14 +9,15 @@ import pmb.helpers.cli
import pmb.config
def previous_install(args):
def previous_install(args, path):
"""
Search the sdcard for possible existence of a previous installation of pmOS.
We temporarily mount the possible pmOS_boot partition as /dev/sdcardp1 inside
the native chroot to check the label from there.
:param path: path to sdcard device (e.g. /dev/mmcblk0)
"""
label = ""
for blockdevice_outside in [args.sdcard + "1", args.sdcard + "p1"]:
for blockdevice_outside in [f"{path}1", f"{path}p1"]:
if not os.path.exists(blockdevice_outside):
continue
blockdevice_inside = "/dev/sdcardp1"
@ -28,39 +29,45 @@ def previous_install(args):
return "pmOS_boot" in label
def mount_sdcard(args):
def mount_sdcard(args, path):
"""
:param path: path to sdcard device (e.g. /dev/mmcblk0)
"""
# Sanity checks
if args.deviceinfo["external_storage"] != "true":
raise RuntimeError("According to the deviceinfo, this device does"
" not support a sdcard installation.")
if not os.path.exists(args.sdcard):
raise RuntimeError("The sdcard device does not exist: " +
args.sdcard)
for path in glob.glob(args.sdcard + "*"):
if pmb.helpers.mount.ismount(path):
raise RuntimeError(path + " is mounted! We will not attempt"
" to format this!")
logging.info("(native) mount /dev/install (host: " + args.sdcard + ")")
pmb.helpers.mount.bind_file(args, args.sdcard,
if not os.path.exists(path):
raise RuntimeError(f"The sdcard device does not exist: {path}")
for path_mount in glob.glob(f"{path}*"):
if pmb.helpers.mount.ismount(path_mount):
raise RuntimeError(f"{path_mount} is mounted! Will not attempt to"
" format this!")
logging.info(f"(native) mount /dev/install (host: {path})")
pmb.helpers.mount.bind_file(args, path,
args.work + "/chroot_native/dev/install")
if previous_install(args):
if previous_install(args, path):
if not pmb.helpers.cli.confirm(args, "WARNING: This device has a"
" previous installation of pmOS."
" CONTINUE?"):
raise RuntimeError("Aborted.")
else:
if not pmb.helpers.cli.confirm(args, "EVERYTHING ON " + args.sdcard +
" WILL BE ERASED! CONTINUE?"):
if not pmb.helpers.cli.confirm(args, f"EVERYTHING ON {path} WILL BE"
" ERASED! CONTINUE?"):
raise RuntimeError("Aborted.")
def create_and_mount_image(args, size_boot, size_root):
def create_and_mount_image(args, size_boot, size_root, size_reserve,
split=False):
"""
Create a new image file, and mount it as /dev/install.
:param size_boot: size of the boot partition in bytes
:param size_root: size of the root partition in bytes
:param size_boot: size of the boot partition in MB
:param size_root: size of the root partition in MB
:param size_reserve: empty partition between root and boot in MB (pma#463)
:param split: create separate images for boot and root partitions
"""
# Short variables for paths
chroot = args.work + "/chroot_native"
img_path_prefix = "/home/pmos/rootfs/" + args.device
@ -77,7 +84,7 @@ def create_and_mount_image(args, size_boot, size_root):
pmb.chroot.root(args, ["rm", img_path])
# Make sure there is enough free space
size_mb = round((size_boot + size_root) / (1024**2))
size_mb = round(size_boot + size_reserve + size_root)
disk_data = os.statvfs(args.work)
free = round((disk_data.f_bsize * disk_data.f_bavail) / (1024**2))
if size_mb > free:
@ -86,10 +93,10 @@ def create_and_mount_image(args, size_boot, size_root):
# Create empty image files
pmb.chroot.user(args, ["mkdir", "-p", "/home/pmos/rootfs"])
size_mb_full = str(size_mb) + "M"
size_mb_boot = str(round(size_boot / (1024**2))) + "M"
size_mb_root = str(round(size_root / (1024**2))) + "M"
size_mb_boot = str(round(size_boot)) + "M"
size_mb_root = str(round(size_root)) + "M"
images = {img_path_full: size_mb_full}
if args.split:
if split:
images = {img_path_boot: size_mb_boot,
img_path_root: size_mb_root}
for img_path, size_mb in images.items():
@ -98,7 +105,7 @@ def create_and_mount_image(args, size_boot, size_root):
# Mount to /dev/install
mount_image_paths = {img_path_full: "/dev/install"}
if args.split:
if split:
mount_image_paths = {img_path_boot: "/dev/installp1",
img_path_root: "/dev/installp2"}
@ -111,16 +118,20 @@ def create_and_mount_image(args, size_boot, size_root):
args.work + "/chroot_native" + mount_point)
def create(args, size_boot, size_root):
def create(args, size_boot, size_root, size_reserve, split, sdcard):
"""
Create /dev/install (the "install blockdevice").
:param size_boot: size of the boot partition in bytes
:param size_root: size of the root partition in bytes
:param size_boot: size of the boot partition in MB
:param size_root: size of the root partition in MB
:param size_reserve: empty partition between root and boot in MB (pma#463)
:param split: create separate images for boot and root partitions
:param sdcard: path to sdcard device (e.g. /dev/mmcblk0) or None
"""
pmb.helpers.mount.umount_all(
args, args.work + "/chroot_native/dev/install")
if args.sdcard:
mount_sdcard(args)
if sdcard:
mount_sdcard(args, sdcard)
else:
create_and_mount_image(args, size_boot, size_root)
create_and_mount_image(args, size_boot, size_root, size_reserve,
split)

View File

@ -23,9 +23,11 @@ def format_and_mount_boot(args):
pmb.chroot.root(args, ["mount", device, mountpoint])
def format_and_mount_root(args):
def format_and_mount_root(args, device):
"""
:param device: root partition on install block device (e.g. /dev/installp2)
"""
mountpoint = "/dev/mapper/pm_crypt"
device = "/dev/installp2"
if args.full_disk_encryption:
logging.info("(native) format " + device + " (root, luks), mount to " +
mountpoint)
@ -41,12 +43,15 @@ def format_and_mount_root(args):
raise RuntimeError("Failed to open cryptdevice!")
def format_and_mount_pm_crypt(args):
def format_and_mount_pm_crypt(args, device, root_label, sdcard):
"""
:param device: root partition on install block device (e.g. /dev/installp2)
:param root_label: label of the root partition (e.g. "pmOS_root")
:param sdcard: path to sdcard device (e.g. /dev/mmcblk0) or None
"""
# Block device
if args.full_disk_encryption:
device = "/dev/mapper/pm_crypt"
else:
device = "/dev/installp2"
# Format
if not args.rsync:
@ -55,12 +60,12 @@ def format_and_mount_pm_crypt(args):
# When changing the options of mkfs.ext4, also change them in the
# recovery zip code (see 'grep -r mkfs\.ext4')!
mkfs_ext4_args = ["mkfs.ext4", "-O", "^metadata_csum", "-F",
"-q", "-L", "pmOS_root"]
"-q", "-L", root_label]
# When we don't know the file system size before hand like
# with non-block devices, we need to explicitely set a number of
# inodes. See #1717 and #1845 for details
if not args.sdcard:
if not sdcard:
mkfs_ext4_args = mkfs_ext4_args + ["-N", "100000"]
pmb.chroot.root(args, mkfs_ext4_args + [device])
@ -72,7 +77,13 @@ def format_and_mount_pm_crypt(args):
pmb.chroot.root(args, ["mount", device, mountpoint])
def format(args):
format_and_mount_root(args)
format_and_mount_pm_crypt(args)
def format(args, size_reserve, root_label, sdcard):
"""
:param size_reserve: empty partition between root and boot in MB (pma#463)
:param root_label: label of the root partition (e.g. "pmOS_root")
:param sdcard: path to sdcard device (e.g. /dev/mmcblk0) or None
"""
root_dev = "/dev/installp3" if size_reserve else "/dev/installp2"
format_and_mount_root(args, root_dev)
format_and_mount_pm_crypt(args, root_dev, root_label, sdcard)
format_and_mount_boot(args)

View File

@ -8,12 +8,14 @@ import pmb.config
import pmb.install.losetup
def partitions_mount(args):
def partitions_mount(args, root_id, sdcard):
"""
Mount blockdevices of partitions inside native chroot
:param root_id: root partition id (3 with --reserve-space, otherwise 2)
:param sdcard: path to sdcard device (e.g. /dev/mmcblk0) or None
"""
prefix = args.sdcard
if not args.sdcard:
prefix = sdcard
if not sdcard:
img_path = "/home/pmos/rootfs/" + args.device + ".img"
prefix = pmb.install.losetup.device_by_back_file(args, img_path)
@ -35,22 +37,28 @@ def partitions_mount(args):
prefix + " to be located at " + prefix +
"1 or " + prefix + "p1!")
for i in [1, 2]:
for i in [1, root_id]:
source = prefix + partition_prefix + str(i)
target = args.work + "/chroot_native/dev/installp" + str(i)
pmb.helpers.mount.bind_file(args, source, target)
def partition(args, size_boot):
def partition(args, size_boot, size_reserve):
"""
Partition /dev/install and create /dev/install{p1,p2}
Partition /dev/install and create /dev/install{p1,p2,p3}:
* /dev/installp1: boot
* /dev/installp2: root (or reserved space)
* /dev/installp3: (root, if reserved space > 0)
size_boot: size of the boot partition in bytes.
:param size_boot: size of the boot partition in MB
:param size_reserve: empty partition between root and boot in MB (pma#463)
"""
# Convert to MB and print info
mb_boot = str(round(size_boot / 1024 / 1024)) + "M"
logging.info("(native) partition /dev/install (boot: " + mb_boot +
", root: the rest)")
mb_boot = f"{round(size_boot)}M"
mb_reserved = f"{round(size_reserve)}M"
mb_root_start = f"{round(size_boot) + round(size_reserve)}M"
logging.info(f"(native) partition /dev/install (boot: {mb_boot},"
f" reserved: {mb_reserved}, root: the rest)")
filesystem = args.deviceinfo["boot_filesystem"] or "ext2"
@ -63,9 +71,16 @@ def partition(args, size_boot):
commands = [
["mktable", "msdos"],
["mkpart", "primary", filesystem, boot_part_start + 's', mb_boot],
["mkpart", "primary", mb_boot, "100%"],
]
if size_reserve:
commands += [["mkpart", "primary", mb_boot, mb_reserved]]
commands += [
["mkpart", "primary", mb_root_start, "100%"],
["set", "1", "boot", "on"]
]
for command in commands:
pmb.chroot.root(args, ["parted", "-s", "/dev/install"] +
command, check=False)

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

@ -497,6 +497,10 @@ def arguments():
help="Copy .Xauthority and set environment variables,"
" so X11 applications can be started (native"
" chroot only)")
chroot.add_argument("-i", "--install-blockdev", action="store_true",
help="Create a sparse image file and mount it as"
" /dev/install, just like during the"
" installation process.")
for action in [build_init, chroot]:
suffix = action.add_mutually_exclusive_group()
if action == chroot:
@ -553,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,