mirror of
https://github.com/chenxiaolong/avbroot.git
synced 2026-07-03 14:05:11 +02:00
0a1888ad94
Newer Magisk versions no longer try to autodetect a writable ext4 partition for storing SELinux rules during boot. Instead, the block device is detected during boot image patching and is stored in the ramdisk's `.backup/.magisk` as `makedev(rdev_maj, rdev_min)`. This unfortunately complicates the patching process for avbroot. Even if we replicate Magisk's algorithm for finding a suitable partition, there's no way to find the block device's rdev for it with the information contained in the OTA package. This is the first change that adds a hard dependency on information only attainable from a running device. For these newer Magisk versions, the user will have to patch the boot image once in the Magisk app (must be on the target device) and then run `avbroot magisk-info` to show the computed device ID. Then, avbroot can use this during patching via `--magisk-rules-device`. If the user's device is unable to run the Magisk app prior to patching (eg. unbootable), they'll have to go through the patching process twice, once with `--ignore-magisk-warnings` and a second time with the proper device ID specified. When using `--ignore-magisk-warnings`, root still works, but there will be subtle issues, like certain modules failing to load. Signed-off-by: Andrew Gunnerson <accounts+github@chiller3.com>
120 lines
3.3 KiB
Python
Executable File
120 lines
3.3 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
|
|
import argparse
|
|
import base64
|
|
import os
|
|
import sys
|
|
|
|
sys.path.append(os.path.join(sys.path[0], '..'))
|
|
from avbroot.formats import compression
|
|
from avbroot.formats import cpio
|
|
|
|
|
|
CONTENT_BEGIN = '----- BEGIN UTF-8 CONTENT -----'
|
|
CONTENT_END = '----- END UTF-8 CONTENT -----'
|
|
CONTENT_END_NO_NEWLINE = '----- END UTF-8 CONTENT (NO NEWLINE) -----'
|
|
|
|
BASE64_BEGIN = '----- BEGIN BASE64 CONTENT -----'
|
|
BASE64_END = '----- END BASE64 CONTENT -----'
|
|
BASE64_END_TRUNCATED = '----- END BASE64 CONTENT (TRUNCATED) -----'
|
|
|
|
NO_DATA = '----- NO DATA -----'
|
|
|
|
|
|
def print_content(data, truncate=False):
|
|
if not data:
|
|
print(NO_DATA)
|
|
return
|
|
|
|
if b'\0' not in data:
|
|
try:
|
|
data_str = data.decode('UTF-8')
|
|
|
|
if CONTENT_BEGIN not in data_str \
|
|
and CONTENT_END not in data_str \
|
|
and CONTENT_END_NO_NEWLINE not in data_str:
|
|
print(CONTENT_BEGIN)
|
|
print(data_str, end='')
|
|
if data_str[-1] != '\n':
|
|
print()
|
|
print(CONTENT_END_NO_NEWLINE)
|
|
else:
|
|
print(CONTENT_END)
|
|
|
|
return
|
|
except UnicodeDecodeError:
|
|
pass
|
|
|
|
data_base64 = base64.b64encode(data).decode('ascii')
|
|
|
|
print(BASE64_BEGIN)
|
|
for i, offset in enumerate(range(0, len(data_base64), 76)):
|
|
if truncate and i == 5:
|
|
print(BASE64_END_TRUNCATED)
|
|
return
|
|
|
|
print(data_base64[offset:offset + 76])
|
|
print(BASE64_END)
|
|
|
|
|
|
def parse_args():
|
|
parser = argparse.ArgumentParser()
|
|
subparsers = parser.add_subparsers(dest='subcommand', required=True,
|
|
help='Subcommands')
|
|
|
|
dump = subparsers.add_parser('dump', help='Dump cpio headers and data')
|
|
repack = subparsers.add_parser('repack', help='Repack cpio archive')
|
|
|
|
dump.add_argument('--no-truncate', action='store_true',
|
|
help='Do not truncate binary file contents')
|
|
|
|
for p in (dump, repack):
|
|
p.add_argument('input', help='Path to input cpio file')
|
|
|
|
repack.add_argument('output', help='Path to output cpio file')
|
|
|
|
return parser.parse_args()
|
|
|
|
|
|
def load_archive(path, **cpio_kwargs):
|
|
with open(path, 'rb') as f_raw:
|
|
with compression.CompressedFile(f_raw, 'rb', raw_if_unknown=True) as f:
|
|
return cpio.load(f.fp, **cpio_kwargs), f.format
|
|
|
|
|
|
def save_archive(path, entries, format):
|
|
with open(path, 'wb') as f_raw:
|
|
with compression.CompressedFile(f_raw, 'wb', format=format,
|
|
raw_if_unknown=True) as f:
|
|
cpio.save(f.fp, entries)
|
|
|
|
|
|
def main():
|
|
args = parse_args()
|
|
|
|
if args.subcommand == 'dump':
|
|
entries, format = load_archive(
|
|
args.input,
|
|
# We want to show the headers exactly as they are
|
|
include_trailer=True,
|
|
reassign_inodes=False,
|
|
)
|
|
|
|
print('Compression format:', format)
|
|
print()
|
|
|
|
for entry in entries:
|
|
print(entry)
|
|
print_content(entry.content, truncate=not args.no_truncate)
|
|
print()
|
|
|
|
elif args.subcommand == 'repack':
|
|
entries, format = load_archive(args.input)
|
|
save_archive(args.output, entries, format)
|
|
|
|
else:
|
|
raise NotImplementedError()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main() |