Compare commits

...

6 Commits

Author SHA1 Message Date
LoveSy
5cbaf2ae11 Use super let to simplify code 2025-08-22 12:05:44 -07:00
topjohnwu
8ebc6207b4 Merge headers 2025-08-22 12:03:47 -07:00
topjohnwu
7848ee616b Cleanup magiskboot main function 2025-08-22 12:03:47 -07:00
topjohnwu
fd193c3cae Simplify ResultExt implementation
Also introduce OptionExt
2025-08-22 12:03:47 -07:00
topjohnwu
36d33c7a85 Make log_err directly return LoggedResult 2025-08-22 12:03:47 -07:00
topjohnwu
5caf28d27c Hide harmless error reporting 2025-08-22 12:03:47 -07:00
16 changed files with 373 additions and 366 deletions

View File

@@ -23,32 +23,29 @@ pub type LoggedResult<T> = Result<T, LoggedError>;
#[macro_export]
macro_rules! log_err {
() => {{
Err($crate::LoggedError::default())
}};
($($args:tt)+) => {{
$crate::error!($($args)+);
$crate::LoggedError::default()
Err($crate::LoggedError::default())
}};
}
// Any result or option can be silenced
pub trait SilentResultExt<T> {
pub trait SilentLogExt<T> {
fn silent(self) -> LoggedResult<T>;
}
impl<T, E> SilentResultExt<T> for Result<T, E> {
impl<T, E> SilentLogExt<T> for Result<T, E> {
fn silent(self) -> LoggedResult<T> {
match self {
Ok(v) => Ok(v),
Err(_) => Err(LoggedError::default()),
}
self.map_err(|_| LoggedError::default())
}
}
impl<T> SilentResultExt<T> for Option<T> {
impl<T> SilentLogExt<T> for Option<T> {
fn silent(self) -> LoggedResult<T> {
match self {
Some(v) => Ok(v),
None => Err(LoggedError::default()),
}
self.ok_or_else(LoggedError::default)
}
}
@@ -64,142 +61,170 @@ pub(crate) trait CxxResultExt<T> {
fn log_cxx(self) -> LoggedResult<T>;
}
trait Loggable<T> {
fn do_log(self, level: LogLevel, caller: Option<&'static Location>) -> LoggedResult<T>;
// Public API for converting Option to LoggedResult
pub trait OptionExt<T> {
fn ok_or_log(self) -> LoggedResult<T>;
fn ok_or_log_msg<F: FnOnce(Formatter) -> fmt::Result>(self, f: F) -> LoggedResult<T>;
}
impl<T> OptionExt<T> for Option<T> {
#[inline(always)]
fn ok_or_log(self) -> LoggedResult<T> {
self.ok_or_else(LoggedError::default)
}
#[cfg(not(debug_assertions))]
fn ok_or_log_msg<F: FnOnce(Formatter) -> fmt::Result>(self, f: F) -> LoggedResult<T> {
self.ok_or_else(|| {
do_log_msg(LogLevel::Error, None, f);
LoggedError::default()
})
}
#[track_caller]
#[cfg(debug_assertions)]
fn ok_or_log_msg<F: FnOnce(Formatter) -> fmt::Result>(self, f: F) -> LoggedResult<T> {
let caller = Some(Location::caller());
self.ok_or_else(|| {
do_log_msg(LogLevel::Error, caller, f);
LoggedError::default()
})
}
}
trait Loggable {
fn do_log(self, level: LogLevel, caller: Option<&'static Location>) -> LoggedError;
fn do_log_msg<F: FnOnce(Formatter) -> fmt::Result>(
self,
level: LogLevel,
caller: Option<&'static Location>,
f: F,
) -> LoggedResult<T>;
) -> LoggedError;
}
impl<T, R: Loggable<T>> CxxResultExt<T> for R {
impl<T, E: Loggable> CxxResultExt<T> for Result<T, E> {
fn log_cxx(self) -> LoggedResult<T> {
self.do_log(LogLevel::ErrorCxx, None)
self.map_err(|e| e.do_log(LogLevel::ErrorCxx, None))
}
}
impl<T, R: Loggable<T>> ResultExt<T> for R {
impl<T, E: Loggable> ResultExt<T> for Result<T, E> {
#[cfg(not(debug_assertions))]
fn log(self) -> LoggedResult<T> {
self.do_log(LogLevel::Error, None)
self.map_err(|e| e.do_log(LogLevel::Error, None))
}
#[track_caller]
#[cfg(debug_assertions)]
fn log(self) -> LoggedResult<T> {
self.do_log(LogLevel::Error, Some(Location::caller()))
let caller = Some(Location::caller());
self.map_err(|e| e.do_log(LogLevel::Error, caller))
}
#[cfg(not(debug_assertions))]
fn log_with_msg<F: FnOnce(Formatter) -> fmt::Result>(self, f: F) -> LoggedResult<T> {
self.do_log_msg(LogLevel::Error, None, f)
self.map_err(|e| e.do_log_msg(LogLevel::Error, None, f))
}
#[track_caller]
#[cfg(debug_assertions)]
fn log_with_msg<F: FnOnce(Formatter) -> fmt::Result>(self, f: F) -> LoggedResult<T> {
self.do_log_msg(LogLevel::Error, Some(Location::caller()), f)
let caller = Some(Location::caller());
self.map_err(|e| e.do_log_msg(LogLevel::Error, caller, f))
}
#[cfg(not(debug_assertions))]
fn log_ok(self) {
self.log().ok();
self.map_err(|e| e.do_log(LogLevel::Error, None)).ok();
}
#[track_caller]
#[cfg(debug_assertions)]
fn log_ok(self) {
self.do_log(LogLevel::Error, Some(Location::caller())).ok();
let caller = Some(Location::caller());
self.map_err(|e| e.do_log(LogLevel::Error, caller)).ok();
}
}
impl<T> Loggable<T> for LoggedResult<T> {
fn do_log(self, _: LogLevel, _: Option<&'static Location>) -> LoggedResult<T> {
impl<T> ResultExt<T> for LoggedResult<T> {
fn log(self) -> LoggedResult<T> {
self
}
fn do_log_msg<F: FnOnce(Formatter) -> fmt::Result>(
self,
level: LogLevel,
caller: Option<&'static Location>,
f: F,
) -> LoggedResult<T> {
match self {
Ok(v) => Ok(v),
Err(_) => {
log_with_formatter(level, |w| {
if let Some(caller) = caller {
write!(w, "[{}:{}] ", caller.file(), caller.line())?;
}
f(w)?;
w.write_char('\n')
});
Err(LoggedError::default())
}
}
#[cfg(not(debug_assertions))]
fn log_with_msg<F: FnOnce(Formatter) -> fmt::Result>(self, f: F) -> LoggedResult<T> {
do_log_msg(LogLevel::Error, None, f);
self
}
#[track_caller]
#[cfg(debug_assertions)]
fn log_with_msg<F: FnOnce(Formatter) -> fmt::Result>(self, f: F) -> LoggedResult<T> {
let caller = Some(Location::caller());
do_log_msg(LogLevel::Error, caller, f);
self
}
fn log_ok(self) {}
}
impl<T, E: Display> Loggable<T> for Result<T, E> {
fn do_log(self, level: LogLevel, caller: Option<&'static Location>) -> LoggedResult<T> {
match self {
Ok(v) => Ok(v),
Err(e) => {
if let Some(caller) = caller {
log_with_args!(level, "[{}:{}] {:#}", caller.file(), caller.line(), e);
} else {
log_with_args!(level, "{:#}", e);
}
Err(LoggedError::default())
}
}
}
fn do_log_msg<F: FnOnce(Formatter) -> fmt::Result>(
self,
level: LogLevel,
caller: Option<&'static Location>,
f: F,
) -> LoggedResult<T> {
match self {
Ok(v) => Ok(v),
Err(e) => {
log_with_formatter(level, |w| {
if let Some(caller) = caller {
write!(w, "[{}:{}] ", caller.file(), caller.line())?;
}
f(w)?;
writeln!(w, ": {e:#}")
});
Err(LoggedError::default())
}
}
}
}
// Automatically convert all printable errors to LoggedError to support `?` operator
impl<T: Display> From<T> for LoggedError {
// Allow converting Loggable errors to LoggedError to support `?` operator
impl<T: Loggable> From<T> for LoggedError {
#[cfg(not(debug_assertions))]
fn from(e: T) -> Self {
log_with_args!(LogLevel::Error, "{:#}", e);
LoggedError::default()
e.do_log(LogLevel::Error, None)
}
#[track_caller]
#[cfg(debug_assertions)]
fn from(e: T) -> Self {
let caller = Location::caller();
log_with_args!(
LogLevel::Error,
"[{}:{}] {:#}",
caller.file(),
caller.line(),
e
);
let caller = Some(Location::caller());
e.do_log(LogLevel::Error, caller)
}
}
// Actual logging implementation
// Make all printable objects Loggable
impl<T: Display> Loggable for T {
fn do_log(self, level: LogLevel, caller: Option<&'static Location>) -> LoggedError {
if let Some(caller) = caller {
log_with_args!(level, "[{}:{}] {:#}", caller.file(), caller.line(), self);
} else {
log_with_args!(level, "{:#}", self);
}
LoggedError::default()
}
fn do_log_msg<F: FnOnce(Formatter) -> fmt::Result>(
self,
level: LogLevel,
caller: Option<&'static Location>,
f: F,
) -> LoggedError {
log_with_formatter(level, |w| {
if let Some(caller) = caller {
write!(w, "[{}:{}] ", caller.file(), caller.line())?;
}
f(w)?;
writeln!(w, ": {self:#}")
});
LoggedError::default()
}
}
fn do_log_msg<F: FnOnce(Formatter) -> fmt::Result>(
level: LogLevel,
caller: Option<&'static Location>,
f: F,
) {
log_with_formatter(level, |w| {
if let Some(caller) = caller {
write!(w, "[{}:{}] ", caller.file(), caller.line())?;
}
f(w)?;
w.write_char('\n')
});
}
// Check libc return value and map to Result

View File

@@ -5,8 +5,6 @@
#include <bitset>
#include <cxx.h>
#include "format.hpp"
/******************
* Special Headers
*****************/

View File

@@ -296,156 +296,145 @@ fn sign_cmd(
Ok(())
}
fn boot_main(cmds: CmdArgs) -> LoggedResult<i32> {
let mut cmds = cmds.0;
if cmds.len() < 2 {
print_usage(cmds.first().unwrap_or(&"magiskboot"));
return log_err!();
}
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(|| match cmds.get(1) {
Some(&"dtb") => print_dtb_usage(),
Some(&"cpio") => print_cpio_usage(),
_ => print_usage(cmds[0]),
});
match cli.action {
Action::Unpack(Unpack {
no_decompress,
dump_header,
ref mut img,
}) => {
return Ok(unpack(
Utf8CStr::from_string(img),
no_decompress,
dump_header,
));
}
Action::Repack(Repack {
no_compress,
mut img,
mut out,
}) => {
repack(
Utf8CStr::from_string(&mut img),
Utf8CStr::from_string(&mut out),
no_compress,
);
}
Action::Verify(Verify { mut img, mut cert }) => {
if !verify_cmd(
Utf8CStr::from_string(&mut img),
cert.as_mut().map(Utf8CStr::from_string),
) {
return log_err!();
}
}
Action::Sign(Sign { mut img, mut args }) => {
let mut iter = args.iter_mut();
sign_cmd(
Utf8CStr::from_string(&mut img),
iter.next().map(Utf8CStr::from_string),
iter.next().map(Utf8CStr::from_string),
iter.next().map(Utf8CStr::from_string),
)?;
}
Action::Extract(Extract { payload, args }) => {
if args.len() > 2 {
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 {
mut file,
mut src,
mut dest,
}) => {
if !hexpatch(
&mut file,
Utf8CStr::from_string(&mut src),
Utf8CStr::from_string(&mut dest),
) {
log_err!("Failed to patch")?;
}
}
Action::Cpio(Cpio { mut file, mut cmds }) => {
cpio_commands(Utf8CStr::from_string(&mut file), &mut cmds)
.log_with_msg(|w| w.write_str("Failed to process cpio"))?;
}
Action::Dtb(Dtb { mut file, action }) => {
return dtb_commands(Utf8CStr::from_string(&mut file), &action)
.map(|b| if b { 0 } else { 1 })
.log_with_msg(|w| w.write_str("Failed to process dtb"));
}
Action::Split(Split {
no_decompress,
mut file,
}) => {
return Ok(split_image_dtb(
Utf8CStr::from_string(&mut file),
no_decompress,
));
}
Action::Sha1(Sha1 { mut file }) => {
let file = MappedFile::open(Utf8CStr::from_string(&mut file))?;
let mut sha1 = [0u8; 20];
sha1_hash(file.as_ref(), &mut sha1);
for byte in &sha1 {
print!("{byte:02x}");
}
println!();
}
Action::Cleanup(_) => {
eprintln!("Cleaning up...");
cleanup();
}
Action::Decompress(Decompress { mut file, mut out }) => {
decompress(&mut file, out.as_mut())?;
}
Action::Compress(Compress {
ref mut file,
ref format,
ref mut out,
}) => {
compress(
FileFormat::from_str(format).unwrap_or(FileFormat::UNKNOWN),
file,
out.as_mut(),
)?;
}
}
Ok(0)
}
#[unsafe(no_mangle)]
pub extern "C" fn main(argc: i32, argv: *const *const c_char, _envp: *const *const c_char) -> i32 {
cmdline_logging();
unsafe { umask(0) };
let res: LoggedResult<()> = try {
let mut cmds = CmdArgs::new(argc, argv).0;
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(|| match cmds.get(1) {
Some(&"dtb") => print_dtb_usage(),
Some(&"cpio") => print_cpio_usage(),
_ => print_usage(cmds[0]),
});
match cli.action {
Action::Unpack(Unpack {
no_decompress,
dump_header,
ref mut img,
}) => return unpack(Utf8CStr::from_string(img), no_decompress, dump_header),
Action::Repack(Repack {
no_compress,
ref mut img,
ref mut out,
}) => {
repack(
Utf8CStr::from_string(img),
Utf8CStr::from_string(out),
no_compress,
);
}
Action::Verify(Verify { mut img, mut cert }) => {
return if verify_cmd(
Utf8CStr::from_string(&mut img),
cert.as_mut().map(Utf8CStr::from_string),
) {
0
} else {
1
};
}
Action::Sign(Sign { mut img, mut args }) => {
let mut iter = args.iter_mut();
sign_cmd(
Utf8CStr::from_string(&mut img),
iter.next().map(Utf8CStr::from_string),
iter.next().map(Utf8CStr::from_string),
iter.next().map(Utf8CStr::from_string),
)?;
}
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 mut file,
ref mut cmds,
}) => {
return if cpio_commands(file, cmds)
.log_with_msg(|w| w.write_str("Failed to process cpio"))?
{
0
} else {
1
};
}
Action::Dtb(Dtb {
ref mut file,
ref action,
}) => {
return if dtb_commands(file, action)
.log_with_msg(|w| w.write_str("Failed to process dtb"))?
{
0
} else {
1
};
}
Action::Split(Split {
no_decompress,
ref mut file,
}) => {
return split_image_dtb(Utf8CStr::from_string(file), 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!("{byte:02x}");
}
println!();
}
Action::Cleanup(_) => {
eprintln!("Cleaning up...");
cleanup();
}
Action::Decompress(Decompress {
ref mut file,
ref mut out,
}) => {
decompress(file, out.as_mut())?;
}
Action::Compress(Compress {
ref mut file,
ref format,
ref mut out,
}) => {
compress(
FileFormat::from_str(format).unwrap_or(FileFormat::UNKNOWN),
file,
out.as_mut(),
)?;
}
}
};
if res.is_ok() { 0 } else { 1 }
let cmds = CmdArgs::new(argc, argv);
boot_main(cmds).unwrap_or(1)
}

View File

@@ -10,11 +10,11 @@ use lz4::{
};
use std::cell::Cell;
use std::fs::File;
use std::io::{BufWriter, Read, Stdin, Stdout, Write, stdin, stdout};
use std::io::{BufWriter, Read, Write, stdin, stdout};
use std::mem::ManuallyDrop;
use std::num::NonZeroU64;
use std::ops::DerefMut;
use std::os::fd::{AsRawFd, FromRawFd, RawFd};
use std::os::fd::{AsFd, AsRawFd, FromRawFd, RawFd};
use xz2::{
stream::{Check as LzmaCheck, Filters as LzmaFilters, LzmaOptions, Stream as LzmaStream},
write::{XzDecoder, XzEncoder},
@@ -426,59 +426,46 @@ pub fn decompress_bytes(format: FileFormat, in_bytes: &[u8], out_fd: RawFd) {
};
}
enum AsRawFdFile {
Stdin(Stdin),
Stdout(Stdout),
File(File),
}
impl AsRawFd for AsRawFdFile {
fn as_raw_fd(&self) -> RawFd {
match self {
AsRawFdFile::Stdin(stdin) => stdin.as_raw_fd(),
AsRawFdFile::Stdout(stdout) => stdout.as_raw_fd(),
AsRawFdFile::File(file) => file.as_raw_fd(),
}
}
}
pub(crate) fn decompress(infile: &mut String, outfile: Option<&mut String>) -> LoggedResult<()> {
let in_std = infile == "-";
let mut rm_in = false;
let raw_in = if in_std {
AsRawFdFile::Stdin(stdin())
} else {
AsRawFdFile::File(Utf8CStr::from_string(infile).open(O_RDONLY)?)
};
let mut buf = [0u8; 4096];
let mut in_file = unsafe { File::from_raw_fd(raw_in.as_raw_fd()) };
let _ = in_file.read(&mut buf)?;
let raw_in = if in_std {
super let mut stdin = stdin();
let _ = stdin.read(&mut buf)?;
stdin.as_fd()
} else {
super let mut infile = Utf8CStr::from_string(infile).open(O_RDONLY)?;
let _ = infile.read(&mut buf)?;
infile.as_fd()
};
let format = check_fmt(&buf);
eprintln!("Detected format: {format}");
if !format.is_compressed() {
return Err(log_err!("Input file is not a supported type!"));
return log_err!("Input file is not a supported type!");
}
let raw_out = if let Some(outfile) = outfile {
if outfile == "-" {
AsRawFdFile::Stdout(stdout())
super let stdout = stdout();
stdout.as_fd()
} else {
AsRawFdFile::File(Utf8CStr::from_string(outfile).create(O_WRONLY | O_TRUNC, 0o644)?)
super let outfile = Utf8CStr::from_string(outfile).create(O_WRONLY | O_TRUNC, 0o644)?;
outfile.as_fd()
}
} else if in_std {
AsRawFdFile::Stdout(stdout())
super let stdout = stdout();
stdout.as_fd()
} else {
// strip the extension
rm_in = true;
let mut outfile = if let Some((outfile, ext)) = infile.rsplit_once('.') {
if ext != format.ext() {
Err(log_err!("Input file is not a supported type!"))?;
log_err!("Input file is not a supported type!")?;
}
outfile.to_owned()
} else {
@@ -486,7 +473,8 @@ pub(crate) fn decompress(infile: &mut String, outfile: Option<&mut String>) -> L
};
eprintln!("Decompressing to [{outfile}]");
AsRawFdFile::File(Utf8CStr::from_string(&mut outfile).create(O_WRONLY | O_TRUNC, 0o644)?)
super let outfile = Utf8CStr::from_string(&mut outfile).create(O_WRONLY | O_TRUNC, 0o644)?;
outfile.as_fd()
};
decompress_bytes_fd(format, &buf, raw_in.as_raw_fd(), raw_out.as_raw_fd());
@@ -511,24 +499,30 @@ pub(crate) fn compress(
let mut rm_in = false;
let raw_in = if in_std {
AsRawFdFile::Stdin(stdin())
super let stdin = stdin();
stdin.as_fd()
} else {
AsRawFdFile::File(Utf8CStr::from_string(infile).open(O_RDONLY)?)
super let infile = Utf8CStr::from_string(infile).open(O_RDONLY)?;
infile.as_fd()
};
let raw_out = if let Some(outfile) = outfile {
if outfile == "-" {
AsRawFdFile::Stdout(stdout())
super let stdout = stdout();
stdout.as_fd()
} else {
AsRawFdFile::File(Utf8CStr::from_string(outfile).create(O_WRONLY | O_TRUNC, 0o644)?)
super let outfile = Utf8CStr::from_string(outfile).create(O_WRONLY | O_TRUNC, 0o644)?;
outfile.as_fd()
}
} else if in_std {
AsRawFdFile::Stdout(stdout())
super let stdout = stdout();
stdout.as_fd()
} else {
let mut outfile = format!("{infile}.{}", method.ext());
eprintln!("Compressing to [{outfile}]");
rm_in = true;
AsRawFdFile::File(Utf8CStr::from_string(&mut outfile).create(O_WRONLY | O_TRUNC, 0o644)?)
super let outfile = Utf8CStr::from_string(&mut outfile).create(O_WRONLY | O_TRUNC, 0o644)?;
outfile.as_fd()
};
compress_fd(method, raw_in.as_raw_fd(), raw_out.as_raw_fd());

View File

@@ -20,8 +20,8 @@ use base::libc::{
dev_t, gid_t, major, makedev, minor, mknod, mode_t, uid_t,
};
use base::{
BytesExt, EarlyExitExt, LoggedResult, MappedFile, ResultExt, Utf8CStr, Utf8CStrBuf, WriteExt,
cstr, log_err,
BytesExt, EarlyExitExt, LoggedResult, MappedFile, OptionExt, ResultExt, Utf8CStr, Utf8CStrBuf,
WriteExt, cstr, log_err,
};
use crate::check_env;
@@ -227,7 +227,7 @@ impl Cpio {
let hdr_sz = size_of::<CpioHeader>();
let hdr = from_bytes::<CpioHeader>(&data[pos..(pos + hdr_sz)]);
if &hdr.magic != b"070701" {
return Err(log_err!("invalid cpio magic"));
return log_err!("invalid cpio magic");
}
pos += hdr_sz;
let name_sz = x8u(&hdr.namesize)? as usize;
@@ -331,7 +331,7 @@ impl Cpio {
let entry = self
.entries
.get(path)
.ok_or_else(|| log_err!("No such file"))?;
.ok_or_log_msg(|w| w.write_str("No such file"))?;
eprintln!("Extracting entry [{path}] to [{out}]");
let out = Utf8CStr::from_string(out);
@@ -362,7 +362,7 @@ impl Cpio {
unsafe { mknod(out.as_ptr().cast(), entry.mode, dev) };
}
_ => {
return Err(log_err!("unknown entry type"));
return log_err!("unknown entry type");
}
}
Ok(())
@@ -389,7 +389,7 @@ impl Cpio {
fn add(&mut self, mode: mode_t, path: &str, file: &mut String) -> LoggedResult<()> {
if path.ends_with('/') {
return Err(log_err!("path cannot end with / for add"));
return log_err!("path cannot end with / for add");
}
let file = Utf8CStr::from_string(file);
let attr = file.get_attr()?;
@@ -412,7 +412,7 @@ impl Cpio {
} else if attr.is_char_device() {
mode | S_IFCHR
} else {
return Err(log_err!("unsupported file type"));
return log_err!("unsupported file type");
}
};
@@ -465,7 +465,7 @@ impl Cpio {
let entry = self
.entries
.remove(&norm_path(from))
.ok_or_else(|| log_err!("no such entry {}", from))?;
.ok_or_log_msg(|w| w.write_fmt(format_args!("No such entry {from}")))?;
self.entries.insert(norm_path(to), entry);
eprintln!("Move [{from}] -> [{to}]");
Ok(())
@@ -753,8 +753,7 @@ impl Display for CpioEntry {
}
}
pub(crate) fn cpio_commands(file: &mut String, cmds: &mut Vec<String>) -> LoggedResult<bool> {
let file = Utf8CStr::from_string(file);
pub(crate) fn cpio_commands(file: &Utf8CStr, cmds: &mut Vec<String>) -> LoggedResult<()> {
let mut cpio = if file.exists() {
Cpio::load_from_file(file)?
} else {
@@ -779,7 +778,11 @@ pub(crate) fn cpio_commands(file: &mut String, cmds: &mut Vec<String>) -> Logged
CpioAction::Restore(_) => cpio.restore()?,
CpioAction::Patch(_) => cpio.patch(),
CpioAction::Exists(Exists { path }) => {
return Ok(cpio.exists(path));
return if cpio.exists(path) {
Ok(())
} else {
log_err!()
};
}
CpioAction::Backup(Backup {
origin,
@@ -792,19 +795,19 @@ pub(crate) fn cpio_commands(file: &mut String, cmds: &mut Vec<String>) -> Logged
CpioAction::Add(Add { mode, path, file }) => cpio.add(*mode, path, file)?,
CpioAction::Extract(Extract { paths }) => {
if !paths.is_empty() && paths.len() != 2 {
Err(log_err!("invalid arguments"))?;
log_err!("invalid arguments")?;
}
let mut it = paths.iter_mut();
cpio.extract(it.next(), it.next())?;
}
CpioAction::List(List { path, recursive }) => {
cpio.ls(path.as_str(), *recursive);
return Ok(true);
return Ok(());
}
};
}
cpio.dump(file)?;
Ok(true)
Ok(())
}
fn x8u(x: &[u8; 8]) -> LoggedResult<u32> {
@@ -812,7 +815,9 @@ fn x8u(x: &[u8; 8]) -> LoggedResult<u32> {
let mut ret = 0u32;
let s = str::from_utf8(x).log_with_msg(|w| w.write_str("bad cpio header"))?;
for c in s.chars() {
ret = ret * 16 + c.to_digit(16).ok_or_else(|| log_err!("bad cpio header"))?;
ret = ret * 16
+ c.to_digit(16)
.ok_or_log_msg(|w| w.write_str("bad cpio header"))?;
}
Ok(ret)
}

View File

@@ -264,8 +264,7 @@ fn dtb_patch(file: &Utf8CStr) -> LoggedResult<bool> {
Ok(patched)
}
pub(crate) fn dtb_commands(file: &mut String, action: &DtbAction) -> LoggedResult<bool> {
let file = Utf8CStr::from_string(file);
pub(crate) fn dtb_commands(file: &Utf8CStr, action: &DtbAction) -> LoggedResult<bool> {
match action {
DtbAction::Print(Print { fstab }) => {
dtb_print(file, *fstab)?;

View File

@@ -1,44 +0,0 @@
#pragma once
enum class FileFormat : ::std::uint8_t;
#define BUFFER_MATCH(buf, s) (memcmp(buf, s, sizeof(s) - 1) == 0)
#define BUFFER_CONTAIN(buf, sz, s) (memmem(buf, sz, s, sizeof(s) - 1) != nullptr)
#define CHECKED_MATCH(s) (len >= (sizeof(s) - 1) && BUFFER_MATCH(buf, s))
#define BOOT_MAGIC "ANDROID!"
#define VENDOR_BOOT_MAGIC "VNDRBOOT"
#define CHROMEOS_MAGIC "CHROMEOS"
#define GZIP1_MAGIC "\x1f\x8b"
#define GZIP2_MAGIC "\x1f\x9e"
#define LZOP_MAGIC "\x89""LZO"
#define XZ_MAGIC "\xfd""7zXZ"
#define BZIP_MAGIC "BZh"
#define LZ4_LEG_MAGIC "\x02\x21\x4c\x18"
#define LZ41_MAGIC "\x03\x21\x4c\x18"
#define LZ42_MAGIC "\x04\x22\x4d\x18"
#define MTK_MAGIC "\x88\x16\x88\x58"
#define DTB_MAGIC "\xd0\x0d\xfe\xed"
#define LG_BUMP_MAGIC "\x41\xa9\xe4\x67\x74\x4d\x1d\x1b\xa4\x29\xf2\xec\xea\x65\x52\x79"
#define DHTB_MAGIC "\x44\x48\x54\x42\x01\x00\x00\x00"
#define SEANDROID_MAGIC "SEANDROIDENFORCE"
#define TEGRABLOB_MAGIC "-SIGNED-BY-SIGNBLOB-"
#define NOOKHD_RL_MAGIC "Red Loader"
#define NOOKHD_GL_MAGIC "Green Loader"
#define NOOKHD_GR_MAGIC "Green Recovery"
#define NOOKHD_EB_MAGIC "eMMC boot.img+secondloader"
#define NOOKHD_ER_MAGIC "eMMC recovery.img+secondloader"
#define NOOKHD_PRE_HEADER_SZ 1048576
#define ACCLAIM_MAGIC "BauwksBoot"
#define ACCLAIM_PRE_HEADER_SZ 262144
#define AMONET_MICROLOADER_MAGIC "microloader"
#define AMONET_MICROLOADER_SZ 1024
#define AVB_FOOTER_MAGIC "AVBf"
#define AVB_MAGIC "AVB0"
#define ZIMAGE_MAGIC "\x18\x28\x6f\x01"
FileFormat check_fmt(const void *buf, size_t len);
static inline FileFormat check_fmt(rust::Slice<const uint8_t> bytes) {
return check_fmt(bytes.data(), bytes.size());
}

View File

@@ -2,6 +2,7 @@
#![feature(btree_extract_if)]
#![feature(iter_intersperse)]
#![feature(try_blocks)]
#![feature(super_let)]
pub use base;
use compress::{compress_bytes, decompress_bytes};
@@ -57,14 +58,12 @@ pub mod ffi {
}
unsafe extern "C++" {
include!("format.hpp");
fn check_fmt(buf: &[u8]) -> FileFormat;
include!("magiskboot.hpp");
fn cleanup();
fn unpack(image: Utf8CStrRef, skip_decomp: bool, hdr: bool) -> i32;
fn repack(src_img: Utf8CStrRef, out_img: Utf8CStrRef, skip_comp: bool);
fn split_image_dtb(filename: Utf8CStrRef, skip_decomp: bool) -> i32;
fn check_fmt(buf: &[u8]) -> FileFormat;
}
extern "Rust" {

View File

@@ -12,7 +12,49 @@
#define BOOTCONFIG_FILE "bootconfig"
#define NEW_BOOT "new-boot.img"
#define BUFFER_MATCH(buf, s) (memcmp(buf, s, sizeof(s) - 1) == 0)
#define BUFFER_CONTAIN(buf, sz, s) (memmem(buf, sz, s, sizeof(s) - 1) != nullptr)
#define CHECKED_MATCH(s) (len >= (sizeof(s) - 1) && BUFFER_MATCH(buf, s))
#define BOOT_MAGIC "ANDROID!"
#define VENDOR_BOOT_MAGIC "VNDRBOOT"
#define CHROMEOS_MAGIC "CHROMEOS"
#define GZIP1_MAGIC "\x1f\x8b"
#define GZIP2_MAGIC "\x1f\x9e"
#define LZOP_MAGIC "\x89""LZO"
#define XZ_MAGIC "\xfd""7zXZ"
#define BZIP_MAGIC "BZh"
#define LZ4_LEG_MAGIC "\x02\x21\x4c\x18"
#define LZ41_MAGIC "\x03\x21\x4c\x18"
#define LZ42_MAGIC "\x04\x22\x4d\x18"
#define MTK_MAGIC "\x88\x16\x88\x58"
#define DTB_MAGIC "\xd0\x0d\xfe\xed"
#define LG_BUMP_MAGIC "\x41\xa9\xe4\x67\x74\x4d\x1d\x1b\xa4\x29\xf2\xec\xea\x65\x52\x79"
#define DHTB_MAGIC "\x44\x48\x54\x42\x01\x00\x00\x00"
#define SEANDROID_MAGIC "SEANDROIDENFORCE"
#define TEGRABLOB_MAGIC "-SIGNED-BY-SIGNBLOB-"
#define NOOKHD_RL_MAGIC "Red Loader"
#define NOOKHD_GL_MAGIC "Green Loader"
#define NOOKHD_GR_MAGIC "Green Recovery"
#define NOOKHD_EB_MAGIC "eMMC boot.img+secondloader"
#define NOOKHD_ER_MAGIC "eMMC recovery.img+secondloader"
#define NOOKHD_PRE_HEADER_SZ 1048576
#define ACCLAIM_MAGIC "BauwksBoot"
#define ACCLAIM_PRE_HEADER_SZ 262144
#define AMONET_MICROLOADER_MAGIC "microloader"
#define AMONET_MICROLOADER_SZ 1024
#define AVB_FOOTER_MAGIC "AVBf"
#define AVB_MAGIC "AVB0"
#define ZIMAGE_MAGIC "\x18\x28\x6f\x01"
enum class FileFormat : ::std::uint8_t;
int unpack(rust::Utf8CStr image, bool skip_decomp = false, bool hdr = false);
void repack(rust::Utf8CStr src_img, rust::Utf8CStr out_img, bool skip_comp = false);
int split_image_dtb(rust::Utf8CStr filename, bool skip_decomp = false);
void cleanup();
FileFormat check_fmt(const void *buf, size_t len);
static inline FileFormat check_fmt(rust::Slice<const uint8_t> bytes) {
return check_fmt(bytes.data(), bytes.size());
}

View File

@@ -25,7 +25,7 @@ use x509_cert::der::Any;
use x509_cert::der::asn1::{OctetString, PrintableString};
use x509_cert::spki::AlgorithmIdentifier;
use base::{LoggedError, LoggedResult, MappedFile, ResultExt, Utf8CStr, cstr, log_err};
use base::{LoggedResult, MappedFile, ResultExt, Utf8CStr, cstr, log_err};
use crate::ffi::BootImage;
@@ -116,7 +116,7 @@ impl Verifier {
digest = Box::<Sha512>::default();
VerifyingKey::SHA521withECDSA(ec)
} else {
return Err(log_err!("Unsupported private key"));
return log_err!("Unsupported private key");
};
Ok(Verifier { digest, key })
}
@@ -177,7 +177,7 @@ impl Signer {
SigningKey::SHA521withECDSA(ec)
}
_ => {
return Err(log_err!("Unsupported private key"));
return log_err!("Unsupported private key");
}
},
},
@@ -248,7 +248,7 @@ struct BootSignature {
impl BootSignature {
fn verify(self, payload: &[u8]) -> LoggedResult<()> {
if self.authenticated_attributes.length as usize != payload.len() {
return Err(log_err!("Invalid image size"));
return log_err!("Invalid image size");
}
let mut verifier = Verifier::from_public_key(
self.certificate
@@ -268,7 +268,7 @@ impl BootImage {
pub fn verify(&self, cert: Option<&Utf8CStr>) -> LoggedResult<()> {
let tail = self.tail();
if tail.starts_with(b"AVB0") {
return Err(LoggedError::default());
return log_err!();
}
// Don't use BootSignature::from_der because tail might have trailing zeros

View File

@@ -307,7 +307,7 @@ pub fn daemon_entry() {
// Remove all pre-init overlay files to free-up memory
tmp_path.append_path(ROOTOVL);
tmp_path.remove_all().log_ok();
tmp_path.remove_all().ok();
tmp_path.truncate(magisk_tmp.len());
let magiskd = MagiskD {

View File

@@ -4,8 +4,8 @@ use crate::ffi::{ModuleInfo, exec_module_scripts, exec_script, get_magisk_tmp, l
use crate::mount::setup_module_mount;
use base::{
DirEntry, Directory, FsPathBuilder, LibcReturn, LoggedResult, OsResultStatic, ResultExt,
Utf8CStr, Utf8CStrBuf, Utf8CString, WalkResult, clone_attr, cstr, debug, error, info, libc,
raw_cstr, warn,
SilentLogExt, Utf8CStr, Utf8CStrBuf, Utf8CString, WalkResult, clone_attr, cstr, debug, error,
info, libc, raw_cstr, warn,
};
use libc::{AT_REMOVEDIR, MS_RDONLY, O_CLOEXEC, O_CREAT, O_RDONLY};
use std::collections::BTreeMap;
@@ -556,7 +556,7 @@ fn inject_zygisk_bins(name: &str, system: &mut FsNode) {
}
fn upgrade_modules() -> LoggedResult<()> {
let mut upgrade = Directory::open(cstr!(MODULEUPGRADE))?;
let mut upgrade = Directory::open(cstr!(MODULEUPGRADE)).silent()?;
let ufd = upgrade.as_raw_fd();
let root = Directory::open(cstr!(MODULEROOT))?;
while let Some(e) = upgrade.read()? {

View File

@@ -16,7 +16,7 @@ use crate::resetprop::proto::persistent_properties::{
use base::const_format::concatcp;
use base::libc::{O_CLOEXEC, O_RDONLY};
use base::{
Directory, FsPathBuilder, LibcReturn, LoggedResult, MappedFile, SilentResultExt, Utf8CStr,
Directory, FsPathBuilder, LibcReturn, LoggedResult, MappedFile, SilentLogExt, Utf8CStr,
Utf8CStrBuf, WalkResult, clone_attr, cstr, debug, libc::mkstemp,
};

View File

@@ -6,8 +6,8 @@ use crate::ffi::{
use crate::socket::{IpcRead, UnixSocketExt};
use base::libc::{O_CLOEXEC, O_CREAT, O_RDONLY, STDOUT_FILENO};
use base::{
Directory, FsPathBuilder, LoggedError, LoggedResult, ResultExt, Utf8CStr, WriteExt, cstr,
fork_dont_care, libc, raw_cstr, warn,
Directory, FsPathBuilder, LoggedResult, ResultExt, Utf8CStr, WriteExt, cstr, fork_dont_care,
libc, log_err, raw_cstr, warn,
};
use std::fmt::Write;
use std::os::fd::{AsRawFd, FromRawFd, RawFd};
@@ -101,7 +101,7 @@ impl ZygiskState {
local.send_fds(&module_fds)?;
}
if local.read_decodable::<i32>()? != 0 {
Err(LoggedError::default())?;
return log_err!();
}
local
};

View File

@@ -1,5 +1,5 @@
use base::{
LOGGER, LogLevel, Logger, SilentResultExt, Utf8CStr, cstr,
LOGGER, LogLevel, Logger, SilentLogExt, Utf8CStr, cstr,
libc::{
O_CLOEXEC, O_RDWR, O_WRONLY, S_IFCHR, STDERR_FILENO, STDIN_FILENO, STDOUT_FILENO, SYS_dup3,
makedev, mknod, syscall,

View File

@@ -92,10 +92,10 @@ pub unsafe extern "C" fn main(
(None, true, false) => SePolicy::from_split(),
(None, false, true) => SePolicy::compile_split(),
(None, false, false) => SePolicy::from_file(cstr!("/sys/fs/selinux/policy")),
_ => Err(log_err!("Multiple load source supplied"))?,
_ => log_err!("Multiple load source supplied")?,
};
if sepol._impl.is_null() {
Err(log_err!("Cannot load policy"))?;
log_err!("Cannot load policy")?;
}
if cli.print_rules {
@@ -105,7 +105,7 @@ pub unsafe extern "C" fn main(
|| cli.live
|| cli.save.is_some()
{
Err(log_err!("Cannot print rules with other options"))?;
log_err!("Cannot print rules with other options")?;
}
sepol.print_rules();
return 0;
@@ -124,12 +124,12 @@ pub unsafe extern "C" fn main(
}
if cli.live && !sepol.to_file(cstr!("/sys/fs/selinux/load")) {
Err(log_err!("Cannot apply policy"))?;
log_err!("Cannot apply policy")?;
}
if let Some(file) = &mut cli.save {
if !sepol.to_file(Utf8CStr::from_string(file)) {
Err(log_err!("Cannot dump policy to {}", file))?;
log_err!("Cannot dump policy to {}", file)?;
}
}
};