image/fastboot: add --confirm option and generalize fastboot_erase{_dtbo,}()

This commit is contained in:
InsanePrawn 2023-04-30 03:24:17 +02:00
parent 4ba5f87f1e
commit 33e1214aef
3 changed files with 75 additions and 28 deletions

View file

@ -12,28 +12,42 @@ from flavours.flavour import get_profile_flavour
from flavours.cli import profile_option
from wrapper import enforce_wrap
from .fastboot import fastboot_boot, fastboot_erase_dtbo
from .fastboot import fastboot_boot, fastboot_erase
from .image import get_device_name, losetup_rootfs_image, get_image_path, dump_aboot, dump_lk2nd
LK2ND = FLASH_PARTS['LK2ND']
ABOOT = FLASH_PARTS['ABOOT']
TYPES = [LK2ND, JUMPDRIVE, ABOOT]
BOOT_TYPES = [LK2ND, JUMPDRIVE, ABOOT]
@click.command(name='boot')
@profile_option
@click.argument('type', required=False, default=ABOOT, type=click.Choice(TYPES))
@click.argument('type', required=False, default=ABOOT, type=click.Choice(BOOT_TYPES))
@click.option('-b', '--sector-size', type=int, help="Override the device's sector size", default=None)
def cmd_boot(type: str, profile: Optional[str] = None, sector_size: Optional[int] = None):
@click.option(
'--erase-dtbo/--no-erase-dtbo',
is_flag=True,
default=True,
show_default=True,
help="Erase the DTBO partition before flashing",
)
@click.option('--confirm', is_flag=True, help="Ask for confirmation before executing fastboot commands")
def cmd_boot(
type: str,
profile: Optional[str] = None,
sector_size: Optional[int] = None,
erase_dtbo: bool = True,
confirm: bool = False,
):
"""Boot JumpDrive or the Kupfer aboot image. Erases Android DTBO in the process."""
enforce_wrap()
device = get_profile_device(profile)
flavour = get_profile_flavour(profile).name
deviceinfo = device.parse_deviceinfo()
sector_size = sector_size or deviceinfo.flash_pagesize
sector_size = sector_size or device.get_image_sectorsize_default()
if not sector_size:
raise Exception(f"Device {device.name} has no flash_pagesize specified")
raise Exception(f"Device {device.name} has no rootfs_image_sector_size specified")
image_path = get_image_path(device, flavour)
strategy = deviceinfo.flash_method
if not strategy:
@ -54,7 +68,8 @@ def cmd_boot(type: str, profile: Optional[str] = None, sector_size: Optional[int
path = dump_aboot(loop_device + 'p1')
else:
raise Exception(f'Unknown boot image type {type}')
fastboot_erase_dtbo()
fastboot_boot(path)
if erase_dtbo:
fastboot_erase('dtbo', confirm=confirm)
fastboot_boot(path, confirm=confirm)
else:
raise Exception(f"Unknown flash strategy {strategy} for device {device.name}")
raise Exception(f'Unsupported flash strategy "{strategy}" for device {device.name}')

View file

@ -1,42 +1,65 @@
import click
import logging
from exec.cmd import run_cmd, CompletedProcess
from typing import Optional
def fastboot_erase_dtbo():
logging.info("Fastboot: Erasing DTBO")
def confirm_cmd(cmd: list[str], color='green', default=True, msg='Really execute fastboot cmd?') -> bool:
return click.confirm(
f'{click.style(msg, fg=color, bold=True)} {" ".join(cmd)}',
default=default,
abort=False,
)
def fastboot_erase(target: str, confirm: bool = False):
if not target:
raise Exception(f"No fastboot erase target specified: {repr(target)}")
cmd = [
'fastboot',
'erase',
target,
]
if confirm:
if not confirm_cmd(cmd, msg=f'Really erase fastboot "{target}" partition?', color='yellow'):
raise Exception("user aborted")
logging.info(f"Fastboot: Erasing {target}")
run_cmd(
[
'fastboot',
'erase',
'dtbo',
],
cmd,
capture_output=True,
)
def fastboot_flash(partition: str, file: str, sparse_size: Optional[str] = None):
logging.info(f"Fastboot: Flashing {file} to {partition}")
result = run_cmd([
def fastboot_flash(partition: str, file: str, sparse_size: Optional[str] = None, confirm: bool = False):
cmd = [
'fastboot',
*(['-S', sparse_size] if sparse_size is not None else []),
'flash',
partition,
file,
])
]
if confirm:
if not confirm_cmd(cmd):
raise Exception("user aborted")
logging.info(f"Fastboot: Flashing {file} to {partition}")
result = run_cmd(cmd)
assert isinstance(result, CompletedProcess)
if result.returncode != 0:
raise Exception(f'Failed to flash {file}')
def fastboot_boot(file):
logging.info(f"Fastboot: booting {file}")
result = run_cmd([
def fastboot_boot(file, confirm: bool = False):
cmd = [
'fastboot',
'boot',
file,
])
]
if confirm:
if not confirm_cmd(cmd):
raise Exception("user aborted")
logging.info(f"Fastboot: booting {file}")
result = run_cmd(cmd)
assert isinstance(result, CompletedProcess)
if result.returncode != 0:
raise Exception(f'Failed to boot {file} using fastboot')

View file

@ -63,8 +63,9 @@ def prepare_minimal_image(source_path: str, sector_size: int) -> str:
@profile_option
@click.option('-m', '--method', type=click.Choice(FLASH_METHODS))
@click.option('--split-size', help='Chunk size when splitting the image into sparse files via fastboot')
@click.option('--shrink/--no-shrink', is_flag=True, default=True, help="Don't copy and shrink the image file to minimal size")
@click.option('--shrink/--no-shrink', is_flag=True, default=True, help="Copy and shrink the image file to minimal size")
@click.option('-b', '--sector-size', type=int, help="Override the device's sector size", default=None)
@click.option('--confirm', is_flag=True, help="Ask for confirmation before executing fastboot commands")
@click.argument('what', type=click.Choice(list(FLASH_PARTS.values())))
@click.argument('location', type=str, required=False)
def cmd_flash(
@ -75,6 +76,7 @@ def cmd_flash(
profile: Optional[str] = None,
shrink: bool = True,
sector_size: Optional[int] = None,
confirm: bool = False,
):
"""Flash a partition onto a device. `location` takes either a path to a block device or one of emmc, sdcard"""
enforce_wrap()
@ -91,6 +93,12 @@ def cmd_flash(
if what not in FLASH_PARTS.values():
raise Exception(f'Unknown what "{what}", must be one of {", ".join(FLASH_PARTS.values())}')
if location and location.startswith('aboot'):
raise Exception("You're trying to flash something to your aboot partition, "
"which contains the android bootloader itself.\n"
"This will brick your phone and is not what you want.\n"
'Aborting.\nDid you mean "boot"?')
if what == ROOTFS:
path = ''
if method not in FLASH_METHODS:
@ -104,6 +112,7 @@ def cmd_flash(
partition=location,
file=image_path,
sparse_size=split_size if split_size is not None else '100M',
confirm=confirm,
)
elif method in [JUMPDRIVE, DD]:
if method == DD or location.startswith("/") or (location not in LOCATIONS and os.path.exists(location)):
@ -121,12 +130,12 @@ def cmd_flash(
loop_device = losetup_rootfs_image(device_image_path, sector_size)
if what == ABOOT:
path = dump_aboot(f'{loop_device}p1')
fastboot_flash('boot', path)
fastboot_flash(location or 'boot', path, confirm=confirm)
elif what == LK2ND:
path = dump_lk2nd(f'{loop_device}p1')
fastboot_flash('lk2nd', path)
fastboot_flash(location or 'lk2nd', path, confirm=confirm)
elif what == QHYPSTUB:
path = dump_qhypstub(f'{loop_device}p1')
fastboot_flash('qhypstub', path)
fastboot_flash(location or 'qhypstub', path, confirm=confirm)
else:
raise Exception(f'Unknown what "{what}", this must be a bug in kupferbootstrap!')