use anyhow::{Ok, Result}; use clap::Parser; use std::path::{Path, PathBuf}; #[cfg(target_os = "android")] use android_logger::Config; #[cfg(target_os = "android")] use log::LevelFilter; use crate::{ apk_sign, assets, debug, defs, defs::KSUD_VERBOSE_LOG_FILE, init_event, ksucalls, module, utils, }; /// KernelSU userspace cli #[derive(Parser, Debug)] #[command(author, version = defs::VERSION_NAME, about, long_about = None)] struct Args { #[command(subcommand)] command: Commands, #[arg(short, long, default_value_t = cfg!(debug_assertions))] verbose: bool, } #[derive(clap::Subcommand, Debug)] enum Commands { /// Manage KernelSU modules Module { #[command(subcommand)] command: Module, }, /// Trigger `post-fs-data` event PostFsData, /// Trigger `service` event Services, /// Trigger `boot-complete` event BootCompleted, /// Install KernelSU userspace component to system Install { #[arg(long, default_value = None)] magiskboot: Option, }, /// Uninstall KernelSU modules and itself(LKM Only) Uninstall { /// magiskboot path, if not specified, will search from $PATH #[arg(long, default_value = None)] magiskboot: Option, }, /// SELinux policy Patch tool Sepolicy { #[command(subcommand)] command: Sepolicy, }, /// Manage App Profiles Profile { #[command(subcommand)] command: Profile, }, /// Manage kernel features Feature { #[command(subcommand)] command: Feature, }, /// Patch boot or init_boot images to apply KernelSU BootPatch { /// boot image path, if not specified, will try to find the boot image automatically #[arg(short, long)] boot: Option, /// kernel image path to replace #[arg(short, long)] kernel: Option, /// LKM module path to replace, if not specified, will use the builtin one #[arg(short, long)] module: Option, /// init to be replaced #[arg(short, long, requires("module"))] init: Option, /// will use another slot when boot image is not specified #[arg(short = 'u', long, default_value = "false")] ota: bool, /// Flash it to boot partition after patch #[arg(short, long, default_value = "false")] flash: bool, /// output path, if not specified, will use current directory #[arg(short, long, default_value = None)] out: Option, /// magiskboot path, if not specified, will search from $PATH #[arg(long, default_value = None)] magiskboot: Option, /// KMI version, if specified, will use the specified KMI #[arg(long, default_value = None)] kmi: Option, /// target partition override (init_boot | boot | vendor_boot) #[arg(long, default_value = None)] partition: Option, }, /// Restore boot or init_boot images patched by KernelSU BootRestore { /// boot image path, if not specified, will try to find the boot image automatically #[arg(short, long)] boot: Option, /// Flash it to boot partition after patch #[arg(short, long, default_value = "false")] flash: bool, /// magiskboot path, if not specified, will search from $PATH #[arg(long, default_value = None)] magiskboot: Option, }, /// Show boot information BootInfo { #[command(subcommand)] command: BootInfo, }, /// KPM module manager #[cfg(target_arch = "aarch64")] Kpm { #[command(subcommand)] command: kpm_cmd::Kpm, }, /// Manage kernel umount paths Umount { #[command(subcommand)] command: Umount, }, /// For developers Debug { #[command(subcommand)] command: Debug, }, /// Kernel interface Kernel { #[command(subcommand)] command: Kernel, }, } #[derive(clap::Subcommand, Debug)] enum BootInfo { /// show current kmi version CurrentKmi, /// show supported kmi versions SupportedKmis, /// check if device is A/B capable IsAbDevice, /// show auto-selected boot partition name DefaultPartition, /// list available partitions for current or OTA toggled slot AvailablePartitions, /// show slot suffix for current or OTA toggled slot SlotSuffix { /// toggle to another slot #[arg(short = 'u', long, default_value = "false")] ota: bool, }, } #[derive(clap::Subcommand, Debug)] enum Debug { /// Set the manager app, kernel CONFIG_KSU_DEBUG should be enabled. SetManager { /// manager package name #[arg(default_value_t = String::from("me.weishu.kernelsu"))] apk: String, }, /// Get apk size and hash GetSign { /// apk path apk: String, }, /// Root Shell Su { /// switch to gloabl mount namespace #[arg(short, long, default_value = "false")] global_mnt: bool, }, /// Get kernel version Version, Mount, /// For testing Test, /// Process mark management Mark { #[command(subcommand)] command: MarkCommand, }, } #[derive(clap::Subcommand, Debug)] enum MarkCommand { /// Get mark status for a process (or all) Get { /// target pid (0 for total count) #[arg(default_value = "0")] pid: i32, }, /// Mark a process Mark { /// target pid (0 for all processes) #[arg(default_value = "0")] pid: i32, }, /// Unmark a process Unmark { /// target pid (0 for all processes) #[arg(default_value = "0")] pid: i32, }, /// Refresh mark for all running processes Refresh, } #[derive(clap::Subcommand, Debug)] enum Sepolicy { /// Patch sepolicy Patch { /// sepolicy statements sepolicy: String, }, /// Apply sepolicy from file Apply { /// sepolicy file path file: String, }, /// Check if sepolicy statement is supported/valid Check { /// sepolicy statements sepolicy: String, }, } #[derive(clap::Subcommand, Debug)] enum Module { /// Install module Install { /// module zip file path zip: String, }, /// Uninstall module Uninstall { /// module id id: String, }, /// Restore module Restore { /// module id id: String, }, /// enable module Enable { /// module id id: String, }, /// disable module Disable { // module id id: String, }, /// run action for module Action { // module id id: String, }, /// list all modules List, } #[derive(clap::Subcommand, Debug)] enum Profile { /// get root profile's selinux policy of GetSepolicy { /// package name package: String, }, /// set root profile's selinux policy of to SetSepolicy { /// package name package: String, /// policy statements policy: String, }, /// get template of GetTemplate { /// template id id: String, }, /// set template of to