diff --git a/native/src/Android.mk b/native/src/Android.mk index d4a418db7..966d66933 100644 --- a/native/src/Android.mk +++ b/native/src/Android.mk @@ -92,7 +92,6 @@ LOCAL_STATIC_LIBRARIES := \ libboot-rs LOCAL_SRC_FILES := \ - boot/main.cpp \ boot/bootimg.cpp \ boot/compress.cpp \ boot/format.cpp \ @@ -102,7 +101,7 @@ LOCAL_LDFLAGS := -static ifdef B_CRT0 LOCAL_STATIC_LIBRARIES += crt0 -LOCAL_LDFLAGS += -lm +LOCAL_LDFLAGS += -lm -Wl,--defsym=vfprintf=musl_vfprintf endif include $(BUILD_EXECUTABLE) diff --git a/native/src/boot/cli.rs b/native/src/boot/cli.rs new file mode 100644 index 000000000..94c18a52f --- /dev/null +++ b/native/src/boot/cli.rs @@ -0,0 +1,397 @@ +use crate::payload::extract_boot_from_payload; +use crate::sign::{sha1_hash, verify_boot_image}; +use argh::FromArgs; +use base::{cmdline_logging, libc::umask, log_err, map_args, raw_cstr, EarlyExitExt, LoggedResult, MappedFile, ResultExt, Utf8CStr}; +use std::ffi::c_char; +use crate::cpio::cpio_commands; +use crate::dtb::dtb_commands; +use crate::ffi::{cleanup, compress, decompress_raw, formats, repack, sign, split_image_dtb, unpack, verify}; +use crate::patch::hexpatch; + +#[derive(FromArgs)] +struct Cli { + #[argh(subcommand)] + action: Action, +} + +#[derive(FromArgs)] +#[argh(subcommand)] +enum Action { + Unpack(Unpack), + Repack(Repack), + Verify(Verify), + Sign(Sign), + Extract(Extract), + HexPatch(HexPatch), + Cpio(Cpio), + Dtb(Dtb), + Split(Split), + Sha1(Sha1), + Cleanup(Cleanup), + Compress(Compress), + Decompress(Decompress), +} + +#[derive(FromArgs)] +#[argh(subcommand, name = "unpack")] +struct Unpack { + #[argh(switch, short = 'n')] + no_decompress: bool, + #[argh(switch, short = 'h')] + dump_header: bool, + #[argh(positional)] + img: String, +} + +#[derive(FromArgs)] +#[argh(subcommand, name = "repack")] +struct Repack { + #[argh(switch, short = 'n')] + no_compress: bool, + #[argh(positional)] + img: String, + #[argh(positional, default = r#""new-boot.img".to_string()"#)] + out: String, +} + +#[derive(FromArgs)] +#[argh(subcommand, name = "verify")] +struct Verify { + #[argh(positional)] + img: String, + #[argh(positional)] + cert: Option, +} + +#[derive(FromArgs)] +#[argh(subcommand, name = "sign")] +struct Sign { + #[argh(positional)] + img: String, + #[argh(positional)] + args: Vec, +} + +#[derive(FromArgs)] +#[argh(subcommand, name = "extract")] +struct Extract { + #[argh(positional)] + payload: String, + #[argh(positional)] + args: Vec, +} + +#[derive(FromArgs)] +#[argh(subcommand, name = "hexpatch")] +struct HexPatch { + #[argh(positional)] + file: String, + #[argh(positional)] + src: String, + #[argh(positional)] + dest: String, +} + +#[derive(FromArgs)] +#[argh(subcommand, name = "cpio")] +struct Cpio { + #[argh(positional)] + cmds: Vec, +} + +#[derive(FromArgs)] +#[argh(subcommand, name = "dtb")] +struct Dtb { + #[argh(positional)] + cmds: Vec, +} + +#[derive(FromArgs)] +#[argh(subcommand, name = "split")] +struct Split { + #[argh(switch, short = 'n')] + no_decompress: bool, + #[argh(positional)] + file: String, +} + +#[derive(FromArgs)] +#[argh(subcommand, name = "sha1")] +struct Sha1 { + #[argh(positional)] + file: String, +} + +#[derive(FromArgs)] +#[argh(subcommand, name = "cleanup")] +struct Cleanup {} + +#[derive(FromArgs)] +#[argh(subcommand, name = "compress")] +struct Compress { + #[argh(option, short = 'f', default = r#""gzip".to_string()"#)] + format: String, + #[argh(positional)] + file: String, + #[argh(positional)] + out: Option, +} + +#[derive(FromArgs)] +#[argh(subcommand, name = "decompress")] +struct Decompress { + #[argh(positional)] + file: String, + #[argh(positional)] + out: Option, +} + +fn print_usage(cmd: &str) { + eprintln!( + r#"MagiskBoot - Boot Image Modification Tool + +Usage: {} [args...] + +Supported actions: + unpack [-n] [-h] + Unpack to its individual components, each component to + a file with its corresponding file name in the current directory. + Supported components: kernel, kernel_dtb, ramdisk.cpio, second, + dtb, extra, and recovery_dtbo. + By default, each component will be decompressed on-the-fly. + If '-n' is provided, all decompression operations will be skipped; + each component will remain untouched, dumped in its original format. + If '-h' is provided, the boot image header information will be + dumped to the file 'header', which can be used to modify header + configurations during repacking. + Return values: + 0:valid 1:error 2:chromeos + + repack [-n] [outbootimg] + Repack boot image components using files from the current directory + to [outbootimg], or 'new-boot.img' if not specified. Current directory + should only contain required files for [outbootimg], or incorrect + [outbootimg] may be produced. + is the original boot image used to unpack the components. + By default, each component will be automatically compressed using its + corresponding format detected in . If a component file + in the current directory is already compressed, then no addition + compression will be performed for that specific component. + If '-n' is provided, all compression operations will be skipped. + If env variable PATCHVBMETAFLAG is set to true, all disable flags in + the boot image's vbmeta header will be set. + + verify [x509.pem] + Check whether the boot image is signed with AVB 1.0 signature. + Optionally provide a certificate to verify whether the image is + signed by the public key certificate. + Return value: + 0:valid 1:error + + sign [name] [x509.pem pk8] + Sign with AVB 1.0 signature. + Optionally provide the name of the image (default: '/boot'). + Optionally provide the certificate/private key pair for signing. + If the certificate/private key pair is not provided, the AOSP + verity key bundled in the executable will be used. + + extract [partition] [outfile] + Extract [partition] from to [outfile]. + If [outfile] is not specified, then output to '[partition].img'. + If [partition] is not specified, then attempt to extract either + 'init_boot' or 'boot'. Which partition was chosen can be determined + by whichever 'init_boot.img' or 'boot.img' exists. + can be '-' to be STDIN. + + hexpatch + Search in , and replace it with + + cpio [commands...] + Do cpio commands to (modifications are done in-place). + Each command is a single argument; add quotes for each command. + See "cpio --help" for supported commands. + + dtb [args...] + Do dtb related actions to . + See "dtb --help" for supported actions. + + split [-n] + Split image.*-dtb into kernel + kernel_dtb. + If '-n' is provided, decompression operations will be skipped; + the kernel will remain untouched, split in its original format. + + sha1 + Print the SHA1 checksum for + + cleanup + Cleanup the current working directory + + compress[=format] [outfile] + Compress with [format] to [outfile]. + /[outfile] can be '-' to be STDIN/STDOUT. + If [format] is not specified, then gzip will be used. + If [outfile] is not specified, then will be replaced + with another file suffixed with a matching file extension. + Supported formats: + + {1} + + decompress [outfile] + Detect format and decompress to [outfile]. + /[outfile] can be '-' to be STDIN/STDOUT. + If [outfile] is not specified, then will be replaced + with another file removing its archive format file extension. + Supported formats: + + {1} +"#, + cmd, formats() + ); +} + +#[no_mangle] +pub unsafe extern "C" fn main( + argc: i32, + argv: *const *const c_char, + _envp: *const *const c_char, +) -> i32 { + cmdline_logging(); + umask(0); + let res: LoggedResult<()> = try { + let mut cmds = map_args(argc, argv)?; + if argc < 2 { + print_usage(cmds.first().unwrap_or(&"magiskboot")); + return 1; + } + + if cmds[1].starts_with("--") { + cmds[1] = &cmds[1][2..]; + } + + if let Some(fmt) = str::strip_prefix(cmds[1], "compress=") { + cmds.insert(1, "compress"); + cmds.insert(2, "-f"); + cmds[3] = fmt; + } + + let mut cli = Cli::from_args(&[cmds[0]], &cmds[1..]).on_early_exit(|| print_usage(cmds[0])); + match cli.action { + Action::Unpack(Unpack { + no_decompress, + dump_header, + ref mut img, + }) => { + return unpack(Utf8CStr::from_string(img).as_ptr(), no_decompress, dump_header); + } + Action::Repack(Repack { + no_compress, + ref mut img, + ref mut out, + }) => { + repack( + Utf8CStr::from_string(img).as_ptr(), + Utf8CStr::from_string(out).as_ptr(), + no_compress, + ); + } + Action::Verify(Verify { + ref mut img, + ref mut cert, + }) => { + return verify(Utf8CStr::from_string(img).as_ptr(), cert.as_mut().map(|x| Utf8CStr::from_string(x).as_ptr()).unwrap_or(std::ptr::null())); + } + Action::Sign(Sign { + ref mut img, + ref mut args, + }) => { + let (pem, pk8) = match args.get_mut(1..=2) { + Some([pem,pk8]) => (Utf8CStr::from_string(pem).as_ptr(), Utf8CStr::from_string(pk8).as_ptr()), + _ => (std::ptr::null(), std::ptr::null()), + }; + return sign( + Utf8CStr::from_string(img).as_ptr(), + args.first_mut().map(|x| Utf8CStr::from_string(x).as_ptr()).unwrap_or(raw_cstr!("/boot")), + pem, pk8 + ) + } + Action::Extract(Extract { + ref payload, + ref args, + }) => { + if args.len() > 2 { + Err(log_err!("Too many arguments"))?; + } + extract_boot_from_payload( + payload, + args.first().map(|x| x.as_str()), + args.get(1).map(|x| x.as_str()), + ) + .log_with_msg(|w| w.write_str("Failed to extract from payload"))?; + } + Action::HexPatch(HexPatch { + ref mut file, + ref mut src, + ref mut dest, + }) => { + if !hexpatch(file, Utf8CStr::from_string(src), Utf8CStr::from_string(dest)) { + Err(log_err!("Failed to patch"))?; + } + } + Action::Cpio(Cpio { + ref cmds, + }) => { + return if cpio_commands(&cmds.iter().map(|x| x.as_str()).collect::>()) { + 0 + } else { + 1 + } + } + Action::Dtb(Dtb { + ref cmds, + }) => { + return if dtb_commands(&cmds.iter().map(|x| x.as_str()).collect::>()) { + 0 + } else { + 1 + } + } + Action::Split(Split { + no_decompress, + ref mut file, + }) => { + return split_image_dtb(Utf8CStr::from_string(file).as_ptr(), no_decompress); + } + Action::Sha1(Sha1 { ref mut file }) => { + let file = MappedFile::open(Utf8CStr::from_string(file))?; + let mut sha1 = [0u8; 20]; + sha1_hash(file.as_ref(), &mut sha1); + for byte in &sha1 { + print!("{:02x}", byte); + } + println!(); + } + Action::Cleanup(_) => { + eprintln!("Cleaning up..."); + cleanup(); + } + Action::Decompress(Decompress { + ref mut file, + ref mut out, + }) => { + decompress_raw(Utf8CStr::from_string(file).as_mut_ptr(), out.as_mut().map(|x| Utf8CStr::from_string(x).as_ptr()).unwrap_or(std::ptr::null())); + } + Action::Compress(Compress { + ref mut file, + ref mut format, + ref mut out, + }) => { + compress(Utf8CStr::from_string(format).as_ptr(), Utf8CStr::from_string(file).as_ptr(), out.as_mut().map(|x| Utf8CStr::from_string(x).as_ptr()).unwrap_or(std::ptr::null())); + } + } + }; + if res.is_ok() { + 0 + } else { + 1 + } +} diff --git a/native/src/boot/compress.hpp b/native/src/boot/compress.hpp index bcb32e59f..167dcc502 100644 --- a/native/src/boot/compress.hpp +++ b/native/src/boot/compress.hpp @@ -12,3 +12,13 @@ void decompress(char *infile, const char *outfile); bool decompress(rust::Slice buf, int fd); bool xz(rust::Slice buf, rust::Vec &out); bool unxz(rust::Slice buf, rust::Vec &out); + +inline ::rust::String formats() { + std::string s; + for (int fmt = GZIP; fmt < LZOP; ++fmt) { + s += fmt2name[(format_t) fmt]; + s += ' '; + } + s.pop_back(); + return {s}; +} diff --git a/native/src/boot/cpio.rs b/native/src/boot/cpio.rs index b7ac18183..12f8e90cd 100644 --- a/native/src/boot/cpio.rs +++ b/native/src/boot/cpio.rs @@ -15,12 +15,12 @@ use num_traits::cast::AsPrimitive; use size::{Base, Size, Style}; use base::libc::{ - c_char, dev_t, gid_t, major, makedev, minor, mknod, mode_t, uid_t, O_CLOEXEC, O_CREAT, + dev_t, gid_t, major, makedev, minor, mknod, mode_t, uid_t, O_CLOEXEC, O_CREAT, O_RDONLY, O_TRUNC, O_WRONLY, S_IFBLK, S_IFCHR, S_IFDIR, S_IFLNK, S_IFMT, S_IFREG, S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR, S_IXGRP, S_IXOTH, S_IXUSR, }; use base::{ - cstr_buf, log_err, map_args, BytesExt, EarlyExitExt, FsPath, LoggedResult, MappedFile, + cstr_buf, log_err, BytesExt, EarlyExitExt, FsPath, LoggedResult, MappedFile, ResultExt, Utf8CStr, Utf8CStrBuf, WriteExt, }; @@ -753,14 +753,8 @@ impl Display for CpioEntry { } } -pub fn cpio_commands(argc: i32, argv: *const *const c_char) -> bool { +pub fn cpio_commands(cmds: &Vec<&str>) -> bool { let res: LoggedResult<()> = try { - if argc < 1 { - Err(log_err!("No arguments"))?; - } - - let cmds = map_args(argc, argv)?; - let mut cli = CpioCli::from_args(&["magiskboot", "cpio"], &cmds).on_early_exit(print_cpio_usage); diff --git a/native/src/boot/dtb.rs b/native/src/boot/dtb.rs index b308e6fee..8e423e75a 100644 --- a/native/src/boot/dtb.rs +++ b/native/src/boot/dtb.rs @@ -7,7 +7,7 @@ use fdt::{ }; use base::{ - libc::c_char, log_err, map_args, EarlyExitExt, LoggedResult, MappedFile, ResultExt, Utf8CStr, + EarlyExitExt, LoggedResult, MappedFile, ResultExt, Utf8CStr, }; use crate::{check_env, patch::patch_verity}; @@ -274,13 +274,8 @@ fn dtb_patch(file: &Utf8CStr) -> LoggedResult { Ok(patched) } -pub fn dtb_commands(argc: i32, argv: *const *const c_char) -> bool { +pub fn dtb_commands(cmds: &Vec<&str>) -> bool { let res: LoggedResult<()> = try { - if argc < 1 { - Err(log_err!("No arguments"))?; - } - let cmds = map_args(argc, argv)?; - let mut cli = DtbCli::from_args(&["magiskboot", "dtb"], &cmds).on_early_exit(print_dtb_usage); diff --git a/native/src/boot/lib.rs b/native/src/boot/lib.rs index d628aa2ef..038ba2cc5 100644 --- a/native/src/boot/lib.rs +++ b/native/src/boot/lib.rs @@ -6,11 +6,7 @@ pub use libz_rs_sys::*; pub use libbz2_rs_sys::*; pub use base; -use cpio::cpio_commands; -use dtb::dtb_commands; -use patch::hexpatch; -use payload::extract_boot_from_payload; -use sign::{get_sha, sha1_hash, sha256_hash, sign_boot_image, verify_boot_image, SHA}; +use sign::{get_sha, sha256_hash, sign_boot_image, verify_boot_image, SHA}; use std::env; mod cpio; @@ -21,6 +17,7 @@ mod payload; #[allow(warnings)] mod proto; mod sign; +mod cli; #[cxx::bridge] pub mod ffi { @@ -35,16 +32,30 @@ pub mod ffi { unsafe extern "C++" { include!("compress.hpp"); fn decompress(buf: &[u8], fd: i32) -> bool; + #[cxx_name = "decompress"] + unsafe fn decompress_raw(infile: *mut c_char, outfile: *const c_char); + unsafe fn compress(format: *const c_char, infile: *const c_char, outfile: *const c_char); fn xz(buf: &[u8], out: &mut Vec) -> bool; fn unxz(buf: &[u8], out: &mut Vec) -> bool; include!("bootimg.hpp"); + include!("magiskboot.hpp"); #[cxx_name = "boot_img"] type BootImage; #[cxx_name = "get_payload"] fn payload(self: &BootImage) -> &[u8]; #[cxx_name = "get_tail"] fn tail(self: &BootImage) -> &[u8]; + + fn cleanup(); + + unsafe fn unpack(image: *const c_char, skip_decomp: bool, hdr: bool) -> i32; + unsafe fn repack(src_img: *const c_char, out_img: *const c_char, skip_comp: bool); + unsafe fn verify(image: *const c_char, cert: *const c_char) -> i32; + unsafe fn sign(image: *const c_char, name: *const c_char, cert: *const c_char, key: *const c_char) -> i32; + unsafe fn split_image_dtb(filename: *const c_char, skip_decomp: bool) -> i32; + + fn formats() -> String; } extern "Rust" { @@ -53,29 +64,19 @@ pub mod ffi { fn update(self: &mut SHA, data: &[u8]); fn finalize_into(self: &mut SHA, out: &mut [u8]); fn output_size(self: &SHA) -> usize; - fn sha1_hash(data: &[u8], out: &mut [u8]); fn sha256_hash(data: &[u8], out: &mut [u8]); - - fn hexpatch(file: &[u8], from: &[u8], to: &[u8]) -> bool; } #[namespace = "rust"] #[allow(unused_unsafe)] extern "Rust" { - fn extract_boot_from_payload( - partition: Utf8CStrRef, - in_path: Utf8CStrRef, - out_path: Utf8CStrRef, - ) -> bool; - unsafe fn cpio_commands(argc: i32, argv: *const *const c_char) -> bool; - unsafe fn verify_boot_image(img: &BootImage, cert: *const c_char) -> bool; unsafe fn sign_boot_image( payload: &[u8], name: *const c_char, cert: *const c_char, key: *const c_char, ) -> Vec; - unsafe fn dtb_commands(argc: i32, argv: *const *const c_char) -> bool; + unsafe fn verify_boot_image(img: &BootImage, cert: *const c_char) -> bool; } } diff --git a/native/src/boot/magiskboot.hpp b/native/src/boot/magiskboot.hpp index f590a740b..f6ea7ba4a 100644 --- a/native/src/boot/magiskboot.hpp +++ b/native/src/boot/magiskboot.hpp @@ -28,3 +28,16 @@ static inline bool check_env(const char *name) { const char *val = getenv(name); return val != nullptr && val == "true"sv; } + +static inline void cleanup() { + unlink(HEADER_FILE); + unlink(KERNEL_FILE); + unlink(RAMDISK_FILE); + unlink(SECOND_FILE); + unlink(KER_DTB_FILE); + unlink(EXTRA_FILE); + unlink(RECV_DTBO_FILE); + unlink(DTB_FILE); + unlink(BOOTCONFIG_FILE); + rm_rf(VND_RAMDISK_DIR); +} \ No newline at end of file diff --git a/native/src/boot/main.cpp b/native/src/boot/main.cpp deleted file mode 100644 index 4972f3820..000000000 --- a/native/src/boot/main.cpp +++ /dev/null @@ -1,228 +0,0 @@ -#include - -#include "boot-rs.hpp" -#include "magiskboot.hpp" -#include "compress.hpp" - -using namespace std; - -#ifdef USE_CRT0 -__BEGIN_DECLS -int musl_vfprintf(FILE *stream, const char *format, va_list arg); -int vfprintf(FILE *stream, const char *format, va_list arg) { - return musl_vfprintf(stream, format, arg); -} -__END_DECLS -#endif - -static void print_formats() { - for (int fmt = GZIP; fmt < LZOP; ++fmt) { - fprintf(stderr, "%s ", fmt2name[(format_t) fmt]); - } -} - -static void usage(char *arg0) { - fprintf(stderr, -R"EOF(MagiskBoot - Boot Image Modification Tool - -Usage: %s [args...] - -Supported actions: - unpack [-n] [-h] - Unpack to its individual components, each component to - a file with its corresponding file name in the current directory. - Supported components: kernel, kernel_dtb, ramdisk.cpio, second, - dtb, extra, and recovery_dtbo. - By default, each component will be decompressed on-the-fly. - If '-n' is provided, all decompression operations will be skipped; - each component will remain untouched, dumped in its original format. - If '-h' is provided, the boot image header information will be - dumped to the file 'header', which can be used to modify header - configurations during repacking. - Return values: - 0:valid 1:error 2:chromeos - - repack [-n] [outbootimg] - Repack boot image components using files from the current directory - to [outbootimg], or 'new-boot.img' if not specified. Current directory - should only contain required files for [outbootimg], or incorrect - [outbootimg] may be produced. - is the original boot image used to unpack the components. - By default, each component will be automatically compressed using its - corresponding format detected in . If a component file - in the current directory is already compressed, then no addition - compression will be performed for that specific component. - If '-n' is provided, all compression operations will be skipped. - If env variable PATCHVBMETAFLAG is set to true, all disable flags in - the boot image's vbmeta header will be set. - - verify [x509.pem] - Check whether the boot image is signed with AVB 1.0 signature. - Optionally provide a certificate to verify whether the image is - signed by the public key certificate. - Return value: - 0:valid 1:error - - sign [name] [x509.pem pk8] - Sign with AVB 1.0 signature. - Optionally provide the name of the image (default: '/boot'). - Optionally provide the certificate/private key pair for signing. - If the certificate/private key pair is not provided, the AOSP - verity key bundled in the executable will be used. - - extract [partition] [outfile] - Extract [partition] from to [outfile]. - If [outfile] is not specified, then output to '[partition].img'. - If [partition] is not specified, then attempt to extract either - 'init_boot' or 'boot'. Which partition was chosen can be determined - by whichever 'init_boot.img' or 'boot.img' exists. - can be '-' to be STDIN. - - hexpatch - Search in , and replace it with - - cpio [commands...] - Do cpio commands to (modifications are done in-place). - Each command is a single argument; add quotes for each command. - See "cpio --help" for supported commands. - - dtb [args...] - Do dtb related actions to . - See "dtb --help" for supported actions. - - split [-n] - Split image.*-dtb into kernel + kernel_dtb. - If '-n' is provided, decompression operations will be skipped; - the kernel will remain untouched, split in its original format. - - sha1 - Print the SHA1 checksum for - - cleanup - Cleanup the current working directory - - compress[=format] [outfile] - Compress with [format] to [outfile]. - /[outfile] can be '-' to be STDIN/STDOUT. - If [format] is not specified, then gzip will be used. - If [outfile] is not specified, then will be replaced - with another file suffixed with a matching file extension. - Supported formats: )EOF", arg0); - - print_formats(); - - fprintf(stderr, R"EOF( - - decompress [outfile] - Detect format and decompress to [outfile]. - /[outfile] can be '-' to be STDIN/STDOUT. - If [outfile] is not specified, then will be replaced - with another file removing its archive format file extension. - Supported formats: )EOF"); - - print_formats(); - - fprintf(stderr, "\n\n"); - exit(1); -} - -int main(int argc, char *argv[]) { - cmdline_logging(); - umask(0); - - if (argc < 2) - usage(argv[0]); - - // Skip '--' for backwards compatibility - string_view action(argv[1]); - if (str_starts(action, "--")) - action = argv[1] + 2; - - if (action == "cleanup") { - fprintf(stderr, "Cleaning up...\n"); - unlink(HEADER_FILE); - unlink(KERNEL_FILE); - unlink(RAMDISK_FILE); - unlink(SECOND_FILE); - unlink(KER_DTB_FILE); - unlink(EXTRA_FILE); - unlink(RECV_DTBO_FILE); - unlink(DTB_FILE); - unlink(BOOTCONFIG_FILE); - rm_rf(VND_RAMDISK_DIR); - } else if (argc > 2 && action == "sha1") { - uint8_t sha1[20]; - { - mmap_data m(argv[2]); - sha1_hash(m, byte_data(sha1, sizeof(sha1))); - } - for (uint8_t i : sha1) - printf("%02x", i); - printf("\n"); - } else if (argc > 2 && action == "split") { - if (argv[2] == "-n"sv) { - if (argc == 3) - usage(argv[0]); - return split_image_dtb(argv[3], true); - } else { - return split_image_dtb(argv[2]); - } - } else if (argc > 2 && action == "unpack") { - int idx = 2; - bool nodecomp = false; - bool hdr = false; - for (;;) { - if (idx >= argc) - usage(argv[0]); - if (argv[idx][0] != '-') - break; - for (char *flag = &argv[idx][1]; *flag; ++flag) { - if (*flag == 'n') - nodecomp = true; - else if (*flag == 'h') - hdr = true; - else - usage(argv[0]); - } - ++idx; - } - return unpack(argv[idx], nodecomp, hdr); - } else if (argc > 2 && action == "repack") { - if (argv[2] == "-n"sv) { - if (argc == 3) - usage(argv[0]); - repack(argv[3], argv[4] ? argv[4] : NEW_BOOT, true); - } else { - repack(argv[2], argv[3] ? argv[3] : NEW_BOOT); - } - } else if (argc > 2 && action == "verify") { - return verify(argv[2], argv[3]); - } else if (argc > 2 && action == "sign") { - if (argc == 5) usage(argv[0]); - return sign( - argv[2], - argc > 3 ? argv[3] : "/boot", - argc > 5 ? argv[4] : nullptr, - argc > 5 ? argv[5] : nullptr); - } else if (argc > 2 && action == "decompress") { - decompress(argv[2], argv[3]); - } else if (argc > 2 && str_starts(action, "compress")) { - compress(action[8] == '=' ? &action[9] : "gzip", argv[2], argv[3]); - } else if (argc > 4 && action == "hexpatch") { - return hexpatch(byte_view(argv[2]), byte_view(argv[3]), byte_view(argv[4])) ? 0 : 1; - } else if (argc > 2 && action == "cpio") { - return rust::cpio_commands(argc - 2, argv + 2) ? 0 : 1; - } else if (argc > 2 && action == "dtb") { - return rust::dtb_commands(argc - 2, argv + 2) ? 0 : 1; - } else if (argc > 2 && action == "extract") { - return rust::extract_boot_from_payload( - argv[2], - argc > 3 ? argv[3] : "", - argc > 4 ? argv[4] : "" - ) ? 0 : 1; - } else { - usage(argv[0]); - } - - return 0; -} diff --git a/native/src/boot/patch.rs b/native/src/boot/patch.rs index d9fecd580..1310b8aa5 100644 --- a/native/src/boot/patch.rs +++ b/native/src/boot/patch.rs @@ -102,13 +102,9 @@ fn hex2byte(hex: &[u8]) -> Vec { v } -pub fn hexpatch(file: &[u8], from: &[u8], to: &[u8]) -> bool { +pub fn hexpatch(file: &mut String, from: &Utf8CStr, to: &Utf8CStr) -> bool { let res: LoggedResult = try { - let file = Utf8CStr::from_bytes(file)?; - let from = Utf8CStr::from_bytes(from)?; - let to = Utf8CStr::from_bytes(to)?; - - let mut map = MappedFile::open_rw(file)?; + let mut map = MappedFile::open_rw(Utf8CStr::from_string(file))?; let pattern = hex2byte(from.as_bytes()); let patch = hex2byte(to.as_bytes()); diff --git a/native/src/boot/payload.rs b/native/src/boot/payload.rs index 75b76083f..fb0b3fbf6 100644 --- a/native/src/boot/payload.rs +++ b/native/src/boot/payload.rs @@ -12,7 +12,7 @@ use crate::{ proto::update_metadata::{mod_InstallOperation::Type, DeltaArchiveManifest}, }; use base::{ - error, ffi::Utf8CStrRef, LoggedError, LoggedResult, ReadSeekExt, ResultExt, Utf8CStr, WriteExt, + error, LoggedError, LoggedResult, ReadSeekExt, ResultExt, WriteExt, }; macro_rules! bad_payload { @@ -28,10 +28,10 @@ macro_rules! bad_payload { const PAYLOAD_MAGIC: &str = "CrAU"; -fn do_extract_boot_from_payload( - in_path: &Utf8CStr, - partition_name: Option<&Utf8CStr>, - out_path: Option<&Utf8CStr>, +pub fn extract_boot_from_payload( + in_path: &str, + partition_name: Option<&str>, + out_path: Option<&str>, ) -> LoggedResult<()> { let mut reader = BufReader::new(if in_path == "-" { unsafe { File::from_raw_fd(0) } @@ -179,24 +179,3 @@ fn do_extract_boot_from_payload( Ok(()) } -pub fn extract_boot_from_payload( - in_path: Utf8CStrRef, - partition: Utf8CStrRef, - out_path: Utf8CStrRef, -) -> bool { - let res: LoggedResult<()> = try { - let partition = if partition.is_empty() { - None - } else { - Some(partition) - }; - let out_path = if out_path.is_empty() { - None - } else { - Some(out_path) - }; - do_extract_boot_from_payload(in_path, partition, out_path)? - }; - res.log_with_msg(|w| w.write_str("Failed to extract from payload")) - .is_ok() -}