ksud: fmt

This commit is contained in:
ShirkNeko
2025-10-06 22:44:09 +08:00
parent 04b603394a
commit e78ee720b5
4 changed files with 90 additions and 151 deletions

View File

@@ -34,7 +34,6 @@ import com.sukisu.ultra.ui.util.install
import com.sukisu.ultra.ui.viewmodel.HomeViewModel import com.sukisu.ultra.ui.viewmodel.HomeViewModel
import com.sukisu.ultra.ui.viewmodel.SuperUserViewModel import com.sukisu.ultra.ui.viewmodel.SuperUserViewModel
import com.sukisu.ultra.ui.webui.initPlatform import com.sukisu.ultra.ui.webui.initPlatform
import io.sukisu.ultra.UltraToolInstall
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import zako.zako.zako.zakoui.activity.component.BottomBar import zako.zako.zako.zakoui.activity.component.BottomBar
@@ -197,7 +196,6 @@ class MainActivity : ComponentActivity() {
val isManager = Natives.becomeManager(packageName) val isManager = Natives.becomeManager(packageName)
if (isManager) { if (isManager) {
install() install()
UltraToolInstall.tryToInstall()
} }
} }

View File

@@ -1,29 +0,0 @@
package io.sukisu.ultra;
import java.util.ArrayList;
import com.sukisu.ultra.ui.util.KsuCli;
public class UltraShellHelper {
public static String runCmd(String cmds) {
StringBuilder sb = new StringBuilder();
for(String str : KsuCli.INSTANCE.getGLOBAL_MNT_SHELL()
.newJob()
.add(cmds)
.to(new ArrayList<>(), null)
.exec()
.getOut()) {
sb.append(str).append("\n");
}
return sb.toString();
}
public static boolean isPathExists(String path) {
String result = runCmd("test -f '" + path + "' && echo 'exists'");
return result.contains("exists");
}
public static void CopyFileTo(String path, String target) {
runCmd("cp -f '" + path + "' '" + target + "' 2>&1");
}
}

View File

@@ -1,17 +0,0 @@
package io.sukisu.ultra;
import static com.sukisu.ultra.ui.util.KsuCliKt.*;
import android.annotation.SuppressLint;
public class UltraToolInstall {
private static final String OUTSIDE_SUSFSD_PATH = "/data/adb/ksu/bin/susfsd";
@SuppressLint("SetWorldReadable")
public static void tryToInstall() {
String SuSFSDaemonPath = getSuSFSDaemonPath();
if (UltraShellHelper.isPathExists(OUTSIDE_SUSFSD_PATH)) {
UltraShellHelper.CopyFileTo(SuSFSDaemonPath, OUTSIDE_SUSFSD_PATH);
UltraShellHelper.runCmd("chmod a+rx " + OUTSIDE_SUSFSD_PATH);
}
}
}

View File

@@ -1,14 +1,17 @@
use anyhow::{anyhow, bail, Result}; use anyhow::{anyhow, bail, Result};
use libc::{c_int, c_ulong, prctl}; use libc::{c_int, c_ulong, prctl};
use notify::{RecursiveMode, Watcher}; use notify::{RecursiveMode, Watcher};
use std::ffi::{CString, OsStr}; use std::{
use std::fs; ffi::{CStr, CString, OsStr},
use std::os::unix::fs::PermissionsExt; path::{Path, PathBuf},
use std::path::{Path, PathBuf}; os::unix::fs::PermissionsExt,
use std::ptr; fs,
ptr,
};
pub const KPM_DIR: &str = "/data/adb/kpm"; pub const KPM_DIR: &str = "/data/adb/kpm";
// SukiSU KPM prctl command space
const KSU_OPTIONS: c_int = 0xdeadbeef_u32 as c_int; const KSU_OPTIONS: c_int = 0xdeadbeef_u32 as c_int;
const SUKISU_KPM_LOAD: c_int = 28; const SUKISU_KPM_LOAD: c_int = 28;
const SUKISU_KPM_UNLOAD: c_int = 29; const SUKISU_KPM_UNLOAD: c_int = 29;
@@ -18,239 +21,224 @@ const SUKISU_KPM_INFO: c_int = 32;
const SUKISU_KPM_CONTROL:c_int = 33; const SUKISU_KPM_CONTROL:c_int = 33;
const SUKISU_KPM_VERSION:c_int = 34; const SUKISU_KPM_VERSION:c_int = 34;
/// Convert raw kernel return code to `Result`.
#[inline(always)] #[inline(always)]
fn check_out(out: c_int) -> Result<c_int> { fn check_out(rc: c_int) -> Result<c_int> {
if out < 0 { if rc < 0 {
bail!("KPM error: {}", std::io::Error::from_raw_os_error(-out)); bail!("KPM error: {}", std::io::Error::from_raw_os_error(-rc));
} }
Ok(out) Ok(rc)
} }
/// Load a `.kpm` into kernel space.
pub fn kpm_load(path: &str, args: Option<&str>) -> Result<()> { pub fn kpm_load(path: &str, args: Option<&str>) -> Result<()> {
let path_c = CString::new(path)?; let path_c = CString::new(path)?;
let args_c = args.map(CString::new).transpose()?; let args_c = args.map(CString::new).transpose()?;
let mut out: c_int = -1; let mut rc: c_int = -1;
// SAFETY: pointers live through the prctl; null-check done by CString.
unsafe { unsafe {
prctl( prctl(
KSU_OPTIONS, KSU_OPTIONS,
SUKISU_KPM_LOAD, SUKISU_KPM_LOAD,
path_c.as_ptr() as c_ulong, path_c.as_ptr() as c_ulong,
args_c.as_ref() args_c.as_ref().map_or(ptr::null(), |s| s.as_ptr()) as c_ulong,
.map_or(ptr::null(), |s| s.as_ptr()) as c_ulong, &mut rc as *mut c_int as c_ulong,
&mut out as *mut c_int as c_ulong,
); );
} }
check_out(out)?; check_out(rc)?;
println!("Success"); println!("Success");
Ok(()) Ok(())
} }
/// Unload by module name.
pub fn kpm_unload(name: &str) -> Result<()> { pub fn kpm_unload(name: &str) -> Result<()> {
let name_c = CString::new(name)?; let name_c = CString::new(name)?;
let mut out: c_int = -1; let mut rc = -1;
unsafe { unsafe {
prctl( prctl(KSU_OPTIONS, SUKISU_KPM_UNLOAD, name_c.as_ptr() as c_ulong, 0, &mut rc as *mut _ as c_ulong);
KSU_OPTIONS,
SUKISU_KPM_UNLOAD,
name_c.as_ptr() as c_ulong,
0,
&mut out as *mut c_int as c_ulong,
);
} }
check_out(out)?; check_out(rc)?;
Ok(()) Ok(())
} }
/// Return loaded module count.
pub fn kpm_num() -> Result<i32> { pub fn kpm_num() -> Result<i32> {
let mut out: c_int = -1; let mut rc = -1;
unsafe { unsafe { prctl(KSU_OPTIONS, SUKISU_KPM_NUM, 0, 0, &mut rc as *mut _ as c_ulong) };
prctl( let n = check_out(rc)?;
KSU_OPTIONS, println!("{n}");
SUKISU_KPM_NUM,
0,
0,
&mut out as *mut c_int as c_ulong,
);
}
let n = check_out(out)?;
println!("{}", n);
Ok(n) Ok(n)
} }
/// Print name list of loaded modules.
pub fn kpm_list() -> Result<()> { pub fn kpm_list() -> Result<()> {
let mut buf = vec![0u8; 1024]; let mut buf = vec![0u8; 1024];
let mut out: c_int = -1; let mut rc = -1;
unsafe { unsafe {
prctl( prctl(
KSU_OPTIONS, KSU_OPTIONS,
SUKISU_KPM_LIST, SUKISU_KPM_LIST,
buf.as_mut_ptr() as c_ulong, buf.as_mut_ptr() as c_ulong,
buf.len() as c_ulong, buf.len() as c_ulong,
&mut out as *mut c_int as c_ulong, &mut rc as *mut _ as c_ulong,
); );
} }
check_out(out)?; check_out(rc)?;
print!("{}", buf2string(&buf)); print!("{}", buf2str(&buf));
Ok(()) Ok(())
} }
/// Print single module info.
pub fn kpm_info(name: &str) -> Result<()> { pub fn kpm_info(name: &str) -> Result<()> {
let name_c = CString::new(name)?; let name_c = CString::new(name)?;
let mut buf = vec![0u8; 256]; let mut buf = vec![0u8; 256];
let mut out: c_int = -1; let mut rc = -1;
unsafe { unsafe {
prctl( prctl(
KSU_OPTIONS, KSU_OPTIONS,
SUKISU_KPM_INFO, SUKISU_KPM_INFO,
name_c.as_ptr() as c_ulong, name_c.as_ptr() as c_ulong,
buf.as_mut_ptr() as c_ulong, buf.as_mut_ptr() as c_ulong,
&mut out as *mut c_int as c_ulong, &mut rc as *mut _ as c_ulong,
); );
} }
check_out(out)?; check_out(rc)?;
println!("{}", buf2string(&buf)); println!("{}", buf2str(&buf));
Ok(()) Ok(())
} }
/// Send control string to a module; returns kernel answer.
pub fn kpm_control(name: &str, args: &str) -> Result<i32> { pub fn kpm_control(name: &str, args: &str) -> Result<i32> {
let name_c = CString::new(name)?; let name_c = CString::new(name)?;
let args_c = CString::new(args)?; let args_c = CString::new(args)?;
let mut out: c_int = -1; let mut rc = -1;
unsafe { unsafe {
prctl( prctl(
KSU_OPTIONS, KSU_OPTIONS,
SUKISU_KPM_CONTROL, SUKISU_KPM_CONTROL,
name_c.as_ptr() as c_ulong, name_c.as_ptr() as c_ulong,
args_c.as_ptr() as c_ulong, args_c.as_ptr() as c_ulong,
&mut out as *mut c_int as c_ulong, &mut rc as *mut _ as c_ulong,
); );
} }
check_out(out)?; check_out(rc).map(|v| v as i32)
Ok(out)
} }
/// Print loader version string.
pub fn kpm_version_loader() -> Result<()> { pub fn kpm_version_loader() -> Result<()> {
let mut buf = vec![0u8; 1024]; let mut buf = vec![0u8; 1024];
let mut out: c_int = -1; let mut rc = -1;
unsafe { unsafe {
prctl( prctl(
KSU_OPTIONS, KSU_OPTIONS,
SUKISU_KPM_VERSION, SUKISU_KPM_VERSION,
buf.as_mut_ptr() as c_ulong, buf.as_mut_ptr() as c_ulong,
buf.len() as c_ulong, buf.len() as c_ulong,
&mut out as *mut c_int as c_ulong, &mut rc as *mut _ as c_ulong,
); );
} }
check_out(out)?; check_out(rc)?;
print!("{}", buf2string(&buf)); print!("{}", buf2str(&buf));
Ok(()) Ok(())
} }
/// Validate loader version; empty or "Error*" => fail.
pub fn check_kpm_version() -> Result<String> { pub fn check_kpm_version() -> Result<String> {
let mut buf = vec![0u8; 1024]; let mut buf = vec![0u8; 1024];
let mut out: c_int = -1; let mut rc = -1;
unsafe { unsafe {
prctl( prctl(
KSU_OPTIONS, KSU_OPTIONS,
SUKISU_KPM_VERSION, SUKISU_KPM_VERSION,
buf.as_mut_ptr() as c_ulong, buf.as_mut_ptr() as c_ulong,
buf.len() as c_ulong, buf.len() as c_ulong,
&mut out as *mut c_int as c_ulong, &mut rc as *mut _ as c_ulong,
); );
} }
check_out(out)?; check_out(rc)?;
let ver = buf2string(&buf); let ver = buf2str(&buf);
if ver.is_empty() || ver.starts_with("Error") { if ver.is_empty() || ver.starts_with("Error") {
bail!("KPM: Invalid version response: {}", ver); bail!("KPM: invalid version response: {ver}");
} }
log::info!("KPM: Version check result: {}", ver); log::info!("KPM: version check ok: {ver}");
Ok(ver) Ok(ver)
} }
/// Create `/data/adb/kpm` with 0o777 if missing.
pub fn ensure_kpm_dir() -> Result<()> { pub fn ensure_kpm_dir() -> Result<()> {
let path = Path::new(KPM_DIR); fs::create_dir_all(KPM_DIR)?;
if !path.exists() { let meta = fs::metadata(KPM_DIR)?;
fs::create_dir_all(path)?;
}
let meta = fs::metadata(path)?;
if meta.permissions().mode() & 0o777 != 0o777 { if meta.permissions().mode() & 0o777 != 0o777 {
fs::set_permissions(path, fs::Permissions::from_mode(0o777))?; fs::set_permissions(KPM_DIR, fs::Permissions::from_mode(0o777))?;
} }
Ok(()) Ok(())
} }
/// Start file watcher for hot-(un)load.
pub fn start_kpm_watcher() -> Result<()> { pub fn start_kpm_watcher() -> Result<()> {
check_kpm_version()?; // 版本不对直接返回 check_kpm_version()?; // bails if loader too old
ensure_kpm_dir()?; ensure_kpm_dir()?;
if crate::utils::is_safe_mode() { if crate::utils::is_safe_mode() {
log::warn!("KPM: Safe mode removing all KPM modules"); log::warn!("KPM: safe-mode removing all modules");
remove_all_kpms()?; remove_all_kpms()?;
return Ok(()); return Ok(());
} }
let mut watcher = notify::recommended_watcher(|res| match res { let mut watcher = notify::recommended_watcher(|res: Result<_, _>| match res {
Ok(event) => handle_kpm_event(event), Ok(evt) => handle_kpm_event(evt),
Err(e) => log::error!("KPM: File monitor error: {:?}", e), Err(e) => log::error!("KPM: watcher error: {e:?}"),
})?; })?;
watcher.watch(Path::new(KPM_DIR), RecursiveMode::NonRecursive)?; watcher.watch(Path::new(KPM_DIR), RecursiveMode::NonRecursive)?;
log::info!("KPM: File watcher started on {}", KPM_DIR); log::info!("KPM: watcher active on {KPM_DIR}");
Ok(()) Ok(())
} }
fn handle_kpm_event(event: notify::Event) { fn handle_kpm_event(evt: notify::Event) {
match event.kind { if let notify::EventKind::Create(_) = evt.kind {
notify::EventKind::Create(_) => { for p in evt.paths {
for p in event.paths { if p.extension() == Some(OsStr::new("kpm")) && load_kpm(&p).is_err() {
if p.extension() == Some(OsStr::new("kpm")) { log::warn!("KPM: failed to load {}", p.display());
if let Err(e) = load_kpm(&p) {
log::warn!("KPM: Failed to load {}: {}", p.display(), e);
}
}
} }
} }
notify::EventKind::Modify(_) => {
for p in event.paths {
log::info!("KPM: Modified file: {}", p.display());
}
}
_ => {}
} }
} }
/// Load single `.kpm` file.
pub fn load_kpm(path: &Path) -> Result<()> { pub fn load_kpm(path: &Path) -> Result<()> {
let path_str = path.to_str().ok_or_else(|| anyhow!("Invalid path"))?; let s = path.to_str().ok_or_else(|| anyhow!("bad path"))?;
kpm_load(path_str, None) kpm_load(s, None)
} }
/// Unload module and delete file.
pub fn unload_kpm(name: &str) -> Result<()> { pub fn unload_kpm(name: &str) -> Result<()> {
kpm_unload(name)?; kpm_unload(name)?;
if let Some(p) = find_kpm_file(name)? { if let Some(p) = find_kpm_file(name)? {
fs::remove_file(&p).ok(); let _ = fs::remove_file(&p);
log::info!("KPM: Deleted file {}", p.display()); log::info!("KPM: deleted {}", p.display());
} }
Ok(()) Ok(())
} }
/// Locate `/data/adb/kpm/<name>.kpm`.
fn find_kpm_file(name: &str) -> Result<Option<PathBuf>> { fn find_kpm_file(name: &str) -> Result<Option<PathBuf>> {
let dir = Path::new(KPM_DIR); let dir = Path::new(KPM_DIR);
if !dir.exists() { if !dir.is_dir() {
return Ok(None); return Ok(None);
} }
for entry in fs::read_dir(dir)? { for entry in fs::read_dir(dir)? {
let p = entry?.path(); let p = entry?.path();
if p.extension() == Some(OsStr::new("kpm")) if p.extension() == Some(OsStr::new("kpm")) && p.file_stem() == Some(OsStr::new(name)) {
&& p.file_stem().map_or(false, |s| s == name)
{
return Ok(Some(p)); return Ok(Some(p));
} }
} }
Ok(None) Ok(None)
} }
/// Remove every `.kpm` file and unload it.
pub fn remove_all_kpms() -> Result<()> { pub fn remove_all_kpms() -> Result<()> {
let dir = Path::new(KPM_DIR); let dir = Path::new(KPM_DIR);
if !dir.exists() { if !dir.is_dir() {
return Ok(()); return Ok(());
} }
for entry in fs::read_dir(dir)? { for entry in fs::read_dir(dir)? {
@@ -258,7 +246,7 @@ pub fn remove_all_kpms() -> Result<()> {
if p.extension() == Some(OsStr::new("kpm")) { if p.extension() == Some(OsStr::new("kpm")) {
if let Some(name) = p.file_stem().and_then(|s| s.to_str()) { if let Some(name) = p.file_stem().and_then(|s| s.to_str()) {
if let Err(e) = unload_kpm(name) { if let Err(e) = unload_kpm(name) {
log::error!("KPM: Failed to unload {}: {}", name, e); log::error!("KPM: unload {name} failed: {e}");
} }
} }
} }
@@ -266,11 +254,12 @@ pub fn remove_all_kpms() -> Result<()> {
Ok(()) Ok(())
} }
/// Bulk-load existing `.kpm`s at boot.
pub fn load_kpm_modules() -> Result<()> { pub fn load_kpm_modules() -> Result<()> {
check_kpm_version()?; check_kpm_version()?;
ensure_kpm_dir()?; ensure_kpm_dir()?;
let dir = Path::new(KPM_DIR); let dir = Path::new(KPM_DIR);
if !dir.exists() { if !dir.is_dir() {
return Ok(()); return Ok(());
} }
let (mut ok, mut ng) = (0, 0); let (mut ok, mut ng) = (0, 0);
@@ -280,20 +269,18 @@ pub fn load_kpm_modules() -> Result<()> {
match load_kpm(&p) { match load_kpm(&p) {
Ok(_) => ok += 1, Ok(_) => ok += 1,
Err(e) => { Err(e) => {
log::warn!("KPM: Failed to load {}: {}", p.display(), e); log::warn!("KPM: load {} failed: {e}", p.display());
ng += 1; ng += 1;
} }
} }
} }
} }
log::info!("KPM: Load done ok: {}, failed: {}", ok, ng); log::info!("KPM: bulk-load done ok: {ok}, failed: {ng}");
Ok(()) Ok(())
} }
fn buf2string(buf: &[u8]) -> String { /// Convert zero-padded kernel buffer to owned String.
unsafe { fn buf2str(buf: &[u8]) -> String {
std::ffi::CStr::from_ptr(buf.as_ptr() as *const _) // SAFETY: buffer is always NUL-terminated by kernel.
.to_string_lossy() unsafe { CStr::from_ptr(buf.as_ptr().cast()).to_string_lossy().into_owned() }
.into_owned()
}
} }