Files
ZygiskNext/zygiskd/src/utils.rs
2023-10-20 23:27:40 +08:00

161 lines
4.5 KiB
Rust

use anyhow::Result;
use std::{fs, io::{Read, Write}, os::unix::net::UnixStream};
use std::ffi::{c_char, CStr, CString};
use std::os::unix::net::UnixListener;
use std::process::Command;
use std::sync::OnceLock;
use rustix::net::{AddressFamily, bind_unix, listen, socket, SocketAddrUnix, SocketType};
use rustix::thread::gettid;
#[cfg(debug_assertions)]
#[macro_export]
macro_rules! debug_select {
($debug:expr, $release:expr) => { $debug };
}
#[cfg(not(debug_assertions))]
#[macro_export]
macro_rules! debug_select {
($debug:expr, $release:expr) => { $release };
}
pub struct LateInit<T> {
cell: OnceLock<T>,
}
impl<T> LateInit<T> {
pub const fn new() -> Self {
LateInit { cell: OnceLock::new() }
}
pub fn init(&self, value: T) {
assert!(self.cell.set(value).is_ok())
}
}
impl<T> std::ops::Deref for LateInit<T> {
type Target = T;
fn deref(&self) -> &T {
self.cell.get().unwrap()
}
}
pub fn set_socket_create_context(context: &str) -> Result<()> {
let path = "/proc/thread-self/attr/sockcreate";
match fs::write(path, context) {
Ok(_) => Ok(()),
Err(_) => {
let path = format!("/proc/self/task/{}/attr/sockcreate", gettid().as_raw_nonzero());
fs::write(path, context)?;
Ok(())
}
}
}
pub fn chcon(path: &str, context: &str) -> Result<()> {
Command::new("chcon").arg(context).arg(path).status()?;
Ok(())
}
pub fn log_raw(level: i32, tag: &str, message: &str) -> Result<()> {
let tag = CString::new(tag)?;
let message = CString::new(message)?;
unsafe {
__android_log_print(level, tag.as_ptr(), message.as_ptr());
}
Ok(())
}
pub fn get_property(name: &str) -> Result<String> {
let name = CString::new(name)?;
let mut buf = vec![0u8; 92];
let prop = unsafe {
__system_property_get(name.as_ptr(), buf.as_mut_ptr() as *mut c_char);
CStr::from_bytes_until_nul(&buf)?
};
Ok(prop.to_string_lossy().to_string())
}
pub fn set_property(name: &str, value: &str) -> Result<()> {
let name = CString::new(name)?;
let value = CString::new(value)?;
unsafe {
__system_property_set(name.as_ptr(), value.as_ptr());
}
Ok(())
}
pub trait UnixStreamExt {
fn read_u8(&mut self) -> Result<u8>;
fn read_u32(&mut self) -> Result<u32>;
fn read_usize(&mut self) -> Result<usize>;
fn read_string(&mut self) -> Result<String>;
fn write_u8(&mut self, value: u8) -> Result<()>;
fn write_u32(&mut self, value: u32) -> Result<()>;
fn write_usize(&mut self, value: usize) -> Result<()>;
fn write_string(&mut self, value: &str) -> Result<()>;
}
impl UnixStreamExt for UnixStream {
fn read_u8(&mut self) -> Result<u8> {
let mut buf = [0u8; 1];
self.read_exact(&mut buf)?;
Ok(buf[0])
}
fn read_u32(&mut self) -> Result<u32> {
let mut buf = [0u8; 4];
self.read_exact(&mut buf)?;
Ok(u32::from_ne_bytes(buf))
}
fn read_usize(&mut self) -> Result<usize> {
let mut buf = [0u8; std::mem::size_of::<usize>()];
self.read_exact(&mut buf)?;
Ok(usize::from_ne_bytes(buf))
}
fn read_string(&mut self) -> Result<String> {
let len = self.read_usize()?;
let mut buf = vec![0u8; len];
self.read_exact(&mut buf)?;
Ok(String::from_utf8(buf)?)
}
fn write_u8(&mut self, value: u8) -> Result<()> {
self.write_all(&value.to_ne_bytes())?;
Ok(())
}
fn write_u32(&mut self, value: u32) -> Result<()> {
self.write_all(&value.to_ne_bytes())?;
Ok(())
}
fn write_usize(&mut self, value: usize) -> Result<()> {
self.write_all(&value.to_ne_bytes())?;
Ok(())
}
fn write_string(&mut self, value: &str) -> Result<()> {
self.write_usize(value.len())?;
self.write_all(value.as_bytes())?;
Ok(())
}
}
pub fn unix_listener_from_path(path: &str) -> Result<UnixListener> {
let _ = fs::remove_file(path);
let addr = SocketAddrUnix::new(path)?;
let socket = socket(AddressFamily::UNIX, SocketType::STREAM, None)?;
bind_unix(&socket, &addr)?;
listen(&socket, 2)?;
chcon(path, "u:object_r:magisk_file:s0")?;
Ok(UnixListener::from(socket))
}
extern "C" {
fn __android_log_print(prio: i32, tag: *const c_char, fmt: *const c_char, ...) -> i32;
fn __system_property_get(name: *const c_char, value: *mut c_char) -> u32;
fn __system_property_set(name: *const c_char, value: *const c_char) -> u32;
}