Introduce CmdArgs for argument parsing in Rust

This commit is contained in:
topjohnwu
2025-08-15 17:44:30 -07:00
committed by John Wu
parent db8d832707
commit af51880a81
4 changed files with 57 additions and 23 deletions

View File

@@ -300,6 +300,13 @@ impl Utf8CStr {
}
}
pub unsafe fn from_raw_parts<'a>(ptr: *const c_char, len: usize) -> &'a Utf8CStr {
unsafe {
let bytes = slice::from_raw_parts(ptr.cast(), len);
Self::from_bytes_unchecked(bytes)
}
}
#[inline(always)]
pub fn as_bytes_with_nul(&self) -> &[u8] {
&self.0

View File

@@ -1,13 +1,16 @@
use crate::{StrErr, Utf8CStr, ffi};
use crate::{Utf8CStr, cstr, ffi};
use argh::EarlyExit;
use libc::c_char;
use std::fmt::Arguments;
use std::io::Write;
use std::mem::ManuallyDrop;
use std::process::exit;
use std::sync::Arc;
use std::sync::atomic::{AtomicPtr, Ordering};
use std::{fmt, slice, str};
use std::{
fmt,
fmt::Arguments,
io::Write,
mem::ManuallyDrop,
process::exit,
slice, str,
sync::Arc,
sync::atomic::{AtomicPtr, Ordering},
};
pub fn errno() -> &'static mut i32 {
unsafe { &mut *libc::__errno() }
@@ -76,15 +79,6 @@ impl<T: AsMut<[u8]> + ?Sized> MutBytesExt for T {
}
}
// SAFETY: libc guarantees argc and argv are properly setup and are static
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub fn map_args(argc: i32, argv: *const *const c_char) -> Result<Vec<&'static str>, StrErr> {
unsafe { slice::from_raw_parts(argv, argc as usize) }
.iter()
.map(|s| unsafe { Utf8CStr::from_ptr(*s) }.map(|s| s.as_str()))
.collect()
}
pub trait EarlyExitExt<T> {
fn on_early_exit<F: FnOnce()>(self, print_help_msg: F) -> T;
}
@@ -227,3 +221,35 @@ impl Chunker {
chunk
}
}
pub struct CmdArgs(pub Vec<&'static str>);
impl CmdArgs {
#[allow(clippy::not_unsafe_ptr_arg_deref)]
pub fn new(argc: i32, argv: *const *const c_char) -> CmdArgs {
CmdArgs(
// SAFETY: libc guarantees argc and argv are properly setup and are static
unsafe { slice::from_raw_parts(argv, argc as usize) }
.iter()
.map(|s| unsafe { Utf8CStr::from_ptr(*s) })
.map(|r| r.unwrap_or(cstr!("<invalid>")))
.map(Utf8CStr::as_str)
.collect(),
)
}
pub fn as_slice(&self) -> &[&'static str] {
self.0.as_slice()
}
pub fn iter(&self) -> slice::Iter<'_, &'static str> {
self.0.iter()
}
pub fn cstr_iter(&self) -> impl Iterator<Item = &'static Utf8CStr> {
// SAFETY: libc guarantees null terminated strings
self.0
.iter()
.map(|s| unsafe { Utf8CStr::from_raw_parts(s.as_ptr().cast(), s.len() + 1) })
}
}

View File

@@ -7,8 +7,8 @@ use crate::payload::extract_boot_from_payload;
use crate::sign::sha1_hash;
use argh::FromArgs;
use base::{
EarlyExitExt, LoggedResult, MappedFile, ResultExt, Utf8CStr, cmdline_logging, cstr,
libc::umask, log_err, map_args,
CmdArgs, EarlyExitExt, LoggedResult, MappedFile, ResultExt, Utf8CStr, cmdline_logging, cstr,
libc::umask, log_err,
};
use std::ffi::c_char;
use std::str::FromStr;
@@ -264,7 +264,7 @@ pub extern "C" fn main(argc: i32, argv: *const *const c_char, _envp: *const *con
cmdline_logging();
unsafe { umask(0) };
let res: LoggedResult<()> = try {
let mut cmds = map_args(argc, argv)?;
let mut cmds = CmdArgs::new(argc, argv).0;
if argc < 2 {
print_usage(cmds.first().unwrap_or(&"magiskboot"));
return 1;

View File

@@ -2,8 +2,8 @@ use crate::ffi::SePolicy;
use crate::statement::format_statement_help;
use argh::FromArgs;
use base::{
EarlyExitExt, FmtAdaptor, LoggedResult, Utf8CStr, cmdline_logging, cstr, libc::umask, log_err,
map_args,
CmdArgs, EarlyExitExt, FmtAdaptor, LoggedResult, Utf8CStr, cmdline_logging, cstr, libc::umask,
log_err,
};
use std::ffi::c_char;
use std::io::stderr;
@@ -79,7 +79,8 @@ pub unsafe extern "C" fn main(
}
let res: LoggedResult<()> = try {
let cmds = map_args(argc, argv)?;
let cmds = CmdArgs::new(argc, argv);
let cmds = cmds.as_slice();
if argc < 2 {
print_usage(cmds.first().unwrap_or(&"magiskpolicy"));
return 1;