pmbootstrap-meow/pmb/install/blockdevice.py
Oliver Smith 942ee20789
install --sdcard: remove external_storage check
The sdcard option can not only be used to write to SD cards, but also
for writing to USB sticks. Or even to write to internal storage if
pmbootstrap runs on a system booted from a live disk / seconds storage.

Drop the check. Thanks to Raymond Hackley for pointing out that this
check is not useful.

Reviewed-by: Anton Bambura <jenneron@postmarketos.org>
Link: https://lists.sr.ht/~postmarketos/pmbootstrap-devel/%3C20231101193702.2223-1-ollieparanoid@postmarketos.org%3E
2023-11-13 09:37:40 +01:00

145 lines
5.9 KiB
Python

# Copyright 2023 Oliver Smith
# SPDX-License-Identifier: GPL-3.0-or-later
import logging
import os
import glob
import pmb.helpers.mount
import pmb.install.losetup
import pmb.helpers.cli
import pmb.config
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 [f"{path}1", f"{path}p1"]:
if not os.path.exists(blockdevice_outside):
continue
blockdevice_inside = "/dev/sdcardp1"
pmb.helpers.mount.bind_file(args, blockdevice_outside,
args.work + '/chroot_native' +
blockdevice_inside)
try:
label = pmb.chroot.root(args, ["blkid", "-s", "LABEL",
"-o", "value",
blockdevice_inside],
output_return=True)
except RuntimeError:
logging.info("WARNING: Could not get block device label,"
" assume no previous installation on that partition")
pmb.helpers.run.root(args, ["umount", args.work + "/chroot_native" +
blockdevice_inside])
return "pmOS_boot" in label
def mount_sdcard(args, path):
"""
:param path: path to sdcard device (e.g. /dev/mmcblk0)
"""
# Sanity checks
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, 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, f"EVERYTHING ON {path} WILL BE"
" ERASED! CONTINUE?"):
raise RuntimeError("Aborted.")
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 MiB
:param size_root: size of the root partition in MiB
:param size_reserve: empty partition between root and boot in MiB (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
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 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_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:
raise RuntimeError("Not enough free space to create rootfs image! "
f"(free: {free}M, required: {size_mb}M)")
# 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)) + "M"
size_mb_root = str(round(size_root)) + "M"
images = {img_path_full: size_mb_full}
if split:
images = {img_path_boot: size_mb_boot,
img_path_root: size_mb_root}
for img_path, size_mb in images.items():
logging.info(f"(native) create {os.path.basename(img_path)} "
f"({size_mb})")
pmb.chroot.root(args, ["truncate", "-s", size_mb, img_path])
# Mount to /dev/install
mount_image_paths = {img_path_full: "/dev/install"}
if 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_file(args, device,
args.work + "/chroot_native" + mount_point)
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 MiB
:param size_root: size of the root partition in MiB
:param size_reserve: empty partition between root and boot in MiB (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 sdcard:
mount_sdcard(args, sdcard)
else:
create_and_mount_image(args, size_boot, size_root, size_reserve,
split)