mirror of
https://gitlab.com/kupfer/kupferbootstrap.git
synced 2025-02-23 05:35:44 -05:00
image/fastboot: add --confirm option and generalize fastboot_erase{_dtbo,}()
This commit is contained in:
parent
4ba5f87f1e
commit
33e1214aef
3 changed files with 75 additions and 28 deletions
|
@ -12,28 +12,42 @@ from flavours.flavour import get_profile_flavour
|
||||||
from flavours.cli import profile_option
|
from flavours.cli import profile_option
|
||||||
from wrapper import enforce_wrap
|
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
|
from .image import get_device_name, losetup_rootfs_image, get_image_path, dump_aboot, dump_lk2nd
|
||||||
|
|
||||||
LK2ND = FLASH_PARTS['LK2ND']
|
LK2ND = FLASH_PARTS['LK2ND']
|
||||||
ABOOT = FLASH_PARTS['ABOOT']
|
ABOOT = FLASH_PARTS['ABOOT']
|
||||||
|
|
||||||
TYPES = [LK2ND, JUMPDRIVE, ABOOT]
|
BOOT_TYPES = [LK2ND, JUMPDRIVE, ABOOT]
|
||||||
|
|
||||||
|
|
||||||
@click.command(name='boot')
|
@click.command(name='boot')
|
||||||
@profile_option
|
@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)
|
@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."""
|
"""Boot JumpDrive or the Kupfer aboot image. Erases Android DTBO in the process."""
|
||||||
enforce_wrap()
|
enforce_wrap()
|
||||||
device = get_profile_device(profile)
|
device = get_profile_device(profile)
|
||||||
flavour = get_profile_flavour(profile).name
|
flavour = get_profile_flavour(profile).name
|
||||||
deviceinfo = device.parse_deviceinfo()
|
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:
|
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)
|
image_path = get_image_path(device, flavour)
|
||||||
strategy = deviceinfo.flash_method
|
strategy = deviceinfo.flash_method
|
||||||
if not strategy:
|
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')
|
path = dump_aboot(loop_device + 'p1')
|
||||||
else:
|
else:
|
||||||
raise Exception(f'Unknown boot image type {type}')
|
raise Exception(f'Unknown boot image type {type}')
|
||||||
fastboot_erase_dtbo()
|
if erase_dtbo:
|
||||||
fastboot_boot(path)
|
fastboot_erase('dtbo', confirm=confirm)
|
||||||
|
fastboot_boot(path, confirm=confirm)
|
||||||
else:
|
else:
|
||||||
raise Exception(f"Unknown flash strategy {strategy} for device {device.name}")
|
raise Exception(f'Unsupported flash strategy "{strategy}" for device {device.name}')
|
||||||
|
|
|
@ -1,42 +1,65 @@
|
||||||
|
import click
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from exec.cmd import run_cmd, CompletedProcess
|
from exec.cmd import run_cmd, CompletedProcess
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
|
||||||
def fastboot_erase_dtbo():
|
def confirm_cmd(cmd: list[str], color='green', default=True, msg='Really execute fastboot cmd?') -> bool:
|
||||||
logging.info("Fastboot: Erasing DTBO")
|
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(
|
run_cmd(
|
||||||
[
|
cmd,
|
||||||
'fastboot',
|
|
||||||
'erase',
|
|
||||||
'dtbo',
|
|
||||||
],
|
|
||||||
capture_output=True,
|
capture_output=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def fastboot_flash(partition: str, file: str, sparse_size: Optional[str] = None):
|
def fastboot_flash(partition: str, file: str, sparse_size: Optional[str] = None, confirm: bool = False):
|
||||||
logging.info(f"Fastboot: Flashing {file} to {partition}")
|
cmd = [
|
||||||
result = run_cmd([
|
|
||||||
'fastboot',
|
'fastboot',
|
||||||
*(['-S', sparse_size] if sparse_size is not None else []),
|
*(['-S', sparse_size] if sparse_size is not None else []),
|
||||||
'flash',
|
'flash',
|
||||||
partition,
|
partition,
|
||||||
file,
|
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)
|
assert isinstance(result, CompletedProcess)
|
||||||
if result.returncode != 0:
|
if result.returncode != 0:
|
||||||
raise Exception(f'Failed to flash {file}')
|
raise Exception(f'Failed to flash {file}')
|
||||||
|
|
||||||
|
|
||||||
def fastboot_boot(file):
|
def fastboot_boot(file, confirm: bool = False):
|
||||||
logging.info(f"Fastboot: booting {file}")
|
cmd = [
|
||||||
result = run_cmd([
|
|
||||||
'fastboot',
|
'fastboot',
|
||||||
'boot',
|
'boot',
|
||||||
file,
|
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)
|
assert isinstance(result, CompletedProcess)
|
||||||
if result.returncode != 0:
|
if result.returncode != 0:
|
||||||
raise Exception(f'Failed to boot {file} using fastboot')
|
raise Exception(f'Failed to boot {file} using fastboot')
|
||||||
|
|
|
@ -63,8 +63,9 @@ def prepare_minimal_image(source_path: str, sector_size: int) -> str:
|
||||||
@profile_option
|
@profile_option
|
||||||
@click.option('-m', '--method', type=click.Choice(FLASH_METHODS))
|
@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('--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('-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('what', type=click.Choice(list(FLASH_PARTS.values())))
|
||||||
@click.argument('location', type=str, required=False)
|
@click.argument('location', type=str, required=False)
|
||||||
def cmd_flash(
|
def cmd_flash(
|
||||||
|
@ -75,6 +76,7 @@ def cmd_flash(
|
||||||
profile: Optional[str] = None,
|
profile: Optional[str] = None,
|
||||||
shrink: bool = True,
|
shrink: bool = True,
|
||||||
sector_size: Optional[int] = None,
|
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"""
|
"""Flash a partition onto a device. `location` takes either a path to a block device or one of emmc, sdcard"""
|
||||||
enforce_wrap()
|
enforce_wrap()
|
||||||
|
@ -91,6 +93,12 @@ def cmd_flash(
|
||||||
if what not in FLASH_PARTS.values():
|
if what not in FLASH_PARTS.values():
|
||||||
raise Exception(f'Unknown what "{what}", must be one of {", ".join(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:
|
if what == ROOTFS:
|
||||||
path = ''
|
path = ''
|
||||||
if method not in FLASH_METHODS:
|
if method not in FLASH_METHODS:
|
||||||
|
@ -104,6 +112,7 @@ def cmd_flash(
|
||||||
partition=location,
|
partition=location,
|
||||||
file=image_path,
|
file=image_path,
|
||||||
sparse_size=split_size if split_size is not None else '100M',
|
sparse_size=split_size if split_size is not None else '100M',
|
||||||
|
confirm=confirm,
|
||||||
)
|
)
|
||||||
elif method in [JUMPDRIVE, DD]:
|
elif method in [JUMPDRIVE, DD]:
|
||||||
if method == DD or location.startswith("/") or (location not in LOCATIONS and os.path.exists(location)):
|
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)
|
loop_device = losetup_rootfs_image(device_image_path, sector_size)
|
||||||
if what == ABOOT:
|
if what == ABOOT:
|
||||||
path = dump_aboot(f'{loop_device}p1')
|
path = dump_aboot(f'{loop_device}p1')
|
||||||
fastboot_flash('boot', path)
|
fastboot_flash(location or 'boot', path, confirm=confirm)
|
||||||
elif what == LK2ND:
|
elif what == LK2ND:
|
||||||
path = dump_lk2nd(f'{loop_device}p1')
|
path = dump_lk2nd(f'{loop_device}p1')
|
||||||
fastboot_flash('lk2nd', path)
|
fastboot_flash(location or 'lk2nd', path, confirm=confirm)
|
||||||
elif what == QHYPSTUB:
|
elif what == QHYPSTUB:
|
||||||
path = dump_qhypstub(f'{loop_device}p1')
|
path = dump_qhypstub(f'{loop_device}p1')
|
||||||
fastboot_flash('qhypstub', path)
|
fastboot_flash(location or 'qhypstub', path, confirm=confirm)
|
||||||
else:
|
else:
|
||||||
raise Exception(f'Unknown what "{what}", this must be a bug in kupferbootstrap!')
|
raise Exception(f'Unknown what "{what}", this must be a bug in kupferbootstrap!')
|
||||||
|
|
Loading…
Add table
Reference in a new issue