Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 74 additions & 34 deletions codexctl/__init__.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
### Importing required general modules

import argparse
import os.path
import sys
import logging
import importlib.util
import tempfile
import shutil
import json
import logging
import os.path
import re

from typing import cast
import shutil
import sys
import tempfile
from os import listdir
from typing import cast

try:
from loguru import logger
Expand Down Expand Up @@ -67,6 +66,9 @@ def call_func(self, function: str, args: dict) -> None:

### Download functionalities
if function == "list":
remarkable_ppure_versions = "\n".join(
self.updater.remarkableppure_versions.keys()
)
remarkable_pp_versions = "\n".join(
self.updater.remarkablepp_versions.keys()
)
Expand All @@ -77,14 +79,26 @@ def call_func(self, function: str, args: dict) -> None:
remarkable_1_versions = "\n".join(self.updater.remarkable1_versions.keys())

version_blocks = []
if remarkable_version is None or remarkable_version == HardwareType.RMPPURE:
version_blocks.append(
f"{HardwareType.RMPPURE.formatted_name}:\n{remarkable_ppure_versions}"
)
if remarkable_version is None or remarkable_version == HardwareType.RMPP:
version_blocks.append(f"ReMarkable Paper Pro:\n{remarkable_pp_versions}")
version_blocks.append(
f"{HardwareType.RMPP.formatted_name}:\n{remarkable_pp_versions}"
)
if remarkable_version is None or remarkable_version == HardwareType.RMPPM:
version_blocks.append(f"ReMarkable Paper Pro Move:\n{remarkable_ppm_versions}")
version_blocks.append(
f"{HardwareType.RMPPM.formatted_name}:\n{remarkable_ppm_versions}"
)
if remarkable_version is None or remarkable_version == HardwareType.RM2:
version_blocks.append(f"ReMarkable 2:\n{remarkable_2_versions}")
version_blocks.append(
f"{HardwareType.RM2.formatted_name}:\n{remarkable_2_versions}"
)
if remarkable_version is None or remarkable_version == HardwareType.RM1:
version_blocks.append(f"ReMarkable 1:\n{remarkable_1_versions}")
version_blocks.append(
f"{HardwareType.RM1.formatted_name}:\n{remarkable_1_versions}"
)

print("\n\n".join(version_blocks))

Expand Down Expand Up @@ -122,8 +136,9 @@ def call_func(self, function: str, args: dict) -> None:
logger.info(f"Extracted image to {args['out']}")
else:
try:
from .analysis import get_update_image
from remarkable_update_fuse import UpdateFS

from .analysis import get_update_image
except ImportError:
raise ImportError(
"remarkable_update_fuse is required for mounting. Please install it!"
Expand Down Expand Up @@ -266,20 +281,27 @@ def version_lookup(version: str | None) -> re.Match[str] | None:
image = UpdateImage(update_file)
if isinstance(image, CPIOUpdateImage):
if image.version is None:
raise SystemError(f"Could not determine version from SWU file: {update_file}")
raise SystemError(
f"Could not determine version from SWU file: {update_file}"
)

version_number = image.version
hw_map = {
"reMarkable1": HardwareType.RM1,
"reMarkable2": HardwareType.RM2,
"ferrari": HardwareType.RMPP,
"chiappa": HardwareType.RMPPM,
"tatsu": HardwareType.RMPPURE,
}
if image.hardware_type not in hw_map:
raise SystemError(f"Unsupported hardware type in SWU file: {update_file}")
raise SystemError(
f"Unsupported hardware type in SWU file: {update_file}"
)

swu_hardware = hw_map[image.hardware_type]
logger.info(f"Extracted from SWU: version={version_number}, hardware={swu_hardware.name}")
logger.info(
f"Extracted from SWU: version={version_number}, hardware={swu_hardware.name}"
)

if swu_hardware != remarkable.hardware:
raise SystemError(
Expand All @@ -289,7 +311,9 @@ def version_lookup(version: str | None) -> re.Match[str] | None:
f"Cannot install firmware for different hardware."
)
except ValueError as e:
logger.warning(f"Could not extract metadata from update file: {e}")
logger.warning(
f"Could not extract metadata from update file: {e}"
)

if not version_number:
version_match = version_lookup(version)
Expand Down Expand Up @@ -337,15 +361,18 @@ def version_lookup(version: str | None) -> re.Match[str] | None:

bootloader_files_for_install = None

if (device_version_uses_new_engine and
remarkable.hardware == HardwareType.RMPP):

if (
device_version_uses_new_engine
and remarkable.hardware == HardwareType.RMPP
):
current_version = remarkable.get_device_status()[2]

if UpdateManager.is_bootloader_boundary_downgrade(current_version, version_number):
print("\n" + "="*60)
if UpdateManager.is_bootloader_boundary_downgrade(
current_version, version_number
):
print("\n" + "=" * 60)
print("WARNING: Bootloader Update Required")
print("="*60)
print("=" * 60)
print(f"Current version: {current_version}")
print(f"Target version: {version_number}")
print()
Expand All @@ -359,21 +386,23 @@ def version_lookup(version: str | None) -> re.Match[str] | None:
print()

response = input("Do you want to continue? (y/N): ")
if response.lower() != 'y':
if response.lower() != "y":
raise SystemExit("Installation cancelled by user")

expected_swu_name = f"remarkable-production-memfault-image-{current_version}-{remarkable.hardware.new_download_hw}-public"
expected_swu_path = f"./{expected_swu_name}"

if os.path.isfile(expected_swu_path):
print(f"\nUsing existing {expected_swu_name} for bootloader extraction...")
print(
f"\nUsing existing {expected_swu_name} for bootloader extraction..."
)
current_swu_path = expected_swu_path
else:
print("\nDownloading current version's SWU for bootloader extraction...")
print(
"\nDownloading current version's SWU for bootloader extraction..."
)
current_swu_path = self.updater.download_version(
remarkable.hardware,
current_version,
"./"
remarkable.hardware, current_version, "./"
)

if not current_swu_path:
Expand All @@ -384,17 +413,26 @@ def version_lookup(version: str | None) -> re.Match[str] | None:

print("Extracting bootloader files...")
from remarkable_update_image import UpdateImage

swu_image = UpdateImage(current_swu_path)
bootloader_files_for_install = {
'update-bootloader.sh': swu_image.archive[b'update-bootloader.sh'].read(),
'imx-boot': swu_image.archive[b'imx-boot'].read(),
"update-bootloader.sh": swu_image.archive[
b"update-bootloader.sh"
].read(),
"imx-boot": swu_image.archive[b"imx-boot"].read(),
}

if not all(bootloader_files_for_install.values()):
raise SystemError("Failed to extract bootloader files from current version")
raise SystemError(
"Failed to extract bootloader files from current version"
)

print(f"✓ Extracted update-bootloader.sh ({len(bootloader_files_for_install['update-bootloader.sh'])} bytes)")
print(f"✓ Extracted imx-boot ({len(bootloader_files_for_install['imx-boot'])} bytes)")
print(
f"✓ Extracted update-bootloader.sh ({len(bootloader_files_for_install['update-bootloader.sh'])} bytes)"
)
print(
f"✓ Extracted imx-boot ({len(bootloader_files_for_install['imx-boot'])} bytes)"
)
print()

if not update_file_requires_new_engine:
Expand Down Expand Up @@ -437,7 +475,9 @@ def version_lookup(version: str | None) -> re.Match[str] | None:
)

if device_version_uses_new_engine:
remarkable.install_sw_update(update_file, bootloader_files=bootloader_files_for_install)
remarkable.install_sw_update(
update_file, bootloader_files=bootloader_files_for_install
)
else:
remarkable.install_ohma_update(update_file)

Expand Down
8 changes: 4 additions & 4 deletions codexctl/__main__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from . import main
if __name__ == "__main__":
main()
from . import main

if __name__ == "__main__":
main()
68 changes: 34 additions & 34 deletions codexctl/analysis.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
import ext4
import warnings
import errno
from remarkable_update_image import UpdateImage
from remarkable_update_image import UpdateImageSignatureException
from .device import HardwareType
def get_update_image(file: str):
"""Extracts files from an update image (<3.11 currently)"""
image = UpdateImage(file)
volume = ext4.Volume(image, offset=0)
try:
inode = volume.inode_at("/usr/share/update_engine/update-payload-key.pub.pem")
if inode is None:
raise FileNotFoundError()
inode.verify()
image.verify(inode.open().read())
except UpdateImageSignatureException:
warnings.warn("Signature doesn't match contents", RuntimeWarning)
except FileNotFoundError:
warnings.warn("Public key missing", RuntimeWarning)
except OSError as e:
if e.errno != errno.ENOTDIR:
raise
warnings.warn("Unable to open public key", RuntimeWarning)
return image, volume
import ext4
import warnings
import errno

from remarkable_update_image import UpdateImage
from remarkable_update_image import UpdateImageSignatureException
from .device import HardwareType


def get_update_image(file: str):
"""Extracts files from an update image (<3.11 currently)"""

image = UpdateImage(file)
volume = ext4.Volume(image, offset=0)
try:
inode = volume.inode_at("/usr/share/update_engine/update-payload-key.pub.pem")
if inode is None:
raise FileNotFoundError()

inode.verify()
image.verify(inode.open().read())

except UpdateImageSignatureException:
warnings.warn("Signature doesn't match contents", RuntimeWarning)

except FileNotFoundError:
warnings.warn("Public key missing", RuntimeWarning)

except OSError as e:
if e.errno != errno.ENOTDIR:
raise
warnings.warn("Unable to open public key", RuntimeWarning)

return image, volume
Loading
Loading