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:
生于生时 亡于亡刻
2025-11-22 06:09:45 +08:00
committed by GitHub
parent a772a0f82d
commit d0e8faea77
20 changed files with 829 additions and 784 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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(

View File

@@ -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
}

View File

@@ -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)?;

View File

@@ -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(),

View File

@@ -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,
"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(())
}

View File

@@ -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 nonKSU 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)?;

View File

@@ -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")

View File

@@ -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;

View File

@@ -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(())
}

View File

@@ -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;

View File

@@ -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| {
props.get("metamodule").is_some_and(|s| {
let trimmed = s.trim();
trimmed == "1" || trimmed.eq_ignore_ascii_case("true")
})
.unwrap_or(false)
}
/// 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,15 +158,17 @@ 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() {
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()
@@ -177,7 +179,7 @@ pub(crate) fn get_install_script(
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)
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()
@@ -186,10 +188,6 @@ pub(crate) fn get_install_script(
} else {
info!("No metamodule found, using default installer");
install_module_script.to_string()
}
} else {
info!("Installing metamodule, using default installer");
install_module_script.to_string()
};
Ok(install_script)
@@ -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(())
}

View File

@@ -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,24 +687,21 @@ 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) => {
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;
}
}
}
// Add enabled, update, remove, web, action flags
let enabled = !path.join(defs::DISABLE_FILE_NAME).exists();
@@ -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 => {
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());
}
}

View File

@@ -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(())

View File

@@ -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(())

View File

@@ -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));
}

View File

@@ -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(())
}
};
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)
}
}

View File

@@ -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(())

View File

@@ -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(())
}