Add install flag to generate separate boot and system images (#1442)

* Usage: pmbootstrap install --split
* Make obvious that export is the next step when split images are created
* Fix note for missing rootfs image on export
  * Change wording from "system image" to "rootfs image"
  * The idea was to show the note only when the rootfs image was not
    generated yet. But this was broken, because the path we checked for
    was missing the chroot path prefix (which is added now).
  * Also don't display the message, when the split image files exist
This commit is contained in:
Daniele Debernardi 2018-05-01 02:18:40 +02:00 committed by Oliver Smith
parent 4e665a2190
commit 827a60cd25
5 changed files with 79 additions and 46 deletions

View File

@ -1,3 +1,4 @@
import glob
import logging
import os
@ -13,10 +14,11 @@ def frontend(args):
if not os.path.exists(target):
pmb.helpers.run.user(args, ["mkdir", "-p", target])
# System image note
img_path = "/home/pmos/rootfs/" + args.device + ".img"
if not os.path.exists(args.work + "/chroot_native" + img_path):
logging.info("NOTE: To export the system image, run 'pmbootstrap"
# Rootfs image note
chroot = args.work + "/chroot_native"
pattern = chroot + "/home/pmos/rootfs/" + args.device + "*.img"
if not glob.glob(pattern):
logging.info("NOTE: To export the rootfs image, run 'pmbootstrap"
" install' first (without the 'sdcard' parameter).")
# Rebuild the initramfs, just to make sure (see #69)

View File

@ -42,6 +42,8 @@ def symlinks(args, flavor, folder):
"uImage-" + flavor: "Kernel, legacy u-boot image format",
"vmlinuz-" + flavor: "Linux kernel",
args.device + ".img": "Rootfs with partitions for /boot and /",
args.device + "-boot.img": "Boot partition image",
args.device + "-root.img": "Root partition image",
"pmos-" + args.device + ".zip": "Android recovery flashable zip",
}
@ -51,6 +53,8 @@ def symlinks(args, flavor, folder):
path_buildroot = args.work + "/chroot_buildroot_" + args.deviceinfo["arch"]
patterns = [path_boot + "/*-" + flavor,
path_native + "/home/pmos/rootfs/" + args.device + ".img",
path_native + "/home/pmos/rootfs/" + args.device + "-boot.img",
path_native + "/home/pmos/rootfs/" + args.device + "-root.img",
path_buildroot +
"/var/lib/postmarketos-android-recovery-installer/pmos-" +
args.device + ".zip"]

View File

@ -46,9 +46,9 @@ def mount_device_rootfs(args, suffix="native"):
def get_subpartitions_size(args):
"""
Calculate the size of the whole image and boot subpartition.
Calculate the size of the boot and root subpartition.
:returns: (full, boot) the size of the full image and boot
:returns: (boot, root) the size of the boot and root
partition as integer in bytes
"""
# Calculate required sizes first
@ -66,7 +66,7 @@ def get_subpartitions_size(args):
full *= 1.20
full += 50 * 1024 * 1024
boot += 15 * 1024 * 1024
return (full, boot)
return (boot, full - boot)
def get_nonfree_packages(args, device):
@ -284,11 +284,13 @@ def install_system_image(args):
# Partition and fill image/sdcard
logging.info("*** (3/5) PREPARE INSTALL BLOCKDEVICE ***")
pmb.chroot.shutdown(args, True)
(size_image, size_boot) = get_subpartitions_size(args)
(size_boot, size_root) = get_subpartitions_size(args)
if not args.rsync:
pmb.install.blockdevice.create(args, size_image)
pmb.install.partition(args, size_boot)
pmb.install.partitions_mount(args)
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)
if args.full_disk_encryption:
logging.info("WARNING: Full disk encryption is enabled!")
@ -309,7 +311,7 @@ def install_system_image(args):
pmb.chroot.shutdown(args, True)
# Convert system image to sparse using img2simg
if args.deviceinfo["flash_sparse"] == "true":
if args.deviceinfo["flash_sparse"] == "true" and not args.split:
logging.info("(native) make sparse system image")
pmb.chroot.apk.install(args, ["libsparse"])
sys_image = args.device + ".img"
@ -325,7 +327,7 @@ def install_system_image(args):
" target device:")
# System flash information
if not args.sdcard:
if not args.sdcard and not args.split:
logging.info("* pmbootstrap flasher flash_rootfs")
logging.info(" Flashes the generated rootfs image to your device:")
logging.info(" " + args.work + "/chroot_native/home/pmos/rootfs/" +
@ -346,9 +348,14 @@ def install_system_image(args):
" Use 'pmbootstrap flasher boot' to do that.)")
# Export information
logging.info("* If the above steps do not work, you can also create"
" symlinks to the generated files with 'pmbootstrap export'"
" and flash outside of pmbootstrap.")
if args.split:
logging.info("* Boot and root image files have been generated, run"
" 'pmbootstrap export' to create symlinks and flash"
" outside of pmbootstrap.")
else:
logging.info("* If the above steps do not work, you can also create"
" symlinks to the generated files with 'pmbootstrap export'"
" and flash outside of pmbootstrap.")
def install_recovery_zip(args):

View File

@ -70,56 +70,73 @@ def mount_sdcard(args):
raise RuntimeError("Aborted.")
def create_and_mount_image(args, size):
def create_and_mount_image(args, size_boot, size_root):
"""
Create a new image file, and mount it as /dev/install.
:param size: of the whole image in bytes
:param size_boot: size of the boot partition in bytes
:param size_root: size of the root partition in bytes
"""
# Short variables for paths
chroot = args.work + "/chroot_native"
img_path = "/home/pmos/rootfs/" + args.device + ".img"
img_path_outside = chroot + img_path
img_path_prefix = "/home/pmos/rootfs/" + args.device
img_path_full = img_path_prefix + ".img"
img_path_boot = img_path_prefix + "-boot.img"
img_path_root = img_path_prefix + "-root.img"
# Umount and delete existing image
if os.path.exists(img_path_outside):
pmb.helpers.mount.umount_all(args, chroot + "/mnt")
pmb.install.losetup.umount(args, img_path)
pmb.chroot.root(args, ["rm", img_path])
if os.path.exists(img_path_outside):
raise RuntimeError("Failed to remove old image file: " +
img_path_outside)
# Umount and delete existing images
for img_path in [img_path_full, img_path_boot, img_path_root]:
outside = chroot + img_path
if os.path.exists(outside):
pmb.helpers.mount.umount_all(args, chroot + "/mnt")
pmb.install.losetup.umount(args, img_path)
pmb.chroot.root(args, ["rm", img_path])
# Make sure there is enough free space
size_mb = round(size / (1024**2))
size_mb = round((size_boot + size_root) / (1024**2))
disk_data = os.statvfs(args.work)
free = round((disk_data.f_bsize * disk_data.f_bavail) / (1024**2))
if size_mb > free:
raise RuntimeError("Not enough free space to create rootfs image! (free: " + str(free) + "M, required: " + str(size_mb) + "M)")
mb = str(size_mb) + "M"
# Create empty image file
logging.info("(native) create " + args.device + ".img (" + mb + ")")
# Create empty image files
pmb.chroot.user(args, ["mkdir", "-p", "/home/pmos/rootfs"])
pmb.chroot.root(args, ["truncate", "-s", mb, img_path])
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"
images = {img_path_full: size_mb_full}
if args.split:
images = {img_path_boot: size_mb_boot,
img_path_root: size_mb_root}
for img_path, size_mb in images.items():
logging.info("(native) create " + os.path.basename(img_path) + " (" + size_mb + ")")
pmb.chroot.root(args, ["truncate", "-s", size_mb, img_path])
# Mount to /dev/install
logging.info("(native) mount /dev/install (" + args.device + ".img)")
pmb.install.losetup.mount(args, img_path)
device = pmb.install.losetup.device_by_back_file(args, img_path)
pmb.helpers.mount.bind_blockdevice(args, device, args.work +
"/chroot_native/dev/install")
mount_image_paths = {img_path_full: "/dev/install"}
if args.split:
mount_image_paths = {img_path_boot: "/dev/installp1",
img_path_root: "/dev/installp2"}
for img_path, mount_point in mount_image_paths.items():
logging.info("(native) mount " + mount_point +
" (" + os.path.basename(img_path) + ")")
pmb.install.losetup.mount(args, img_path)
device = pmb.install.losetup.device_by_back_file(args, img_path)
pmb.helpers.mount.bind_blockdevice(args, device, args.work +
"/chroot_native" + mount_point)
def create(args, size):
def create(args, size_boot, size_root):
"""
Create /dev/install (the "install blockdevice").
:param size: of the whole image in bytes
:param size_boot: size of the boot partition in bytes
:param size_root: size of the root partition in bytes
"""
pmb.helpers.mount.umount_all(
args, args.work + "/chroot_native/dev/install")
if args.sdcard:
mount_sdcard(args)
else:
create_and_mount_image(args, size)
create_and_mount_image(args, size_boot, size_root)

View File

@ -321,8 +321,14 @@ def arguments():
# Action: install
install = sub.add_parser("install", help="set up device specific" +
" chroot and install to sdcard or image file")
install.add_argument("--sdcard", help="path to the sdcard device,"
" eg. /dev/mmcblk0")
group = install.add_mutually_exclusive_group()
group.add_argument("--sdcard", help="path to the sdcard device,"
" eg. /dev/mmcblk0")
group.add_argument("--split", help="install the boot and root partition"
" in separated image files", action="store_true")
group.add_argument("--android-recovery-zip",
help="generate TWRP flashable zip",
action="store_true", dest="android_recovery_zip")
install.add_argument("--rsync", help="update the sdcard using rsync,"
" only works with --no-fde", action="store_true")
install.add_argument("--cipher", help="cryptsetup cipher used to"
@ -337,9 +343,6 @@ def arguments():
install.add_argument("--flavor",
help="Specify kernel flavor to include in recovery"
" flashable zip", default=None)
install.add_argument("--android-recovery-zip",
help="generate TWRP flashable zip",
action="store_true", dest="android_recovery_zip")
install.add_argument("--recovery-install-partition", default="system",
help="partition to flash from recovery,"
" eg. external_sd",