chore(ksud): enable clippy::all, clippy::pedantic && make clippy happy (#617)
* Revert "chore(ksud): bump ksud's deps (#585)"
* Because it may cause compilation errors.
This reverts commit c8020b2066.
* chore(ksud): remove unused Result
Signed-off-by: Tools-app <localhost.hutao@gmail.com>
* chore(ksud): enable clippy::all, clippy::pedantic && make clippy happy
https://rust-lang.github.io/rust-clippy/master/index.html#map_unwrap_or
https://rust-lang.github.io/rust-clippy/master/index.html#uninlined_format_args
https://rust-lang.github.io/rust-clippy/master/index.html#used_underscore_items
https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure_for_method_calls
https://rust-lang.github.io/rust-clippy/master/index.html#redundant_pub_crate
...
and use some #![allow(...)] or #[allow(...)]
Signed-off-by: Tools-app <localhost.hutao@gmail.com>
---------
Signed-off-by: Tools-app <localhost.hutao@gmail.com>
This commit is contained in:
872
userspace/ksud/Cargo.lock
generated
872
userspace/ksud/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -6,11 +6,11 @@ edition = "2024"
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
notify = "8.2"
|
||||
notify = "6.1"
|
||||
anyhow = "1"
|
||||
clap = { version = "4", features = ["derive"] }
|
||||
const_format = "0.2"
|
||||
zip = { version = "6", features = [
|
||||
zip = { version = "3", features = [
|
||||
"deflate",
|
||||
"deflate64",
|
||||
"time",
|
||||
@@ -38,7 +38,7 @@ rust-embed = { version = "8", features = [
|
||||
"debug-embed",
|
||||
"compression", # must clean build after updating binaries
|
||||
] }
|
||||
which = "8"
|
||||
which = "7"
|
||||
getopts = "0.2"
|
||||
sha256 = "1"
|
||||
sha1 = "0.10"
|
||||
@@ -48,14 +48,14 @@ regex-lite = "0.1"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
|
||||
[target.'cfg(any(target_os = "android", target_os = "linux"))'.dependencies]
|
||||
rustix = { git = "https://github.com/Kernel-SU/rustix.git", rev = "4a53fbc7cb7a07cabe87125cc21dbc27db316259", features = [
|
||||
rustix = { git = "https://github.com/Kernel-SU/rustix.git", branch = "main", features = [
|
||||
"all-apis",
|
||||
] }
|
||||
# some android specific dependencies which compiles under unix are also listed here for convenience of coding
|
||||
android-properties = { version = "0.2", features = ["bionic-deprecated"] }
|
||||
|
||||
[target.'cfg(target_os = "android")'.dependencies]
|
||||
android_logger = { version = "0.15", default-features = false }
|
||||
android_logger = { version = "0.14", default-features = false }
|
||||
|
||||
[profile.release]
|
||||
overflow-checks = false
|
||||
|
||||
@@ -84,7 +84,7 @@ pub fn get_apk_signature(apk: &str) -> Result<(u32, String)> {
|
||||
return Err(anyhow::anyhow!("Unexpected v3 signature found!",));
|
||||
}
|
||||
|
||||
v2_signing.ok_or(anyhow::anyhow!("No signature found!"))
|
||||
v2_signing.ok_or_else(|| anyhow::anyhow!("No signature found!"))
|
||||
}
|
||||
|
||||
fn calc_cert_sha256(
|
||||
|
||||
@@ -31,19 +31,19 @@ pub fn ensure_binaries(ignore_if_exist: bool) -> Result<()> {
|
||||
// don't extract ksuinit and kernel modules
|
||||
continue;
|
||||
}
|
||||
let asset = Asset::get(&file).ok_or(anyhow::anyhow!("asset not found: {}", file))?;
|
||||
utils::ensure_binary(format!("{BINARY_DIR}{file}"), &asset.data, ignore_if_exist)?
|
||||
let asset = Asset::get(&file).ok_or_else(|| anyhow::anyhow!("asset not found: {file}"))?;
|
||||
utils::ensure_binary(format!("{BINARY_DIR}{file}"), &asset.data, ignore_if_exist)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn copy_assets_to_file(name: &str, dst: impl AsRef<Path>) -> Result<()> {
|
||||
let asset = Asset::get(name).ok_or(anyhow::anyhow!("asset not found: {}", name))?;
|
||||
let asset = Asset::get(name).ok_or_else(|| anyhow::anyhow!("asset not found: {name}"))?;
|
||||
std::fs::write(dst, asset.data)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn list_supported_kmi() -> Result<Vec<String>> {
|
||||
pub fn list_supported_kmi() -> std::vec::Vec<std::string::String> {
|
||||
let mut list = Vec::new();
|
||||
for file in Asset::iter() {
|
||||
// kmi_name = "xxx_kernelsu.ko"
|
||||
@@ -51,5 +51,5 @@ pub fn list_supported_kmi() -> Result<Vec<String>> {
|
||||
list.push(kmi.to_string());
|
||||
}
|
||||
}
|
||||
Ok(list)
|
||||
list
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#![allow(clippy::ref_option, clippy::needless_pass_by_value)]
|
||||
#[cfg(unix)]
|
||||
use std::{
|
||||
os::unix::fs::PermissionsExt,
|
||||
@@ -217,7 +218,7 @@ pub fn restore(
|
||||
let workdir = tmpdir.path();
|
||||
let magiskboot = find_magiskboot(magiskboot_path, workdir)?;
|
||||
|
||||
let kmi = get_current_kmi().unwrap_or_else(|_| String::from(""));
|
||||
let kmi = get_current_kmi().unwrap_or_default();
|
||||
|
||||
let (bootimage, bootdevice) = find_boot_image(&image, &kmi, false, false, workdir, &None)?;
|
||||
|
||||
@@ -233,7 +234,7 @@ pub fn restore(
|
||||
|
||||
let mut ramdisk = workdir.join("ramdisk.cpio");
|
||||
if !ramdisk.exists() {
|
||||
ramdisk = workdir.join("vendor_ramdisk").join("init_boot.cpio")
|
||||
ramdisk = workdir.join("vendor_ramdisk").join("init_boot.cpio");
|
||||
}
|
||||
if !ramdisk.exists() {
|
||||
ramdisk = workdir.join("vendor_ramdisk").join("ramdisk.cpio");
|
||||
@@ -272,7 +273,7 @@ pub fn restore(
|
||||
new_boot = Some(backup_path);
|
||||
from_backup = true;
|
||||
} else {
|
||||
println!("- Warning: no backup {backup_path:?} found!");
|
||||
println!("- Warning: no backup {} found!", backup_path.display());
|
||||
}
|
||||
|
||||
if let Err(e) = clean_backup(sha) {
|
||||
@@ -355,7 +356,7 @@ pub fn patch(
|
||||
result
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
#[allow(clippy::too_many_arguments, clippy::needless_pass_by_value)]
|
||||
fn do_patch(
|
||||
image: Option<PathBuf>,
|
||||
kernel: Option<PathBuf>,
|
||||
@@ -415,7 +416,7 @@ fn do_patch(
|
||||
);
|
||||
parse_kmi_from_kernel(kernel_path, tmpdir.path())?
|
||||
} else {
|
||||
"".to_string()
|
||||
String::new()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -444,7 +445,7 @@ fn do_patch(
|
||||
let name = format!("{kmi}_kernelsu.ko");
|
||||
assets::copy_assets_to_file(&name, kmod_file)
|
||||
.with_context(|| format!("Failed to copy {name}"))?;
|
||||
};
|
||||
}
|
||||
|
||||
let init_file = workdir.join("init");
|
||||
if let Some(init) = init {
|
||||
@@ -465,7 +466,7 @@ fn do_patch(
|
||||
|
||||
let mut ramdisk = workdir.join("ramdisk.cpio");
|
||||
if !ramdisk.exists() {
|
||||
ramdisk = workdir.join("vendor_ramdisk").join("init_boot.cpio")
|
||||
ramdisk = workdir.join("vendor_ramdisk").join("init_boot.cpio");
|
||||
}
|
||||
if !ramdisk.exists() {
|
||||
ramdisk = workdir.join("vendor_ramdisk").join("ramdisk.cpio");
|
||||
@@ -481,15 +482,16 @@ fn do_patch(
|
||||
println!("- Adding KernelSU LKM");
|
||||
let is_kernelsu_patched = is_kernelsu_patched(&magiskboot, workdir, ramdisk)?;
|
||||
|
||||
let mut need_backup = false;
|
||||
if !is_kernelsu_patched {
|
||||
let need_backup = if is_kernelsu_patched {
|
||||
false
|
||||
} else {
|
||||
// kernelsu.ko is not exist, backup init if necessary
|
||||
let status = do_cpio_cmd(&magiskboot, workdir, ramdisk, "exists init");
|
||||
if status.is_ok() {
|
||||
do_cpio_cmd(&magiskboot, workdir, ramdisk, "mv init init.real")?;
|
||||
}
|
||||
need_backup = flash;
|
||||
}
|
||||
flash
|
||||
};
|
||||
|
||||
do_cpio_cmd(&magiskboot, workdir, ramdisk, "add 0755 init init")?;
|
||||
do_cpio_cmd(
|
||||
@@ -678,7 +680,7 @@ fn find_boot_image(
|
||||
|
||||
bootimage = tmp_boot_path;
|
||||
bootdevice = Some(boot_partition);
|
||||
};
|
||||
}
|
||||
Ok((bootimage, bootdevice))
|
||||
}
|
||||
|
||||
@@ -719,12 +721,12 @@ pub fn choose_boot_partition(
|
||||
|
||||
#[cfg(target_os = "android")]
|
||||
pub fn get_slot_suffix(ota: bool) -> String {
|
||||
let mut slot_suffix = utils::getprop("ro.boot.slot_suffix").unwrap_or_else(|| String::from(""));
|
||||
let mut slot_suffix = utils::getprop("ro.boot.slot_suffix").unwrap_or_default();
|
||||
if !slot_suffix.is_empty() && ota {
|
||||
if slot_suffix == "_a" {
|
||||
slot_suffix = "_b".to_string()
|
||||
slot_suffix = "_b".to_string();
|
||||
} else {
|
||||
slot_suffix = "_a".to_string()
|
||||
slot_suffix = "_a".to_string();
|
||||
}
|
||||
}
|
||||
slot_suffix
|
||||
@@ -741,8 +743,8 @@ pub fn list_available_partitions() -> Vec<String> {
|
||||
let candidates = vec!["boot", "init_boot", "vendor_boot"];
|
||||
candidates
|
||||
.into_iter()
|
||||
.filter(|name| Path::new(&format!("/dev/block/by-name/{}{}", name, slot_suffix)).exists())
|
||||
.map(|s| s.to_string())
|
||||
.filter(|name| Path::new(&format!("/dev/block/by-name/{name}{slot_suffix}")).exists())
|
||||
.map(std::string::ToString::to_string)
|
||||
.collect()
|
||||
}
|
||||
|
||||
@@ -765,7 +767,7 @@ fn post_ota() -> Result<()> {
|
||||
.stdout;
|
||||
let current_slot = String::from_utf8(current_slot)?;
|
||||
let current_slot = current_slot.trim();
|
||||
let target_slot = if current_slot == "0" { 1 } else { 0 };
|
||||
let target_slot = i32::from(current_slot == "0");
|
||||
|
||||
Command::new(BOOTCTL_PATH)
|
||||
.arg(format!("set-active-boot-slot {target_slot}"))
|
||||
@@ -776,11 +778,11 @@ fn post_ota() -> Result<()> {
|
||||
let post_ota_sh = post_fs_data.join("post_ota.sh");
|
||||
|
||||
let sh_content = format!(
|
||||
r###"
|
||||
r"
|
||||
{BOOTCTL_PATH} mark-boot-successful
|
||||
rm -f {BOOTCTL_PATH}
|
||||
rm -f /data/adb/post-fs-data.d/post_ota.sh
|
||||
"###
|
||||
"
|
||||
);
|
||||
|
||||
std::fs::write(&post_ota_sh, sh_content)?;
|
||||
|
||||
@@ -7,7 +7,7 @@ use android_logger::Config;
|
||||
#[cfg(target_os = "android")]
|
||||
use log::LevelFilter;
|
||||
|
||||
use crate::{apk_sign, assets, debug, defs, init_event, ksucalls, module, utils};
|
||||
use crate::{apk_sign, assets, debug, defs, init_event, ksucalls, module, module_config, utils};
|
||||
|
||||
/// KernelSU userspace cli
|
||||
#[derive(Parser, Debug)]
|
||||
@@ -540,7 +540,10 @@ pub fn run() -> Result<()> {
|
||||
|
||||
let result = match cli.command {
|
||||
Commands::PostFsData => init_event::on_post_data_fs(),
|
||||
Commands::BootCompleted => init_event::on_boot_completed(),
|
||||
Commands::BootCompleted => {
|
||||
init_event::on_boot_completed();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Commands::Module { command } => {
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
@@ -561,17 +564,16 @@ pub fn run() -> Result<()> {
|
||||
anyhow::anyhow!("This command must be run in the context of a module")
|
||||
})?;
|
||||
|
||||
use crate::module_config;
|
||||
match command {
|
||||
ModuleConfigCmd::Get { key } => {
|
||||
// Use merge_configs to respect priority (temp overrides persist)
|
||||
let config = module_config::merge_configs(&module_id)?;
|
||||
match config.get(&key) {
|
||||
Some(value) => {
|
||||
println!("{}", value);
|
||||
println!("{value}");
|
||||
Ok(())
|
||||
}
|
||||
None => anyhow::bail!("Key '{}' not found", key),
|
||||
None => anyhow::bail!("Key '{key}' not found"),
|
||||
}
|
||||
}
|
||||
ModuleConfigCmd::Set { key, value, temp } => {
|
||||
@@ -592,7 +594,7 @@ pub fn run() -> Result<()> {
|
||||
println!("No config entries found");
|
||||
} else {
|
||||
for (key, value) in config {
|
||||
println!("{}={}", key, value);
|
||||
println!("{key}={value}");
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
@@ -624,7 +626,10 @@ pub fn run() -> Result<()> {
|
||||
Sepolicy::Apply { file } => crate::sepolicy::apply_file(file),
|
||||
Sepolicy::Check { sepolicy } => crate::sepolicy::check_rule(&sepolicy),
|
||||
},
|
||||
Commands::Services => init_event::on_services(),
|
||||
Commands::Services => {
|
||||
init_event::on_services();
|
||||
Ok(())
|
||||
}
|
||||
Commands::Profile { command } => match command {
|
||||
Profile::GetSepolicy { package } => crate::profile::get_sepolicy(package),
|
||||
Profile::SetSepolicy { package, policy } => {
|
||||
@@ -637,10 +642,13 @@ pub fn run() -> Result<()> {
|
||||
},
|
||||
|
||||
Commands::Feature { command } => match command {
|
||||
Feature::Get { id } => crate::feature::get_feature(id),
|
||||
Feature::Set { id, value } => crate::feature::set_feature(id, value),
|
||||
Feature::List => crate::feature::list_features(),
|
||||
Feature::Check { id } => crate::feature::check_feature(id),
|
||||
Feature::Get { id } => crate::feature::get_feature(&id),
|
||||
Feature::Set { id, value } => crate::feature::set_feature(&id, value),
|
||||
Feature::List => {
|
||||
crate::feature::list_features();
|
||||
Ok(())
|
||||
}
|
||||
Feature::Check { id } => crate::feature::check_feature(&id),
|
||||
Feature::Load => crate::feature::load_config_and_apply(),
|
||||
Feature::Save => crate::feature::save_config(),
|
||||
},
|
||||
@@ -689,8 +697,10 @@ pub fn run() -> Result<()> {
|
||||
return Ok(());
|
||||
}
|
||||
BootInfo::SupportedKmis => {
|
||||
let kmi = crate::assets::list_supported_kmi()?;
|
||||
kmi.iter().for_each(|kmi| println!("{kmi}"));
|
||||
let kmi = crate::assets::list_supported_kmi();
|
||||
for kmi in &kmi {
|
||||
println!("{kmi}");
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
BootInfo::IsAbDevice => {
|
||||
@@ -701,7 +711,7 @@ pub fn run() -> Result<()> {
|
||||
return Ok(());
|
||||
}
|
||||
BootInfo::DefaultPartition => {
|
||||
let kmi = crate::boot_patch::get_current_kmi().unwrap_or_else(|_| String::from(""));
|
||||
let kmi = crate::boot_patch::get_current_kmi().unwrap_or_else(|_| String::new());
|
||||
let name = crate::boot_patch::choose_boot_partition(&kmi, false, &None);
|
||||
println!("{name}");
|
||||
return Ok(());
|
||||
@@ -713,7 +723,9 @@ pub fn run() -> Result<()> {
|
||||
}
|
||||
BootInfo::AvailablePartitions => {
|
||||
let parts = crate::boot_patch::list_available_partitions();
|
||||
parts.iter().for_each(|p| println!("{p}"));
|
||||
for p in &parts {
|
||||
println!("{p}");
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
},
|
||||
@@ -747,7 +759,7 @@ pub fn run() -> Result<()> {
|
||||
Kpm::Info { name } => crate::kpm::kpm_info(&name),
|
||||
Kpm::Control { name, args } => {
|
||||
let ret = crate::kpm::kpm_control(&name, &args)?;
|
||||
println!("{}", ret);
|
||||
println!("{ret}");
|
||||
Ok(())
|
||||
}
|
||||
Kpm::Version => crate::kpm::kpm_version_loader(),
|
||||
|
||||
@@ -58,13 +58,11 @@ pub fn mark_get(pid: i32) -> Result<()> {
|
||||
let result = ksucalls::mark_get(pid)?;
|
||||
if pid == 0 {
|
||||
bail!("Please specify a pid to get its mark status");
|
||||
} else {
|
||||
println!(
|
||||
"Process {} mark status: {}",
|
||||
pid,
|
||||
if result != 0 { "marked" } else { "unmarked" }
|
||||
);
|
||||
}
|
||||
println!(
|
||||
"Process {pid} mark status: {}",
|
||||
if result != 0 { "marked" } else { "unmarked" }
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -74,7 +72,7 @@ pub fn mark_set(pid: i32) -> Result<()> {
|
||||
if pid == 0 {
|
||||
println!("All processes marked successfully");
|
||||
} else {
|
||||
println!("Process {} marked successfully", pid);
|
||||
println!("Process {pid} marked successfully");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -85,7 +83,7 @@ pub fn mark_unset(pid: i32) -> Result<()> {
|
||||
if pid == 0 {
|
||||
println!("All processes unmarked successfully");
|
||||
} else {
|
||||
println!("Process {} unmarked successfully", pid);
|
||||
println!("Process {pid} unmarked successfully");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ use std::path::Path;
|
||||
use crate::defs;
|
||||
|
||||
const FEATURE_CONFIG_PATH: &str = concatcp!(defs::WORKING_DIR, ".feature_config");
|
||||
#[allow(clippy::unreadable_literal)]
|
||||
const FEATURE_MAGIC: u32 = 0x7f4b5355;
|
||||
const FEATURE_VERSION: u32 = 1;
|
||||
|
||||
@@ -21,37 +22,37 @@ pub enum FeatureId {
|
||||
}
|
||||
|
||||
impl FeatureId {
|
||||
pub fn from_u32(id: u32) -> Option<Self> {
|
||||
pub const fn from_u32(id: u32) -> Option<Self> {
|
||||
match id {
|
||||
0 => Some(FeatureId::SuCompat),
|
||||
1 => Some(FeatureId::KernelUmount),
|
||||
2 => Some(FeatureId::EnhancedSecurity),
|
||||
3 => Some(FeatureId::SuLog),
|
||||
0 => Some(Self::SuCompat),
|
||||
1 => Some(Self::KernelUmount),
|
||||
2 => Some(Self::EnhancedSecurity),
|
||||
3 => Some(Self::SuLog),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn name(&self) -> &'static str {
|
||||
pub const fn name(self) -> &'static str {
|
||||
match self {
|
||||
FeatureId::SuCompat => "su_compat",
|
||||
FeatureId::KernelUmount => "kernel_umount",
|
||||
FeatureId::EnhancedSecurity => "enhanced_security",
|
||||
FeatureId::SuLog => "sulog",
|
||||
Self::SuCompat => "su_compat",
|
||||
Self::KernelUmount => "kernel_umount",
|
||||
Self::EnhancedSecurity => "enhanced_security",
|
||||
Self::SuLog => "sulog",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn description(&self) -> &'static str {
|
||||
pub const fn description(self) -> &'static str {
|
||||
match self {
|
||||
FeatureId::SuCompat => {
|
||||
Self::SuCompat => {
|
||||
"SU Compatibility Mode - allows authorized apps to gain root via traditional 'su' command"
|
||||
}
|
||||
FeatureId::KernelUmount => {
|
||||
Self::KernelUmount => {
|
||||
"Kernel Umount - controls whether kernel automatically unmounts modules when not needed"
|
||||
}
|
||||
FeatureId::EnhancedSecurity => {
|
||||
Self::EnhancedSecurity => {
|
||||
"Enhanced Security - disable non‑KSU root elevation and unauthorized UID downgrades"
|
||||
}
|
||||
FeatureId::SuLog => {
|
||||
Self::SuLog => {
|
||||
"SU Log - enables logging of SU command usage to kernel log for auditing purposes"
|
||||
}
|
||||
}
|
||||
@@ -64,7 +65,7 @@ fn parse_feature_id(name: &str) -> Result<FeatureId> {
|
||||
"kernel_umount" | "1" => Ok(FeatureId::KernelUmount),
|
||||
"enhanced_security" | "2" => Ok(FeatureId::EnhancedSecurity),
|
||||
"sulog" | "3" => Ok(FeatureId::SuLog),
|
||||
_ => bail!("Unknown feature: {}", name),
|
||||
_ => bail!("Unknown feature: {name}"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,11 +84,7 @@ pub fn load_binary_config() -> Result<HashMap<u32, u64>> {
|
||||
let magic = u32::from_le_bytes(magic_buf);
|
||||
|
||||
if magic != FEATURE_MAGIC {
|
||||
bail!(
|
||||
"Invalid feature config magic: expected 0x{:08x}, got 0x{:08x}",
|
||||
FEATURE_MAGIC,
|
||||
magic
|
||||
);
|
||||
bail!("Invalid feature config magic: expected 0x{FEATURE_MAGIC:08x}, got 0x{magic:08x}",);
|
||||
}
|
||||
|
||||
let mut version_buf = [0u8; 4];
|
||||
@@ -97,9 +94,8 @@ pub fn load_binary_config() -> Result<HashMap<u32, u64>> {
|
||||
|
||||
if version != FEATURE_VERSION {
|
||||
log::warn!(
|
||||
"Feature config version mismatch: expected {}, got {}",
|
||||
FEATURE_VERSION,
|
||||
version
|
||||
"Feature config version mismatch: expected {FEATURE_VERSION}, got {version
|
||||
}",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -144,11 +140,11 @@ pub fn save_binary_config(features: &HashMap<u32, u64>) -> Result<()> {
|
||||
file.write_all(&count.to_le_bytes())
|
||||
.with_context(|| "Failed to write count")?;
|
||||
|
||||
for (&id, &value) in features.iter() {
|
||||
for (&id, &value) in features {
|
||||
file.write_all(&id.to_le_bytes())
|
||||
.with_context(|| format!("Failed to write feature id {}", id))?;
|
||||
.with_context(|| format!("Failed to write feature id {id}"))?;
|
||||
file.write_all(&value.to_le_bytes())
|
||||
.with_context(|| format!("Failed to write feature value for id {}", id))?;
|
||||
.with_context(|| format!("Failed to write feature value for id {id}"))?;
|
||||
}
|
||||
|
||||
file.sync_all()
|
||||
@@ -158,43 +154,42 @@ pub fn save_binary_config(features: &HashMap<u32, u64>) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn apply_config(features: &HashMap<u32, u64>) -> Result<()> {
|
||||
pub fn apply_config(features: &HashMap<u32, u64>) {
|
||||
log::info!("Applying feature configuration to kernel...");
|
||||
|
||||
let mut applied = 0;
|
||||
for (&id, &value) in features.iter() {
|
||||
for (&id, &value) in features {
|
||||
match crate::ksucalls::set_feature(id, value) {
|
||||
Ok(_) => {
|
||||
Ok(()) => {
|
||||
if let Some(feature_id) = FeatureId::from_u32(id) {
|
||||
log::info!("Set feature {} to {}", feature_id.name(), value);
|
||||
log::info!("Set feature {} to {value}", feature_id.name());
|
||||
} else {
|
||||
log::info!("Set feature {} to {}", id, value);
|
||||
log::info!("Set feature {id} to {value}");
|
||||
}
|
||||
applied += 1;
|
||||
}
|
||||
Err(e) => {
|
||||
log::warn!("Failed to set feature {}: {}", id, e);
|
||||
log::warn!("Failed to set feature {id}: {e}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log::info!("Applied {} features successfully", applied);
|
||||
Ok(())
|
||||
log::info!("Applied {applied} features successfully");
|
||||
}
|
||||
|
||||
pub fn get_feature(id: String) -> Result<()> {
|
||||
let feature_id = parse_feature_id(&id)?;
|
||||
pub fn get_feature(id: &str) -> Result<()> {
|
||||
let feature_id = parse_feature_id(id)?;
|
||||
let (value, supported) = crate::ksucalls::get_feature(feature_id as u32)
|
||||
.with_context(|| format!("Failed to get feature {}", id))?;
|
||||
.with_context(|| format!("Failed to get feature {id}"))?;
|
||||
|
||||
if !supported {
|
||||
println!("Feature '{}' is not supported by kernel", id);
|
||||
println!("Feature '{id}' is not supported by kernel");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
println!("Feature: {} ({})", feature_id.name(), feature_id as u32);
|
||||
println!("Description: {}", feature_id.description());
|
||||
println!("Value: {}", value);
|
||||
println!("Value: {value}");
|
||||
println!(
|
||||
"Status: {}",
|
||||
if value != 0 { "enabled" } else { "disabled" }
|
||||
@@ -203,8 +198,8 @@ pub fn get_feature(id: String) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_feature(id: String, value: u64) -> Result<()> {
|
||||
let feature_id = parse_feature_id(&id)?;
|
||||
pub fn set_feature(id: &str, value: u64) -> Result<()> {
|
||||
let feature_id = parse_feature_id(id)?;
|
||||
|
||||
// Check if this feature is managed by any module
|
||||
if let Ok(managed_features_map) = crate::module::get_managed_features() {
|
||||
@@ -232,27 +227,25 @@ pub fn set_feature(id: String, value: u64) -> Result<()> {
|
||||
}
|
||||
|
||||
log::info!(
|
||||
"Module '{}' is setting managed feature '{}'",
|
||||
caller_module,
|
||||
"Module '{caller_module}' is setting managed feature '{}'",
|
||||
feature_id.name()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
crate::ksucalls::set_feature(feature_id as u32, value)
|
||||
.with_context(|| format!("Failed to set feature {} to {}", id, value))?;
|
||||
.with_context(|| format!("Failed to set feature {id} to {value}"))?;
|
||||
|
||||
println!(
|
||||
"Feature '{}' set to {} ({})",
|
||||
"Feature '{}' set to {value} ({})",
|
||||
feature_id.name(),
|
||||
value,
|
||||
if value != 0 { "enabled" } else { "disabled" }
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn list_features() -> Result<()> {
|
||||
pub fn list_features() {
|
||||
println!("Available Features:");
|
||||
println!("{}", "=".repeat(80));
|
||||
|
||||
@@ -261,7 +254,7 @@ pub fn list_features() -> Result<()> {
|
||||
|
||||
// Build a reverse map: feature_name -> Vec<module_id>
|
||||
let mut feature_to_modules: HashMap<String, Vec<String>> = HashMap::new();
|
||||
for (module_id, feature_list) in managed_features_map.iter() {
|
||||
for (module_id, feature_list) in &managed_features_map {
|
||||
for feature_name in feature_list {
|
||||
feature_to_modules
|
||||
.entry(feature_name.clone())
|
||||
@@ -277,14 +270,14 @@ pub fn list_features() -> Result<()> {
|
||||
FeatureId::SuLog,
|
||||
];
|
||||
|
||||
for feature_id in all_features.iter() {
|
||||
for feature_id in &all_features {
|
||||
let id = *feature_id as u32;
|
||||
let (value, supported) = crate::ksucalls::get_feature(id).unwrap_or((0, false));
|
||||
|
||||
let status = if !supported {
|
||||
"NOT_SUPPORTED".to_string()
|
||||
} else if value != 0 {
|
||||
format!("ENABLED ({})", value)
|
||||
format!("ENABLED ({value})")
|
||||
} else {
|
||||
"DISABLED".to_string()
|
||||
};
|
||||
@@ -314,8 +307,6 @@ pub fn list_features() -> Result<()> {
|
||||
|
||||
println!();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn load_config_and_apply() -> Result<()> {
|
||||
@@ -326,7 +317,7 @@ pub fn load_config_and_apply() -> Result<()> {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
apply_config(&features)?;
|
||||
apply_config(&features);
|
||||
println!("Feature configuration loaded and applied");
|
||||
Ok(())
|
||||
}
|
||||
@@ -341,13 +332,13 @@ pub fn save_config() -> Result<()> {
|
||||
FeatureId::SuLog,
|
||||
];
|
||||
|
||||
for feature_id in all_features.iter() {
|
||||
for feature_id in &all_features {
|
||||
let id = *feature_id as u32;
|
||||
if let Ok((value, supported)) = crate::ksucalls::get_feature(id)
|
||||
&& supported
|
||||
{
|
||||
features.insert(id, value);
|
||||
log::info!("Saved feature {} = {}", feature_id.name(), value);
|
||||
log::info!("Saved feature {} = {value}", feature_id.name());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -359,8 +350,8 @@ pub fn save_config() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn check_feature(id: String) -> Result<()> {
|
||||
let feature_id = parse_feature_id(&id)?;
|
||||
pub fn check_feature(id: &str) -> Result<()> {
|
||||
let feature_id = parse_feature_id(id)?;
|
||||
|
||||
// Check if this feature is managed by any module
|
||||
let managed_features_map = crate::module::get_managed_features().unwrap_or_default();
|
||||
@@ -375,7 +366,7 @@ pub fn check_feature(id: String) -> Result<()> {
|
||||
|
||||
// Check if the feature is supported by kernel
|
||||
let (_value, supported) = crate::ksucalls::get_feature(feature_id as u32)
|
||||
.with_context(|| format!("Failed to get feature {}", id))?;
|
||||
.with_context(|| format!("Failed to get feature {id}"))?;
|
||||
|
||||
if supported {
|
||||
println!("supported");
|
||||
@@ -400,10 +391,9 @@ pub fn init_features() -> Result<()> {
|
||||
);
|
||||
|
||||
// Build a set of all managed feature IDs to skip
|
||||
for (module_id, feature_list) in managed_features_map.iter() {
|
||||
for (module_id, feature_list) in &managed_features_map {
|
||||
log::info!(
|
||||
"Module '{}' manages {} feature(s)",
|
||||
module_id,
|
||||
"Module '{module_id}' manages {} feature(s)",
|
||||
feature_list.len()
|
||||
);
|
||||
for feature_name in feature_list {
|
||||
@@ -412,22 +402,16 @@ pub fn init_features() -> Result<()> {
|
||||
// Remove managed features from config, let modules control them
|
||||
if features.remove(&feature_id_u32).is_some() {
|
||||
log::info!(
|
||||
" - Skipping managed feature '{}' (controlled by module: {})",
|
||||
feature_name,
|
||||
module_id
|
||||
" - Skipping managed feature '{feature_name}' (controlled by module: {module_id})",
|
||||
);
|
||||
} else {
|
||||
log::info!(
|
||||
" - Feature '{}' is managed by module '{}', skipping",
|
||||
feature_name,
|
||||
module_id
|
||||
" - Feature '{feature_name}' is managed by module '{module_id}', skipping",
|
||||
);
|
||||
}
|
||||
} else {
|
||||
log::warn!(
|
||||
" - Unknown managed feature '{}' from module '{}', ignoring",
|
||||
feature_name,
|
||||
module_id
|
||||
" - Unknown managed feature '{feature_name}' from module '{module_id}', ignoring",
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -444,7 +428,7 @@ pub fn init_features() -> Result<()> {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
apply_config(&features)?;
|
||||
apply_config(&features);
|
||||
|
||||
// Save the configuration (excluding managed features)
|
||||
save_binary_config(&features)?;
|
||||
|
||||
@@ -21,9 +21,9 @@ pub fn on_post_data_fs() -> Result<()> {
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
let _ = catch_bootlog("logcat", vec!["logcat"]);
|
||||
let _ = catch_bootlog("logcat", &["logcat"]);
|
||||
#[cfg(unix)]
|
||||
let _ = catch_bootlog("dmesg", vec!["dmesg", "-w"]);
|
||||
let _ = catch_bootlog("dmesg", &["dmesg", "-w"]);
|
||||
|
||||
if utils::has_magisk() {
|
||||
warn!("Magisk detected, skip post-fs-data!");
|
||||
@@ -159,24 +159,20 @@ fn run_stage(stage: &str, block: bool) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn on_services() -> Result<()> {
|
||||
pub fn on_services() {
|
||||
info!("on_services triggered!");
|
||||
run_stage("service", false);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn on_boot_completed() -> Result<()> {
|
||||
pub fn on_boot_completed() {
|
||||
ksucalls::report_boot_complete();
|
||||
info!("on_boot_completed triggered!");
|
||||
|
||||
run_stage("boot-completed", false);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn catch_bootlog(logname: &str, command: Vec<&str>) -> Result<()> {
|
||||
fn catch_bootlog(logname: &str, command: &[&str]) -> Result<()> {
|
||||
use std::os::unix::process::CommandExt;
|
||||
use std::process::Stdio;
|
||||
|
||||
@@ -192,7 +188,7 @@ fn catch_bootlog(logname: &str, command: Vec<&str>) -> Result<()> {
|
||||
let bootlog = std::fs::File::create(bootlog)?;
|
||||
|
||||
let mut args = vec!["-s", "9", "30s"];
|
||||
args.extend_from_slice(&command);
|
||||
args.extend_from_slice(command);
|
||||
// timeout -s 9 30s logcat > boot.log
|
||||
let result = unsafe {
|
||||
std::process::Command::new("timeout")
|
||||
|
||||
@@ -20,6 +20,7 @@ const KPM_INFO: u64 = 5;
|
||||
const KPM_CONTROL: u64 = 6;
|
||||
const KPM_VERSION: u64 = 7;
|
||||
|
||||
#[allow(clippy::unreadable_literal)]
|
||||
const KSU_IOCTL_KPM: u32 = 0xc0004bc8; // _IOC(_IOC_READ|_IOC_WRITE, 'K', 200, 0)
|
||||
|
||||
#[repr(C)]
|
||||
@@ -32,7 +33,7 @@ struct KsuKpmCmd {
|
||||
}
|
||||
|
||||
fn kpm_ioctl(cmd: &mut KsuKpmCmd) -> std::io::Result<()> {
|
||||
ksuctl(KSU_IOCTL_KPM, cmd as *mut _)?;
|
||||
ksuctl(KSU_IOCTL_KPM, std::ptr::from_mut(cmd))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -57,7 +58,7 @@ where
|
||||
control_code: KPM_LOAD,
|
||||
arg1: path_c.as_ptr() as u64,
|
||||
arg2: args_c.as_ref().map_or(0, |s| s.as_ptr() as u64),
|
||||
result_code: &mut result as *mut i32 as u64,
|
||||
result_code: &raw mut result as u64,
|
||||
};
|
||||
|
||||
kpm_ioctl(&mut cmd)?;
|
||||
@@ -75,7 +76,7 @@ pub fn kpm_unload(name: &str) -> Result<()> {
|
||||
control_code: KPM_UNLOAD,
|
||||
arg1: name_c.as_ptr() as u64,
|
||||
arg2: 0,
|
||||
result_code: &mut result as *mut i32 as u64,
|
||||
result_code: &raw mut result as u64,
|
||||
};
|
||||
|
||||
kpm_ioctl(&mut cmd)?;
|
||||
@@ -90,7 +91,7 @@ pub fn kpm_num() -> Result<i32> {
|
||||
control_code: KPM_NUM,
|
||||
arg1: 0,
|
||||
arg2: 0,
|
||||
result_code: &mut result as *mut i32 as u64,
|
||||
result_code: &raw mut result as u64,
|
||||
};
|
||||
|
||||
kpm_ioctl(&mut cmd)?;
|
||||
@@ -108,7 +109,7 @@ pub fn kpm_list() -> Result<()> {
|
||||
control_code: KPM_LIST,
|
||||
arg1: buf.as_mut_ptr() as u64,
|
||||
arg2: buf.len() as u64,
|
||||
result_code: &mut result as *mut i32 as u64,
|
||||
result_code: &raw mut result as u64,
|
||||
};
|
||||
|
||||
kpm_ioctl(&mut cmd)?;
|
||||
@@ -127,7 +128,7 @@ pub fn kpm_info(name: &str) -> Result<()> {
|
||||
control_code: KPM_INFO,
|
||||
arg1: name_c.as_ptr() as u64,
|
||||
arg2: buf.as_mut_ptr() as u64,
|
||||
result_code: &mut result as *mut i32 as u64,
|
||||
result_code: &raw mut result as u64,
|
||||
};
|
||||
|
||||
kpm_ioctl(&mut cmd)?;
|
||||
@@ -146,7 +147,7 @@ pub fn kpm_control(name: &str, args: &str) -> Result<i32> {
|
||||
control_code: KPM_CONTROL,
|
||||
arg1: name_c.as_ptr() as u64,
|
||||
arg2: args_c.as_ptr() as u64,
|
||||
result_code: &mut result as *mut i32 as u64,
|
||||
result_code: &raw mut result as u64,
|
||||
};
|
||||
|
||||
kpm_ioctl(&mut cmd)?;
|
||||
@@ -162,7 +163,7 @@ pub fn kpm_version_loader() -> Result<()> {
|
||||
control_code: KPM_VERSION,
|
||||
arg1: buf.as_mut_ptr() as u64,
|
||||
arg2: buf.len() as u64,
|
||||
result_code: &mut result as *mut i32 as u64,
|
||||
result_code: &raw mut result as u64,
|
||||
};
|
||||
|
||||
kpm_ioctl(&mut cmd)?;
|
||||
@@ -180,7 +181,7 @@ pub fn check_kpm_version() -> Result<String> {
|
||||
control_code: KPM_VERSION,
|
||||
arg1: buf.as_mut_ptr() as u64,
|
||||
arg2: buf.len() as u64,
|
||||
result_code: &mut result as *mut i32 as u64,
|
||||
result_code: &raw mut result as u64,
|
||||
};
|
||||
|
||||
kpm_ioctl(&mut cmd)?;
|
||||
@@ -308,7 +309,7 @@ pub fn load_kpm_modules() -> Result<()> {
|
||||
&& ex == OsStr::new("kpm")
|
||||
{
|
||||
match kpm_load(&p, None) {
|
||||
Ok(_) => ok += 1,
|
||||
Ok(()) => ok += 1,
|
||||
Err(e) => {
|
||||
log::warn!("KPM: load {} failed: {e}", p.display());
|
||||
ng += 1;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#![allow(clippy::unreadable_literal)]
|
||||
use std::fs;
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
use std::os::fd::RawFd;
|
||||
@@ -115,7 +116,7 @@ fn scan_driver_fd() -> Option<RawFd> {
|
||||
|
||||
for entry in fd_dir.flatten() {
|
||||
if let Ok(fd_num) = entry.file_name().to_string_lossy().parse::<i32>() {
|
||||
let link_path = format!("/proc/self/fd/{}", fd_num);
|
||||
let link_path = format!("/proc/self/fd/{fd_num}");
|
||||
if let Ok(target) = fs::read_link(&link_path) {
|
||||
let target_str = target.to_string_lossy();
|
||||
if target_str.contains("[ksu_driver]") {
|
||||
@@ -181,7 +182,7 @@ fn get_info() -> GetInfoCmd {
|
||||
version: 0,
|
||||
flags: 0,
|
||||
};
|
||||
let _ = ksuctl(KSU_IOCTL_GET_INFO, &mut cmd as *mut _);
|
||||
let _ = ksuctl(KSU_IOCTL_GET_INFO, &raw mut cmd);
|
||||
cmd
|
||||
})
|
||||
}
|
||||
@@ -210,7 +211,7 @@ pub fn grant_root() -> std::io::Result<()> {
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
fn report_event(event: u32) {
|
||||
let mut cmd = ReportEventCmd { event };
|
||||
let _ = ksuctl(KSU_IOCTL_REPORT_EVENT, &mut cmd as *mut _);
|
||||
let _ = ksuctl(KSU_IOCTL_REPORT_EVENT, &raw mut cmd);
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "linux", target_os = "android")))]
|
||||
@@ -231,7 +232,7 @@ pub fn report_module_mounted() {
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
pub fn check_kernel_safemode() -> bool {
|
||||
let mut cmd = CheckSafemodeCmd { in_safe_mode: 0 };
|
||||
let _ = ksuctl(KSU_IOCTL_CHECK_SAFEMODE, &mut cmd as *mut _);
|
||||
let _ = ksuctl(KSU_IOCTL_CHECK_SAFEMODE, &raw mut cmd);
|
||||
cmd.in_safe_mode != 0
|
||||
}
|
||||
|
||||
@@ -242,7 +243,7 @@ pub fn check_kernel_safemode() -> bool {
|
||||
|
||||
pub fn set_sepolicy(cmd: &SetSepolicyCmd) -> std::io::Result<()> {
|
||||
let mut ioctl_cmd = *cmd;
|
||||
ksuctl(KSU_IOCTL_SET_SEPOLICY, &mut ioctl_cmd as *mut _)?;
|
||||
ksuctl(KSU_IOCTL_SET_SEPOLICY, &raw mut ioctl_cmd)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -254,21 +255,21 @@ pub fn get_feature(feature_id: u32) -> std::io::Result<(u64, bool)> {
|
||||
value: 0,
|
||||
supported: 0,
|
||||
};
|
||||
ksuctl(KSU_IOCTL_GET_FEATURE, &mut cmd as *mut _)?;
|
||||
ksuctl(KSU_IOCTL_GET_FEATURE, &raw mut cmd)?;
|
||||
Ok((cmd.value, cmd.supported != 0))
|
||||
}
|
||||
|
||||
/// Set feature value in kernel
|
||||
pub fn set_feature(feature_id: u32, value: u64) -> std::io::Result<()> {
|
||||
let mut cmd = SetFeatureCmd { feature_id, value };
|
||||
ksuctl(KSU_IOCTL_SET_FEATURE, &mut cmd as *mut _)?;
|
||||
ksuctl(KSU_IOCTL_SET_FEATURE, &raw mut cmd)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
pub fn get_wrapped_fd(fd: RawFd) -> std::io::Result<RawFd> {
|
||||
let mut cmd = GetWrapperFdCmd { fd, flags: 0 };
|
||||
let result = ksuctl(KSU_IOCTL_GET_WRAPPER_FD, &mut cmd as *mut _)?;
|
||||
let result = ksuctl(KSU_IOCTL_GET_WRAPPER_FD, &raw mut cmd)?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
@@ -279,7 +280,7 @@ pub fn mark_get(pid: i32) -> std::io::Result<u32> {
|
||||
pid,
|
||||
result: 0,
|
||||
};
|
||||
ksuctl(KSU_IOCTL_MANAGE_MARK, &mut cmd as *mut _)?;
|
||||
ksuctl(KSU_IOCTL_MANAGE_MARK, &raw mut cmd)?;
|
||||
Ok(cmd.result)
|
||||
}
|
||||
|
||||
@@ -290,7 +291,7 @@ pub fn mark_set(pid: i32) -> std::io::Result<()> {
|
||||
pid,
|
||||
result: 0,
|
||||
};
|
||||
ksuctl(KSU_IOCTL_MANAGE_MARK, &mut cmd as *mut _)?;
|
||||
ksuctl(KSU_IOCTL_MANAGE_MARK, &raw mut cmd)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -301,7 +302,7 @@ pub fn mark_unset(pid: i32) -> std::io::Result<()> {
|
||||
pid,
|
||||
result: 0,
|
||||
};
|
||||
ksuctl(KSU_IOCTL_MANAGE_MARK, &mut cmd as *mut _)?;
|
||||
ksuctl(KSU_IOCTL_MANAGE_MARK, &raw mut cmd)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -312,7 +313,7 @@ pub fn mark_refresh() -> std::io::Result<()> {
|
||||
pid: 0,
|
||||
result: 0,
|
||||
};
|
||||
ksuctl(KSU_IOCTL_MANAGE_MARK, &mut cmd as *mut _)?;
|
||||
ksuctl(KSU_IOCTL_MANAGE_MARK, &raw mut cmd)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -321,7 +322,7 @@ pub fn nuke_ext4_sysfs(mnt: &str) -> anyhow::Result<()> {
|
||||
let mut ioctl_cmd = NukeExt4SysfsCmd {
|
||||
arg: c_mnt.as_ptr() as u64,
|
||||
};
|
||||
ksuctl(KSU_IOCTL_NUKE_EXT4_SYSFS, &mut ioctl_cmd as *mut _)?;
|
||||
ksuctl(KSU_IOCTL_NUKE_EXT4_SYSFS, &raw mut ioctl_cmd)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -332,7 +333,7 @@ pub fn umount_list_wipe() -> std::io::Result<()> {
|
||||
flags: 0,
|
||||
mode: KSU_UMOUNT_WIPE,
|
||||
};
|
||||
ksuctl(KSU_IOCTL_ADD_TRY_UMOUNT, &mut cmd as *mut _)?;
|
||||
ksuctl(KSU_IOCTL_ADD_TRY_UMOUNT, &raw mut cmd)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -344,7 +345,7 @@ pub fn umount_list_add(path: &str, flags: u32) -> anyhow::Result<()> {
|
||||
flags,
|
||||
mode: KSU_UMOUNT_ADD,
|
||||
};
|
||||
ksuctl(KSU_IOCTL_ADD_TRY_UMOUNT, &mut cmd as *mut _)?;
|
||||
ksuctl(KSU_IOCTL_ADD_TRY_UMOUNT, &raw mut cmd)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -356,6 +357,6 @@ pub fn umount_list_del(path: &str) -> anyhow::Result<()> {
|
||||
flags: 0,
|
||||
mode: KSU_UMOUNT_DEL,
|
||||
};
|
||||
ksuctl(KSU_IOCTL_ADD_TRY_UMOUNT, &mut cmd as *mut _)?;
|
||||
ksuctl(KSU_IOCTL_ADD_TRY_UMOUNT, &raw mut cmd)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,3 +1,15 @@
|
||||
#![deny(clippy::all, clippy::pedantic)]
|
||||
#![warn(clippy::nursery)]
|
||||
#![allow(
|
||||
clippy::module_name_repetitions,
|
||||
clippy::cast_possible_truncation,
|
||||
clippy::cast_sign_loss,
|
||||
clippy::cast_precision_loss,
|
||||
clippy::doc_markdown,
|
||||
clippy::too_many_lines,
|
||||
clippy::cast_possible_wrap
|
||||
)]
|
||||
|
||||
mod apk_sign;
|
||||
mod assets;
|
||||
mod boot_patch;
|
||||
|
||||
@@ -17,13 +17,10 @@ use crate::{assets, defs};
|
||||
|
||||
/// Determine whether the provided module properties mark it as a metamodule
|
||||
pub fn is_metamodule(props: &HashMap<String, String>) -> bool {
|
||||
props
|
||||
.get("metamodule")
|
||||
.map(|s| {
|
||||
let trimmed = s.trim();
|
||||
trimmed == "1" || trimmed.eq_ignore_ascii_case("true")
|
||||
})
|
||||
.unwrap_or(false)
|
||||
props.get("metamodule").is_some_and(|s| {
|
||||
let trimmed = s.trim();
|
||||
trimmed == "1" || trimmed.eq_ignore_ascii_case("true")
|
||||
})
|
||||
}
|
||||
|
||||
/// Get metamodule path if it exists
|
||||
@@ -44,12 +41,11 @@ pub fn get_metamodule_path() -> Option<PathBuf> {
|
||||
|
||||
if resolved.exists() && resolved.is_dir() {
|
||||
return Some(resolved);
|
||||
} else {
|
||||
warn!(
|
||||
"Metamodule symlink points to non-existent path: {:?}",
|
||||
resolved
|
||||
);
|
||||
}
|
||||
warn!(
|
||||
"Metamodule symlink points to non-existent path: {}",
|
||||
resolved.display()
|
||||
);
|
||||
}
|
||||
|
||||
// Fallback: search for metamodule=1 in modules directory
|
||||
@@ -58,7 +54,10 @@ pub fn get_metamodule_path() -> Option<PathBuf> {
|
||||
if let Ok(props) = crate::module::read_module_prop(module_path)
|
||||
&& is_metamodule(&props)
|
||||
{
|
||||
info!("Found metamodule in modules directory: {:?}", module_path);
|
||||
info!(
|
||||
"Found metamodule in modules directory: {}",
|
||||
module_path.display()
|
||||
);
|
||||
result = Some(module_path.to_path_buf());
|
||||
}
|
||||
Ok(())
|
||||
@@ -113,13 +112,14 @@ pub fn check_install_safety() -> Result<(), bool> {
|
||||
|
||||
/// Create or update the metamodule symlink
|
||||
/// Points /data/adb/metamodule -> /data/adb/modules/{module_id}
|
||||
pub(crate) fn ensure_symlink(module_path: &Path) -> Result<()> {
|
||||
pub fn ensure_symlink(module_path: &Path) -> Result<()> {
|
||||
// METAMODULE_DIR might have trailing slash, so we need to trim it
|
||||
let symlink_path = Path::new(defs::METAMODULE_DIR.trim_end_matches('/'));
|
||||
|
||||
info!(
|
||||
"Creating metamodule symlink: {:?} -> {:?}",
|
||||
symlink_path, module_path
|
||||
"Creating metamodule symlink: {} -> {}",
|
||||
symlink_path.display(),
|
||||
module_path.display()
|
||||
);
|
||||
|
||||
// Remove existing symlink if it exists
|
||||
@@ -137,14 +137,14 @@ pub(crate) fn ensure_symlink(module_path: &Path) -> Result<()> {
|
||||
// Create symlink
|
||||
#[cfg(unix)]
|
||||
std::os::unix::fs::symlink(module_path, symlink_path)
|
||||
.with_context(|| format!("Failed to create symlink to {:?}", module_path))?;
|
||||
.with_context(|| format!("Failed to create symlink to {}", module_path.display()))?;
|
||||
|
||||
info!("Metamodule symlink created successfully");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Remove the metamodule symlink
|
||||
pub(crate) fn remove_symlink() -> Result<()> {
|
||||
pub fn remove_symlink() -> Result<()> {
|
||||
let symlink_path = Path::new(defs::METAMODULE_DIR.trim_end_matches('/'));
|
||||
|
||||
if symlink_path.is_symlink() {
|
||||
@@ -158,37 +158,35 @@ pub(crate) fn remove_symlink() -> Result<()> {
|
||||
|
||||
/// Get the install script content, using metainstall.sh from metamodule if available
|
||||
/// Returns the script content to be executed
|
||||
pub(crate) fn get_install_script(
|
||||
pub fn get_install_script(
|
||||
is_metamodule: bool,
|
||||
installer_content: &str,
|
||||
install_module_script: &str,
|
||||
) -> Result<String> {
|
||||
// Check if there's a metamodule with metainstall.sh
|
||||
// Only apply this logic for regular modules (not when installing metamodule itself)
|
||||
let install_script = if !is_metamodule {
|
||||
if let Some(metamodule_path) = get_metamodule_path() {
|
||||
if metamodule_path.join(defs::DISABLE_FILE_NAME).exists() {
|
||||
info!("Metamodule is disabled, using default installer");
|
||||
install_module_script.to_string()
|
||||
} else {
|
||||
let metainstall_path = metamodule_path.join(defs::METAMODULE_METAINSTALL_SCRIPT);
|
||||
|
||||
if metainstall_path.exists() {
|
||||
info!("Using metainstall.sh from metamodule");
|
||||
let metamodule_content = std::fs::read_to_string(&metainstall_path)
|
||||
.with_context(|| "Failed to read metamodule metainstall.sh")?;
|
||||
format!("{}\n{}\nexit 0\n", installer_content, metamodule_content)
|
||||
} else {
|
||||
info!("Metamodule exists but has no metainstall.sh, using default installer");
|
||||
install_module_script.to_string()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
info!("No metamodule found, using default installer");
|
||||
let install_script = if is_metamodule {
|
||||
info!("Installing metamodule, using default installer");
|
||||
install_module_script.to_string()
|
||||
} else if let Some(metamodule_path) = get_metamodule_path() {
|
||||
if metamodule_path.join(defs::DISABLE_FILE_NAME).exists() {
|
||||
info!("Metamodule is disabled, using default installer");
|
||||
install_module_script.to_string()
|
||||
} else {
|
||||
let metainstall_path = metamodule_path.join(defs::METAMODULE_METAINSTALL_SCRIPT);
|
||||
|
||||
if metainstall_path.exists() {
|
||||
info!("Using metainstall.sh from metamodule");
|
||||
let metamodule_content = std::fs::read_to_string(&metainstall_path)
|
||||
.with_context(|| "Failed to read metamodule metainstall.sh")?;
|
||||
format!("{installer_content}\n{metamodule_content}\nexit 0\n")
|
||||
} else {
|
||||
info!("Metamodule exists but has no metainstall.sh, using default installer");
|
||||
install_module_script.to_string()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
info!("Installing metamodule, using default installer");
|
||||
info!("No metamodule found, using default installer");
|
||||
install_module_script.to_string()
|
||||
};
|
||||
|
||||
@@ -204,7 +202,7 @@ fn check_metamodule_script(script_name: &str) -> Option<PathBuf> {
|
||||
|
||||
// Check if metamodule is disabled
|
||||
if metamodule_path.join(defs::DISABLE_FILE_NAME).exists() {
|
||||
info!("Metamodule is disabled, skipping {}", script_name);
|
||||
info!("Metamodule is disabled, skipping {script_name}");
|
||||
return None;
|
||||
}
|
||||
|
||||
@@ -218,16 +216,13 @@ fn check_metamodule_script(script_name: &str) -> Option<PathBuf> {
|
||||
}
|
||||
|
||||
/// Execute metamodule's metauninstall.sh for a specific module
|
||||
pub(crate) fn exec_metauninstall_script(module_id: &str) -> Result<()> {
|
||||
pub fn exec_metauninstall_script(module_id: &str) -> Result<()> {
|
||||
let Some(metauninstall_path) = check_metamodule_script(defs::METAMODULE_METAUNINSTALL_SCRIPT)
|
||||
else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
info!(
|
||||
"Executing metamodule metauninstall.sh for module: {}",
|
||||
module_id
|
||||
);
|
||||
info!("Executing metamodule metauninstall.sh for module: {module_id}",);
|
||||
|
||||
let result = Command::new(assets::BUSYBOX_PATH)
|
||||
.args(["sh", metauninstall_path.to_str().unwrap()])
|
||||
@@ -238,15 +233,11 @@ pub(crate) fn exec_metauninstall_script(module_id: &str) -> Result<()> {
|
||||
|
||||
ensure!(
|
||||
result.success(),
|
||||
"Metamodule metauninstall.sh failed for module {}: {:?}",
|
||||
module_id,
|
||||
"Metamodule metauninstall.sh failed for module {module_id}: {:?}",
|
||||
result
|
||||
);
|
||||
|
||||
info!(
|
||||
"Metamodule metauninstall.sh executed successfully for {}",
|
||||
module_id
|
||||
);
|
||||
info!("Metamodule metauninstall.sh executed successfully for {module_id}",);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -276,12 +267,12 @@ pub fn exec_mount_script(module_dir: &str) -> Result<()> {
|
||||
|
||||
/// Execute metamodule script for a specific stage
|
||||
pub fn exec_stage_script(stage: &str, block: bool) -> Result<()> {
|
||||
let Some(script_path) = check_metamodule_script(&format!("{}.sh", stage)) else {
|
||||
let Some(script_path) = check_metamodule_script(&format!("{stage}.sh")) else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
info!("Executing metamodule {}.sh", stage);
|
||||
info!("Executing metamodule {stage}.sh");
|
||||
crate::module::exec_script(&script_path, block)?;
|
||||
info!("Metamodule {}.sh executed successfully", stage);
|
||||
info!("Metamodule {stage}.sh executed successfully");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ pub fn validate_module_id(module_id: &str) -> Result<()> {
|
||||
}
|
||||
|
||||
/// Get common environment variables for script execution
|
||||
pub(crate) fn get_common_script_envs() -> Vec<(&'static str, String)> {
|
||||
pub fn get_common_script_envs() -> Vec<(&'static str, String)> {
|
||||
vec![
|
||||
("ASH_STANDALONE", "1".to_string()),
|
||||
("KSU", "true".to_string()),
|
||||
@@ -104,13 +104,14 @@ fn ensure_boot_completed() -> Result<()> {
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub(crate) enum ModuleType {
|
||||
pub enum ModuleType {
|
||||
All,
|
||||
Active,
|
||||
Updated,
|
||||
}
|
||||
|
||||
pub(crate) fn foreach_module(
|
||||
#[allow(clippy::needless_pass_by_value)]
|
||||
pub fn foreach_module(
|
||||
module_type: ModuleType,
|
||||
mut f: impl FnMut(&Path) -> Result<()>,
|
||||
) -> Result<()> {
|
||||
@@ -172,22 +173,20 @@ pub fn exec_script<T: AsRef<Path>>(path: T, wait: bool) -> Result<()> {
|
||||
.ok()
|
||||
.and_then(|p| p.components().next())
|
||||
.and_then(|c| c.as_os_str().to_str())
|
||||
.map(|s| s.to_string());
|
||||
.map(std::string::ToString::to_string);
|
||||
|
||||
// Validate and log module_id extraction
|
||||
let validated_module_id = module_id
|
||||
.as_ref()
|
||||
.and_then(|id| match validate_module_id(id) {
|
||||
Ok(_) => {
|
||||
debug!("Module ID extracted from script path: '{}'", id);
|
||||
Ok(()) => {
|
||||
debug!("Module ID extracted from script path: '{id}'");
|
||||
Some(id.as_str())
|
||||
}
|
||||
Err(e) => {
|
||||
warn!(
|
||||
"Invalid module ID '{}' extracted from script path '{}': {}",
|
||||
id,
|
||||
"Invalid module ID '{id}' extracted from script path '{}': {e}",
|
||||
path.as_ref().display(),
|
||||
e
|
||||
);
|
||||
None
|
||||
}
|
||||
@@ -228,7 +227,7 @@ pub fn exec_script<T: AsRef<Path>>(path: T, wait: bool) -> Result<()> {
|
||||
} else {
|
||||
command.spawn().map(|_| ())
|
||||
};
|
||||
result.map_err(|err| anyhow!("Failed to exec {}: {}", path.as_ref().display(), err))
|
||||
result.map_err(|e| anyhow!("Failed to exec {}: {e}", path.as_ref().display()))
|
||||
}
|
||||
|
||||
pub fn exec_stage_script(stage: &str, block: bool) -> Result<()> {
|
||||
@@ -317,13 +316,10 @@ pub fn prune_modules() -> Result<()> {
|
||||
if is_metamodule {
|
||||
info!("Removing metamodule symlink");
|
||||
if let Err(e) = metamodule::remove_symlink() {
|
||||
warn!("Failed to remove metamodule symlink: {}", e);
|
||||
warn!("Failed to remove metamodule symlink: {e}");
|
||||
}
|
||||
} else if let Err(e) = metamodule::exec_metauninstall_script(module_id) {
|
||||
warn!(
|
||||
"Failed to exec metamodule uninstall for {}: {}",
|
||||
module_id, e
|
||||
);
|
||||
warn!("Failed to exec metamodule uninstall for {module_id}: {e}",);
|
||||
}
|
||||
|
||||
// Then execute module's own uninstall.sh
|
||||
@@ -336,12 +332,12 @@ pub fn prune_modules() -> Result<()> {
|
||||
|
||||
// Clear module configs before removing module directory
|
||||
if let Err(e) = crate::module_config::clear_module_configs(module_id) {
|
||||
warn!("Failed to clear configs for {}: {}", module_id, e);
|
||||
warn!("Failed to clear configs for {module_id}: {e}");
|
||||
}
|
||||
|
||||
// Finally remove the module directory
|
||||
if let Err(e) = remove_dir_all(module) {
|
||||
warn!("Failed to remove {}: {}", module.display(), e);
|
||||
warn!("Failed to remove {}: {e}", module.display());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -349,7 +345,7 @@ pub fn prune_modules() -> Result<()> {
|
||||
|
||||
// collect remaining modules, if none, clean up metamodule record
|
||||
let remaining_modules: Vec<_> = std::fs::read_dir(defs::MODULE_DIR)?
|
||||
.filter_map(|entry| entry.ok())
|
||||
.filter_map(std::result::Result::ok)
|
||||
.filter(|entry| entry.path().join("module.prop").exists())
|
||||
.collect();
|
||||
|
||||
@@ -381,12 +377,12 @@ pub fn handle_updated_modules() -> Result<()> {
|
||||
if removed {
|
||||
let path = module_dir.join(defs::REMOVE_FILE_NAME);
|
||||
if let Err(e) = ensure_file_exists(&path) {
|
||||
warn!("Failed to create {}: {}", path.display(), e);
|
||||
warn!("Failed to create {}: {e}", path.display());
|
||||
}
|
||||
} else if disabled {
|
||||
let path = module_dir.join(defs::DISABLE_FILE_NAME);
|
||||
if let Err(e) = ensure_file_exists(&path) {
|
||||
warn!("Failed to create {}: {}", path.display(), e);
|
||||
warn!("Failed to create {}: {e}", path.display());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -395,7 +391,7 @@ pub fn handle_updated_modules() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn _install_module(zip: &str) -> Result<()> {
|
||||
fn install_module_to_system(zip: &str) -> Result<()> {
|
||||
ensure_boot_completed()?;
|
||||
|
||||
// print banner
|
||||
@@ -429,7 +425,7 @@ fn _install_module(zip: &str) -> Result<()> {
|
||||
|
||||
// Validate module_id format
|
||||
validate_module_id(module_id)
|
||||
.with_context(|| format!("Invalid module ID in module.prop: '{}'", module_id))?;
|
||||
.with_context(|| format!("Invalid module ID in module.prop: '{module_id}'"))?;
|
||||
|
||||
// Check if this module is a metamodule
|
||||
let is_metamodule = metamodule::is_metamodule(&module_prop);
|
||||
@@ -455,7 +451,7 @@ fn _install_module(zip: &str) -> Result<()> {
|
||||
let updated_dir = Path::new(defs::MODULE_UPDATE_DIR).join(module_id);
|
||||
|
||||
if is_metamodule {
|
||||
info!("Installing metamodule: {}", module_id);
|
||||
info!("Installing metamodule: {module_id}");
|
||||
|
||||
// Check if there's already a metamodule installed
|
||||
if metamodule::has_metamodule()
|
||||
@@ -470,7 +466,7 @@ fn _install_module(zip: &str) -> Result<()> {
|
||||
println!("\n❌ Installation Failed");
|
||||
println!("┌────────────────────────────────");
|
||||
println!("│ A metamodule is already installed");
|
||||
println!("│ Current metamodule: {}", existing_id);
|
||||
println!("│ Current metamodule: {existing_id}");
|
||||
println!("│");
|
||||
println!("│ Only one metamodule can be active at a time.");
|
||||
println!("│");
|
||||
@@ -536,13 +532,13 @@ fn _install_module(zip: &str) -> Result<()> {
|
||||
}
|
||||
|
||||
println!("- Module installed successfully!");
|
||||
info!("Module {} installed successfully!", module_id);
|
||||
info!("Module {module_id} installed successfully!");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn install_module(zip: &str) -> Result<()> {
|
||||
let result = _install_module(zip);
|
||||
let result = install_module_to_system(zip);
|
||||
if let Err(ref e) = result {
|
||||
println!("- Error: {e}");
|
||||
}
|
||||
@@ -553,14 +549,14 @@ pub fn undo_uninstall_module(id: &str) -> Result<()> {
|
||||
validate_module_id(id)?;
|
||||
|
||||
let module_path = Path::new(defs::MODULE_DIR).join(id);
|
||||
ensure!(module_path.exists(), "Module {} not found", id);
|
||||
ensure!(module_path.exists(), "Module {id} not found");
|
||||
|
||||
// Remove the remove mark
|
||||
let remove_file = module_path.join(defs::REMOVE_FILE_NAME);
|
||||
if remove_file.exists() {
|
||||
std::fs::remove_file(&remove_file)
|
||||
.with_context(|| format!("Failed to delete remove file for module '{}'", id))?;
|
||||
info!("Removed the remove mark for module {}", id);
|
||||
.with_context(|| format!("Failed to delete remove file for module '{id}'"))?;
|
||||
info!("Removed the remove mark for module {id}");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -570,13 +566,13 @@ pub fn uninstall_module(id: &str) -> Result<()> {
|
||||
validate_module_id(id)?;
|
||||
|
||||
let module_path = Path::new(defs::MODULE_DIR).join(id);
|
||||
ensure!(module_path.exists(), "Module {} not found", id);
|
||||
ensure!(module_path.exists(), "Module {id} not found");
|
||||
|
||||
// Mark for removal
|
||||
let remove_file = module_path.join(defs::REMOVE_FILE_NAME);
|
||||
File::create(remove_file).with_context(|| "Failed to create remove file")?;
|
||||
|
||||
info!("Module {} marked for removal", id);
|
||||
info!("Module {id} marked for removal");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -592,14 +588,14 @@ pub fn enable_module(id: &str) -> Result<()> {
|
||||
validate_module_id(id)?;
|
||||
|
||||
let module_path = Path::new(defs::MODULE_DIR).join(id);
|
||||
ensure!(module_path.exists(), "Module {} not found", id);
|
||||
ensure!(module_path.exists(), "Module {id} not found");
|
||||
|
||||
let disable_path = module_path.join(defs::DISABLE_FILE_NAME);
|
||||
if disable_path.exists() {
|
||||
std::fs::remove_file(&disable_path).with_context(|| {
|
||||
format!("Failed to remove disable file: {}", disable_path.display())
|
||||
})?;
|
||||
info!("Module {} enabled", id);
|
||||
info!("Module {id} enabled");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -607,12 +603,12 @@ pub fn enable_module(id: &str) -> Result<()> {
|
||||
|
||||
pub fn disable_module(id: &str) -> Result<()> {
|
||||
let module_path = Path::new(defs::MODULE_DIR).join(id);
|
||||
ensure!(module_path.exists(), "Module {} not found", id);
|
||||
ensure!(module_path.exists(), "Module {id} not found");
|
||||
|
||||
let disable_path = module_path.join(defs::DISABLE_FILE_NAME);
|
||||
ensure_file_exists(disable_path)?;
|
||||
|
||||
info!("Module {} disabled", id);
|
||||
info!("Module {id} disabled");
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -633,7 +629,7 @@ fn mark_all_modules(flag_file: &str) -> Result<()> {
|
||||
let path = entry.path();
|
||||
let flag = path.join(flag_file);
|
||||
if let Err(e) = ensure_file_exists(flag) {
|
||||
warn!("Failed to mark module: {}: {}", path.display(), e);
|
||||
warn!("Failed to mark module: {}: {e}", path.display());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -662,12 +658,12 @@ pub fn read_module_prop(module_path: &Path) -> Result<HashMap<String, String>> {
|
||||
Ok(prop_map)
|
||||
}
|
||||
|
||||
fn _list_modules(path: &str) -> Vec<HashMap<String, String>> {
|
||||
fn list_module(path: &str) -> Vec<HashMap<String, String>> {
|
||||
// Load all module configs once to minimize I/O overhead
|
||||
let all_configs = match crate::module_config::get_all_module_configs() {
|
||||
Ok(configs) => configs,
|
||||
Err(e) => {
|
||||
warn!("Failed to load module configs: {}", e);
|
||||
warn!("Failed to load module configs: {e}");
|
||||
HashMap::new()
|
||||
}
|
||||
};
|
||||
@@ -691,22 +687,19 @@ fn _list_modules(path: &str) -> Vec<HashMap<String, String>> {
|
||||
let mut module_prop_map = match read_module_prop(&path) {
|
||||
Ok(prop) => prop,
|
||||
Err(e) => {
|
||||
warn!("Failed to read module.prop for {}: {}", path.display(), e);
|
||||
warn!("Failed to read module.prop for {}: {e}", path.display());
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
// If id is missing or empty, use directory name as fallback
|
||||
if !module_prop_map.contains_key("id") || module_prop_map["id"].is_empty() {
|
||||
match entry.file_name().to_str() {
|
||||
Some(id) => {
|
||||
info!("Use dir name as module id: {id}");
|
||||
module_prop_map.insert("id".to_owned(), id.to_owned());
|
||||
}
|
||||
_ => {
|
||||
info!("Failed to get module id from dir name");
|
||||
continue;
|
||||
}
|
||||
if let Some(id) = entry.file_name().to_str() {
|
||||
info!("Use dir name as module id: {id}");
|
||||
module_prop_map.insert("id".to_owned(), id.to_owned());
|
||||
} else {
|
||||
info!("Failed to get module id from dir name");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -739,7 +732,8 @@ fn _list_modules(path: &str) -> Vec<HashMap<String, String>> {
|
||||
.iter()
|
||||
.filter_map(|(k, v)| {
|
||||
if k.starts_with("manage.") && crate::module_config::parse_bool_config(v) {
|
||||
k.strip_prefix("manage.").map(|f| f.to_string())
|
||||
k.strip_prefix("manage.")
|
||||
.map(std::string::ToString::to_string)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -758,7 +752,7 @@ fn _list_modules(path: &str) -> Vec<HashMap<String, String>> {
|
||||
}
|
||||
|
||||
pub fn list_modules() -> Result<()> {
|
||||
let modules = _list_modules(defs::MODULE_DIR);
|
||||
let modules = list_module(defs::MODULE_DIR);
|
||||
println!("{}", serde_json::to_string_pretty(&modules)?);
|
||||
Ok(())
|
||||
}
|
||||
@@ -771,35 +765,31 @@ pub fn get_managed_features() -> Result<HashMap<String, Vec<String>>> {
|
||||
|
||||
foreach_active_module(|module_path| {
|
||||
// Get module ID
|
||||
let module_id = match module_path.file_name().and_then(|n| n.to_str()) {
|
||||
Some(id) => id,
|
||||
None => {
|
||||
warn!(
|
||||
"Failed to get module id from path: {}",
|
||||
module_path.display()
|
||||
);
|
||||
return Ok(());
|
||||
}
|
||||
let Some(module_id) = module_path.file_name().and_then(|n| n.to_str()) else {
|
||||
warn!(
|
||||
"Failed to get module id from path: {}",
|
||||
module_path.display()
|
||||
);
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
// Read module config
|
||||
let config = match crate::module_config::merge_configs(module_id) {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
warn!("Failed to merge configs for module '{}': {}", module_id, e);
|
||||
warn!("Failed to merge configs for module '{module_id}': {e}");
|
||||
return Ok(()); // Skip this module
|
||||
}
|
||||
};
|
||||
|
||||
// Extract manage.* config entries
|
||||
let mut feature_list = Vec::new();
|
||||
for (key, value) in config.iter() {
|
||||
for (key, value) in &config {
|
||||
if key.starts_with("manage.") {
|
||||
// Parse feature name
|
||||
if let Some(feature_name) = key.strip_prefix("manage.")
|
||||
&& crate::module_config::parse_bool_config(value)
|
||||
{
|
||||
info!("Module {} manages feature: {}", module_id, feature_name);
|
||||
feature_list.push(feature_name.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ use std::path::{Path, PathBuf};
|
||||
use crate::defs;
|
||||
use crate::utils::ensure_dir_exists;
|
||||
|
||||
#[allow(clippy::unreadable_literal)]
|
||||
const MODULE_CONFIG_MAGIC: u32 = 0x4b53554d; // "KSUM"
|
||||
const MODULE_CONFIG_VERSION: u32 = 1;
|
||||
|
||||
@@ -23,10 +24,10 @@ pub enum ConfigType {
|
||||
}
|
||||
|
||||
impl ConfigType {
|
||||
fn filename(&self) -> &'static str {
|
||||
const fn filename(self) -> &'static str {
|
||||
match self {
|
||||
ConfigType::Persist => defs::PERSIST_CONFIG_NAME,
|
||||
ConfigType::Temp => defs::TEMP_CONFIG_NAME,
|
||||
Self::Persist => defs::PERSIST_CONFIG_NAME,
|
||||
Self::Temp => defs::TEMP_CONFIG_NAME,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -133,12 +134,12 @@ pub fn load_config(module_id: &str, config_type: ConfigType) -> Result<HashMap<S
|
||||
let config_path = get_config_path(module_id, config_type);
|
||||
|
||||
if !config_path.exists() {
|
||||
debug!("Config file not found: {:?}", config_path);
|
||||
debug!("Config file not found: {}", config_path.display());
|
||||
return Ok(HashMap::new());
|
||||
}
|
||||
|
||||
let mut file = File::open(&config_path)
|
||||
.with_context(|| format!("Failed to open config file: {:?}", config_path))?;
|
||||
.with_context(|| format!("Failed to open config file: {}", config_path.display()))?;
|
||||
|
||||
// Read magic
|
||||
let mut magic_buf = [0u8; 4];
|
||||
@@ -161,11 +162,7 @@ pub fn load_config(module_id: &str, config_type: ConfigType) -> Result<HashMap<S
|
||||
let version = u32::from_le_bytes(version_buf);
|
||||
|
||||
if version != MODULE_CONFIG_VERSION {
|
||||
bail!(
|
||||
"Unsupported config version: expected {}, got {}",
|
||||
MODULE_CONFIG_VERSION,
|
||||
version
|
||||
);
|
||||
bail!("Unsupported config version: expected {MODULE_CONFIG_VERSION}, got {version}");
|
||||
}
|
||||
|
||||
// Read count
|
||||
@@ -180,33 +177,37 @@ pub fn load_config(module_id: &str, config_type: ConfigType) -> Result<HashMap<S
|
||||
// Read key length
|
||||
let mut key_len_buf = [0u8; 4];
|
||||
file.read_exact(&mut key_len_buf)
|
||||
.with_context(|| format!("Failed to read key length for entry {}", i))?;
|
||||
.with_context(|| format!("Failed to read key length for entry {i}"))?;
|
||||
let key_len = u32::from_le_bytes(key_len_buf) as usize;
|
||||
|
||||
// Read key data
|
||||
let mut key_buf = vec![0u8; key_len];
|
||||
file.read_exact(&mut key_buf)
|
||||
.with_context(|| format!("Failed to read key data for entry {}", i))?;
|
||||
.with_context(|| format!("Failed to read key data for entry {i}"))?;
|
||||
let key = String::from_utf8(key_buf)
|
||||
.with_context(|| format!("Invalid UTF-8 in key for entry {}", i))?;
|
||||
.with_context(|| format!("Invalid UTF-8 in key for entry {i}"))?;
|
||||
|
||||
// Read value length
|
||||
let mut value_len_buf = [0u8; 4];
|
||||
file.read_exact(&mut value_len_buf)
|
||||
.with_context(|| format!("Failed to read value length for entry {}", i))?;
|
||||
.with_context(|| format!("Failed to read value length for entry {i}"))?;
|
||||
let value_len = u32::from_le_bytes(value_len_buf) as usize;
|
||||
|
||||
// Read value data
|
||||
let mut value_buf = vec![0u8; value_len];
|
||||
file.read_exact(&mut value_buf)
|
||||
.with_context(|| format!("Failed to read value data for entry {}", i))?;
|
||||
.with_context(|| format!("Failed to read value data for entry {i}"))?;
|
||||
let value = String::from_utf8(value_buf)
|
||||
.with_context(|| format!("Invalid UTF-8 in value for entry {}", i))?;
|
||||
.with_context(|| format!("Invalid UTF-8 in value for entry {i}"))?;
|
||||
|
||||
config.insert(key, value);
|
||||
}
|
||||
|
||||
debug!("Loaded {} entries from {:?}", config.len(), config_path);
|
||||
debug!(
|
||||
"Loaded {} entries from {}",
|
||||
config.len(),
|
||||
config_path.display()
|
||||
);
|
||||
Ok(config)
|
||||
}
|
||||
|
||||
@@ -223,9 +224,9 @@ pub fn save_config(
|
||||
|
||||
// Validate all keys and values
|
||||
for (key, value) in config {
|
||||
validate_config_key(key).with_context(|| format!("Invalid config key: '{}'", key))?;
|
||||
validate_config_key(key).with_context(|| format!("Invalid config key: '{key}'"))?;
|
||||
validate_config_value(value)
|
||||
.with_context(|| format!("Invalid config value for key '{}'", key))?;
|
||||
.with_context(|| format!("Invalid config value for key '{key}'"))?;
|
||||
}
|
||||
|
||||
ensure_config_dir(module_id)?;
|
||||
@@ -235,7 +236,7 @@ pub fn save_config(
|
||||
|
||||
// Write to temporary file first
|
||||
let mut file = File::create(&temp_path)
|
||||
.with_context(|| format!("Failed to create temp config file: {:?}", temp_path))?;
|
||||
.with_context(|| format!("Failed to create temp config file: {}", temp_path.display()))?;
|
||||
|
||||
// Write magic
|
||||
file.write_all(&MODULE_CONFIG_MAGIC.to_le_bytes())
|
||||
@@ -256,21 +257,21 @@ pub fn save_config(
|
||||
let key_bytes = key.as_bytes();
|
||||
let key_len = key_bytes.len() as u32;
|
||||
file.write_all(&key_len.to_le_bytes())
|
||||
.with_context(|| format!("Failed to write key length for '{}'", key))?;
|
||||
.with_context(|| format!("Failed to write key length for '{key}'"))?;
|
||||
|
||||
// Write key data
|
||||
file.write_all(key_bytes)
|
||||
.with_context(|| format!("Failed to write key data for '{}'", key))?;
|
||||
.with_context(|| format!("Failed to write key data for '{key}'"))?;
|
||||
|
||||
// Write value length
|
||||
let value_bytes = value.as_bytes();
|
||||
let value_len = value_bytes.len() as u32;
|
||||
file.write_all(&value_len.to_le_bytes())
|
||||
.with_context(|| format!("Failed to write value length for '{}'", key))?;
|
||||
.with_context(|| format!("Failed to write value length for '{key}'"))?;
|
||||
|
||||
// Write value data
|
||||
file.write_all(value_bytes)
|
||||
.with_context(|| format!("Failed to write value data for '{}'", key))?;
|
||||
.with_context(|| format!("Failed to write value data for '{key}'"))?;
|
||||
}
|
||||
|
||||
file.sync_all()
|
||||
@@ -279,12 +280,17 @@ pub fn save_config(
|
||||
// Atomic rename
|
||||
fs::rename(&temp_path, &config_path).with_context(|| {
|
||||
format!(
|
||||
"Failed to rename config file: {:?} -> {:?}",
|
||||
temp_path, config_path
|
||||
"Failed to rename config file: {} -> {}",
|
||||
temp_path.display(),
|
||||
config_path.display()
|
||||
)
|
||||
})?;
|
||||
|
||||
debug!("Saved {} entries to {:?}", config.len(), config_path);
|
||||
debug!(
|
||||
"Saved {} entries to {}",
|
||||
config.len(),
|
||||
config_path.display()
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -323,7 +329,7 @@ pub fn delete_config_value(module_id: &str, key: &str, config_type: ConfigType)
|
||||
let mut config = load_config(module_id, config_type)?;
|
||||
|
||||
if config.remove(key).is_none() {
|
||||
bail!("Key '{}' not found in config", key);
|
||||
bail!("Key '{key}' not found in config");
|
||||
}
|
||||
|
||||
save_config(module_id, config_type, &config)?;
|
||||
@@ -336,8 +342,8 @@ pub fn clear_config(module_id: &str, config_type: ConfigType) -> Result<()> {
|
||||
|
||||
if config_path.exists() {
|
||||
fs::remove_file(&config_path)
|
||||
.with_context(|| format!("Failed to remove config file: {:?}", config_path))?;
|
||||
debug!("Cleared config: {:?}", config_path);
|
||||
.with_context(|| format!("Failed to remove config file: {}", config_path.display()))?;
|
||||
debug!("Cleared config: {}", config_path.display());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -350,10 +356,7 @@ pub fn merge_configs(module_id: &str) -> Result<HashMap<String, String>> {
|
||||
let mut merged = match load_config(module_id, ConfigType::Persist) {
|
||||
Ok(config) => config,
|
||||
Err(e) => {
|
||||
warn!(
|
||||
"Failed to load persist config for module '{}': {}",
|
||||
module_id, e
|
||||
);
|
||||
warn!("Failed to load persist config for module '{module_id}': {e}");
|
||||
HashMap::new()
|
||||
}
|
||||
};
|
||||
@@ -361,10 +364,7 @@ pub fn merge_configs(module_id: &str) -> Result<HashMap<String, String>> {
|
||||
let temp = match load_config(module_id, ConfigType::Temp) {
|
||||
Ok(config) => config,
|
||||
Err(e) => {
|
||||
warn!(
|
||||
"Failed to load temp config for module '{}': {}",
|
||||
module_id, e
|
||||
);
|
||||
warn!("Failed to load temp config for module '{module_id}': {e}");
|
||||
HashMap::new()
|
||||
}
|
||||
};
|
||||
@@ -389,7 +389,7 @@ pub fn get_all_module_configs() -> Result<HashMap<String, HashMap<String, String
|
||||
let mut all_configs = HashMap::new();
|
||||
|
||||
for entry in fs::read_dir(config_root)
|
||||
.with_context(|| format!("Failed to read config directory: {:?}", config_root))?
|
||||
.with_context(|| format!("Failed to read config directory: {}", config_root.display()))?
|
||||
{
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
@@ -406,7 +406,7 @@ pub fn get_all_module_configs() -> Result<HashMap<String, HashMap<String, String
|
||||
}
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Failed to load config for module '{}': {}", module_id, e);
|
||||
warn!("Failed to load config for module '{module_id}': {e}");
|
||||
// Continue processing other modules
|
||||
}
|
||||
}
|
||||
@@ -428,7 +428,7 @@ pub fn clear_all_temp_configs() -> Result<()> {
|
||||
let mut cleared_count = 0;
|
||||
|
||||
for entry in fs::read_dir(config_root)
|
||||
.with_context(|| format!("Failed to read config directory: {:?}", config_root))?
|
||||
.with_context(|| format!("Failed to read config directory: {}", config_root.display()))?
|
||||
{
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
@@ -440,19 +440,19 @@ pub fn clear_all_temp_configs() -> Result<()> {
|
||||
let temp_config = path.join(defs::TEMP_CONFIG_NAME);
|
||||
if temp_config.exists() {
|
||||
match fs::remove_file(&temp_config) {
|
||||
Ok(_) => {
|
||||
debug!("Cleared temp config: {:?}", temp_config);
|
||||
Ok(()) => {
|
||||
debug!("Cleared temp config: {}", temp_config.display());
|
||||
cleared_count += 1;
|
||||
}
|
||||
Err(e) => {
|
||||
warn!("Failed to clear temp config {:?}: {}", temp_config, e);
|
||||
warn!("Failed to clear temp config {}: {e}", temp_config.display());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if cleared_count > 0 {
|
||||
debug!("Cleared {} temp config file(s)", cleared_count);
|
||||
debug!("Cleared {cleared_count} temp config file(s)");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -465,9 +465,13 @@ pub fn clear_module_configs(module_id: &str) -> Result<()> {
|
||||
let config_dir = get_config_dir(module_id);
|
||||
|
||||
if config_dir.exists() {
|
||||
fs::remove_dir_all(&config_dir)
|
||||
.with_context(|| format!("Failed to remove config directory: {:?}", config_dir))?;
|
||||
debug!("Cleared all configs for module: {}", module_id);
|
||||
fs::remove_dir_all(&config_dir).with_context(|| {
|
||||
format!(
|
||||
"Failed to remove config directory: {}",
|
||||
config_dir.display()
|
||||
)
|
||||
})?;
|
||||
debug!("Cleared all configs for module: {module_id}");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -50,7 +50,7 @@ pub fn list_templates() -> Result<()> {
|
||||
let template = template.file_name();
|
||||
if let Some(template) = template.to_str() {
|
||||
println!("{template}");
|
||||
};
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -71,9 +71,9 @@ pub fn apply_sepolies() -> Result<()> {
|
||||
};
|
||||
let sepolicy = sepolicy.path();
|
||||
if sepolicy::apply_file(&sepolicy).is_ok() {
|
||||
log::info!("profile sepolicy applied: {sepolicy:?}");
|
||||
log::info!("profile sepolicy applied: {}", sepolicy.display());
|
||||
} else {
|
||||
log::info!("profile sepolicy apply failed: {sepolicy:?}");
|
||||
log::info!("profile sepolicy apply failed: {}", sepolicy.display());
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
||||
@@ -390,11 +390,11 @@ impl TryFrom<&str> for PolicyObject {
|
||||
fn try_from(s: &str) -> Result<Self> {
|
||||
anyhow::ensure!(s.len() <= SEPOLICY_MAX_LEN, "policy object too long");
|
||||
if s == "*" {
|
||||
return Ok(PolicyObject::All);
|
||||
return Ok(Self::All);
|
||||
}
|
||||
let mut buf = [0u8; SEPOLICY_MAX_LEN];
|
||||
buf[..s.len()].copy_from_slice(s.as_bytes());
|
||||
Ok(PolicyObject::One(buf))
|
||||
Ok(Self::One(buf))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -669,7 +669,7 @@ struct FfiPolicy {
|
||||
sepol7: *const ffi::c_char,
|
||||
}
|
||||
|
||||
fn to_c_ptr(pol: &PolicyObject) -> *const ffi::c_char {
|
||||
const fn to_c_ptr(pol: &PolicyObject) -> *const ffi::c_char {
|
||||
match pol {
|
||||
PolicyObject::None | PolicyObject::All => std::ptr::null(),
|
||||
PolicyObject::One(s) => s.as_ptr().cast::<ffi::c_char>(),
|
||||
@@ -677,8 +677,8 @@ fn to_c_ptr(pol: &PolicyObject) -> *const ffi::c_char {
|
||||
}
|
||||
|
||||
impl From<AtomicStatement> for FfiPolicy {
|
||||
fn from(policy: AtomicStatement) -> FfiPolicy {
|
||||
FfiPolicy {
|
||||
fn from(policy: AtomicStatement) -> Self {
|
||||
Self {
|
||||
cmd: policy.cmd,
|
||||
subcmd: policy.subcmd,
|
||||
sepol1: to_c_ptr(&policy.sepol1),
|
||||
@@ -700,10 +700,10 @@ fn apply_one_rule<'a>(statement: &'a PolicyStatement<'a>, strict: bool) -> Resul
|
||||
let ffi_policy = FfiPolicy::from(policy);
|
||||
let cmd = crate::ksucalls::SetSepolicyCmd {
|
||||
cmd: 0,
|
||||
arg: &ffi_policy as *const _ as u64,
|
||||
arg: &raw const ffi_policy as u64,
|
||||
};
|
||||
if let Err(e) = crate::ksucalls::set_sepolicy(&cmd) {
|
||||
log::warn!("apply rule {:?} failed: {}", statement, e);
|
||||
log::warn!("apply rule {statement:?} failed: {e}");
|
||||
if strict {
|
||||
return Err(anyhow::anyhow!("apply rule {:?} failed: {}", statement, e));
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ pub fn grant_root(_global_mnt: bool) -> Result<()> {
|
||||
unimplemented!("grant_root is only available on android");
|
||||
}
|
||||
|
||||
fn print_usage(program: &str, opts: Options) {
|
||||
fn print_usage(program: &str, opts: &Options) {
|
||||
let brief = format!("KernelSU\n\nUsage: {program} [options] [-] [user [argument...]]");
|
||||
print!("{}", opts.usage(&brief));
|
||||
}
|
||||
@@ -78,10 +78,9 @@ fn wrap_tty(fd: c_int) {
|
||||
bail!("dup {new_fd} -> {fd} errno: {}", unsafe {
|
||||
*libc::__errno()
|
||||
});
|
||||
} else {
|
||||
unsafe { libc::close(new_fd) };
|
||||
Ok(())
|
||||
}
|
||||
unsafe { libc::close(new_fd) };
|
||||
Ok(())
|
||||
};
|
||||
|
||||
if let Err(e) = inner_fn() {
|
||||
@@ -95,16 +94,16 @@ pub fn root_shell() -> Result<()> {
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
#[allow(clippy::similar_names)]
|
||||
pub fn root_shell() -> Result<()> {
|
||||
// we are root now, this was set in kernel!
|
||||
|
||||
use anyhow::anyhow;
|
||||
let env_args: Vec<String> = env::args().collect();
|
||||
let program = env_args[0].clone();
|
||||
let args = env_args
|
||||
.iter()
|
||||
.position(|arg| arg == "-c")
|
||||
.map(|i| {
|
||||
let args = env_args.iter().position(|arg| arg == "-c").map_or_else(
|
||||
|| env_args.clone(),
|
||||
|i| {
|
||||
let rest = env_args[i + 1..].to_vec();
|
||||
let mut new_args = env_args[..i].to_vec();
|
||||
new_args.push("-c".to_string());
|
||||
@@ -112,8 +111,8 @@ pub fn root_shell() -> Result<()> {
|
||||
new_args.push(rest.join(" "));
|
||||
}
|
||||
new_args
|
||||
})
|
||||
.unwrap_or_else(|| env_args.clone());
|
||||
},
|
||||
);
|
||||
|
||||
let mut opts = Options::new();
|
||||
opts.optopt(
|
||||
@@ -169,13 +168,13 @@ pub fn root_shell() -> Result<()> {
|
||||
Result::Ok(m) => m,
|
||||
Err(f) => {
|
||||
println!("{f}");
|
||||
print_usage(&program, opts);
|
||||
print_usage(&program, &opts);
|
||||
std::process::exit(-1);
|
||||
}
|
||||
};
|
||||
|
||||
if matches.opt_present("h") {
|
||||
print_usage(&program, opts);
|
||||
print_usage(&program, &opts);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
@@ -189,7 +188,9 @@ pub fn root_shell() -> Result<()> {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let shell = matches.opt_str("s").unwrap_or("/system/bin/sh".to_string());
|
||||
let shell = matches
|
||||
.opt_str("s")
|
||||
.unwrap_or_else(|| "/system/bin/sh".to_string());
|
||||
let mut is_login = matches.opt_present("l");
|
||||
let preserve_env = matches.opt_present("p");
|
||||
let mount_master = matches.opt_present("M");
|
||||
@@ -234,10 +235,7 @@ pub fn root_shell() -> Result<()> {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let pw = libc::getpwnam(name.as_ptr() as *const i8).as_ref();
|
||||
|
||||
match pw {
|
||||
Some(pw) => pw.pw_uid,
|
||||
None => name.parse::<u32>().unwrap_or(0),
|
||||
}
|
||||
pw.map_or_else(|| name.parse::<u32>().unwrap_or(0), |pw| pw.pw_uid)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,28 +19,28 @@ const SERVICE_PATH: &str = "/data/adb/service.d/uid_scanner.sh";
|
||||
|
||||
pub fn start_uid_scanner_daemon() -> Result<()> {
|
||||
if !fs::exists(SCANNER_PATH)? {
|
||||
warn!("uid scanner binary not found at {}", SCANNER_PATH);
|
||||
warn!("uid scanner binary not found at {SCANNER_PATH}");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if let Err(e) = fs::set_permissions(SCANNER_PATH, fs::Permissions::from_mode(0o755)) {
|
||||
warn!("failed to set permissions for {}: {}", SCANNER_PATH, e);
|
||||
warn!("failed to set permissions for {SCANNER_PATH}: {e}");
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
{
|
||||
if let Err(e) = fs::create_dir_all(LINK_DIR) {
|
||||
warn!("failed to create {}: {}", LINK_DIR, e);
|
||||
warn!("failed to create {LINK_DIR}: {e}");
|
||||
} else if !fs::exists(LINK_PATH)? {
|
||||
match symlink(SCANNER_PATH, LINK_PATH) {
|
||||
Ok(_) => info!("created symlink {} -> {}", SCANNER_PATH, LINK_PATH),
|
||||
Err(e) => warn!("failed to create symlink: {}", e),
|
||||
Ok(()) => info!("created symlink {SCANNER_PATH} -> {LINK_PATH}"),
|
||||
Err(e) => warn!("failed to create symlink: {e}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Err(e) = fs::create_dir_all(SERVICE_DIR) {
|
||||
warn!("failed to create {}: {}", SERVICE_DIR, e);
|
||||
warn!("failed to create {SERVICE_DIR}: {e}");
|
||||
}
|
||||
|
||||
if !fs::exists(SERVICE_PATH)? {
|
||||
@@ -55,8 +55,8 @@ pub fn start_uid_scanner_daemon() -> Result<()> {
|
||||
f.sync_all()?;
|
||||
fs::set_permissions(SERVICE_PATH, fs::Permissions::from_mode(0o755))
|
||||
}) {
|
||||
Ok(_) => info!("created service script {}", SERVICE_PATH),
|
||||
Err(e) => warn!("failed to write {}: {}", SERVICE_PATH, e),
|
||||
Ok(()) => info!("created service script {SERVICE_PATH}"),
|
||||
Err(e) => warn!("failed to write {SERVICE_PATH}: {e}"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ pub fn start_uid_scanner_daemon() -> Result<()> {
|
||||
info!("uid scanner daemon started with pid: {}", child.id());
|
||||
std::mem::drop(child);
|
||||
}
|
||||
Err(e) => warn!("failed to start uid scanner daemon: {}", e),
|
||||
Err(e) => warn!("failed to start uid scanner daemon: {e}"),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -8,6 +8,7 @@ use crate::ksucalls::ksuctl;
|
||||
const MAGIC_NUMBER_HEADER: &[u8; 4] = b"KUMT";
|
||||
const MAGIC_VERSION: u32 = 1;
|
||||
const CONFIG_FILE: &str = "/data/adb/ksu/.umount";
|
||||
#[allow(clippy::unreadable_literal)]
|
||||
const KSU_IOCTL_UMOUNT_MANAGER: u32 = 0xc0004b6b; // _IOC(_IOC_READ|_IOC_WRITE, 'K', 107, 0)
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
@@ -39,7 +40,7 @@ struct UmountManagerCmd {
|
||||
|
||||
impl Default for UmountManagerCmd {
|
||||
fn default() -> Self {
|
||||
UmountManagerCmd {
|
||||
Self {
|
||||
operation: 0,
|
||||
path: [0; 256],
|
||||
flags: 0,
|
||||
@@ -61,7 +62,7 @@ impl UmountManager {
|
||||
}
|
||||
};
|
||||
|
||||
Ok(UmountManager {
|
||||
Ok(Self {
|
||||
config,
|
||||
config_path: path,
|
||||
})
|
||||
@@ -81,7 +82,7 @@ impl UmountManager {
|
||||
|
||||
let version = u32::from_le_bytes([data[4], data[5], data[6], data[7]]);
|
||||
if version != MAGIC_VERSION {
|
||||
return Err(anyhow!("Unsupported config version: {}", version));
|
||||
return Err(anyhow!("Unsupported config version: {version}"));
|
||||
}
|
||||
|
||||
let json_data = &data[8..];
|
||||
@@ -110,7 +111,7 @@ impl UmountManager {
|
||||
pub fn add_entry(&mut self, path: &str, flags: i32) -> Result<()> {
|
||||
let exists = self.config.entries.iter().any(|e| e.path == path);
|
||||
if exists {
|
||||
return Err(anyhow!("Entry already exists: {}", path));
|
||||
return Err(anyhow!("Entry already exists: {path}"));
|
||||
}
|
||||
|
||||
let entry = UmountEntry {
|
||||
@@ -128,7 +129,7 @@ impl UmountManager {
|
||||
self.config.entries.retain(|e| e.path != path);
|
||||
|
||||
if before == self.config.entries.len() {
|
||||
return Err(anyhow!("Entry not found: {}", path));
|
||||
return Err(anyhow!("Entry not found: {path}"));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -137,9 +138,8 @@ impl UmountManager {
|
||||
self.config.entries.clone()
|
||||
}
|
||||
|
||||
pub fn clear_custom_entries(&mut self) -> Result<()> {
|
||||
pub fn clear_custom_entries(&mut self) {
|
||||
self.config.entries.retain(|e| e.is_default);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn apply_to_kernel(&self) -> Result<()> {
|
||||
@@ -183,7 +183,7 @@ pub fn add_umount_path(path: &str, flags: i32) -> Result<()> {
|
||||
let mut manager = init_umount_manager()?;
|
||||
manager.add_entry(path, flags)?;
|
||||
manager.save_config()?;
|
||||
println!("✓ Added umount path: {}", path);
|
||||
println!("✓ Added umount path: {path}");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -191,7 +191,7 @@ pub fn remove_umount_path(path: &str) -> Result<()> {
|
||||
let mut manager = init_umount_manager()?;
|
||||
manager.remove_entry(path)?;
|
||||
manager.save_config()?;
|
||||
println!("✓ Removed umount path: {}", path);
|
||||
println!("✓ Removed umount path: {path}");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -222,7 +222,7 @@ pub fn list_umount_paths() -> Result<()> {
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
fn umount_manager_ioctl(cmd: &UmountManagerCmd) -> std::io::Result<()> {
|
||||
let mut ioctl_cmd = *cmd;
|
||||
ksuctl(KSU_IOCTL_UMOUNT_MANAGER, &mut ioctl_cmd as *mut _)?;
|
||||
ksuctl(KSU_IOCTL_UMOUNT_MANAGER, &raw mut ioctl_cmd)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -233,7 +233,7 @@ pub fn umount_manager_ioctl(_cmd: &UmountManagerCmd) -> std::io::Result<()> {
|
||||
|
||||
pub fn clear_custom_paths() -> Result<()> {
|
||||
let mut manager = init_umount_manager()?;
|
||||
manager.clear_custom_entries()?;
|
||||
manager.clear_custom_entries();
|
||||
manager.save_config()?;
|
||||
println!("✓ Cleared all custom paths");
|
||||
Ok(())
|
||||
@@ -242,7 +242,7 @@ pub fn clear_custom_paths() -> Result<()> {
|
||||
pub fn save_umount_config() -> Result<()> {
|
||||
let manager = init_umount_manager()?;
|
||||
manager.save_config()?;
|
||||
println!("✓ Configuration saved to: {}", CONFIG_FILE);
|
||||
println!("✓ Configuration saved to: {CONFIG_FILE}");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user