mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-08-25 18:28:01 +00:00
Consolidate for_each implementation into Rust
This commit is contained in:
@@ -1,15 +1,20 @@
|
||||
// Functions in this file are only for exporting to C++, DO NOT USE IN RUST
|
||||
|
||||
use std::os::fd::{BorrowedFd, OwnedFd, RawFd};
|
||||
use std::fs::File;
|
||||
use std::io::BufReader;
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::ops::DerefMut;
|
||||
use std::os::fd::{BorrowedFd, FromRawFd, OwnedFd, RawFd};
|
||||
|
||||
use cfg_if::cfg_if;
|
||||
use libc::{c_char, mode_t};
|
||||
use libc::{O_RDONLY, c_char, mode_t};
|
||||
|
||||
use crate::ffi::{FnBoolStrStr, FnBoolString};
|
||||
use crate::files::map_file_at;
|
||||
pub(crate) use crate::xwrap::*;
|
||||
use crate::{
|
||||
CxxResultExt, Directory, OsResultStatic, Utf8CStr, clone_attr, cstr, fclone_attr, fd_path,
|
||||
map_fd, map_file, slice_from_ptr,
|
||||
BufReadExt, CxxResultExt, Directory, OsResultStatic, Utf8CStr, clone_attr, cstr, fclone_attr,
|
||||
fd_path, map_fd, map_file, slice_from_ptr,
|
||||
};
|
||||
|
||||
pub(crate) fn fd_path_for_cxx(fd: RawFd, buf: &mut [u8]) -> isize {
|
||||
@@ -178,3 +183,14 @@ unsafe extern "C" fn str_ptr(this: &&Utf8CStr) -> *const u8 {
|
||||
unsafe extern "C" fn str_len(this: &&Utf8CStr) -> usize {
|
||||
this.len()
|
||||
}
|
||||
|
||||
pub(crate) fn parse_prop_file_rs(name: &Utf8CStr, f: &FnBoolStrStr) {
|
||||
if let Ok(file) = name.open(O_RDONLY) {
|
||||
BufReader::new(file).for_each_prop(|key, value| f.call(key, value))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn file_readline_rs(fd: RawFd, f: &FnBoolString) {
|
||||
let mut fd = ManuallyDrop::new(unsafe { File::from_raw_fd(fd) });
|
||||
BufReader::new(fd.deref_mut()).for_each_line(|line| f.call(line));
|
||||
}
|
||||
|
@@ -8,15 +8,6 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
int fd_pathat(int dirfd, const char *name, char *path, size_t size) {
|
||||
if (fd_path(dirfd, byte_data(path, size)) < 0)
|
||||
return -1;
|
||||
auto len = strlen(path);
|
||||
path[len] = '/';
|
||||
strscpy(path + len + 1, name, size - len - 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void full_read(int fd, string &str) {
|
||||
char buf[4096];
|
||||
for (ssize_t len; (len = xread(fd, buf, sizeof(buf))) > 0;)
|
||||
@@ -52,53 +43,6 @@ void write_zero(int fd, size_t size) {
|
||||
}
|
||||
}
|
||||
|
||||
void file_readline(bool trim, FILE *fp, const function<bool(string_view)> &fn) {
|
||||
size_t len = 1024;
|
||||
char *buf = (char *) malloc(len);
|
||||
char *start;
|
||||
ssize_t read;
|
||||
while ((read = getline(&buf, &len, fp)) >= 0) {
|
||||
start = buf;
|
||||
if (trim) {
|
||||
while (read && "\n\r "sv.find(buf[read - 1]) != string::npos)
|
||||
--read;
|
||||
buf[read] = '\0';
|
||||
while (*start == ' ')
|
||||
++start;
|
||||
}
|
||||
if (!fn(start))
|
||||
break;
|
||||
}
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void file_readline(bool trim, const char *file, const function<bool(string_view)> &fn) {
|
||||
if (auto fp = open_file(file, "re"))
|
||||
file_readline(trim, fp.get(), fn);
|
||||
}
|
||||
|
||||
void file_readline(const char *file, const function<bool(string_view)> &fn) {
|
||||
file_readline(false, file, fn);
|
||||
}
|
||||
|
||||
void parse_prop_file(FILE *fp, const function<bool(string_view, string_view)> &fn) {
|
||||
file_readline(true, fp, [&](string_view line_view) -> bool {
|
||||
char *line = (char *) line_view.data();
|
||||
if (line[0] == '#')
|
||||
return true;
|
||||
char *eql = strchr(line, '=');
|
||||
if (eql == nullptr || eql == line)
|
||||
return true;
|
||||
*eql = '\0';
|
||||
return fn(line, eql + 1);
|
||||
});
|
||||
}
|
||||
|
||||
void parse_prop_file(const char *file, const function<bool(string_view, string_view)> &fn) {
|
||||
if (auto fp = open_file(file, "re"))
|
||||
parse_prop_file(fp.get(), fn);
|
||||
}
|
||||
|
||||
sDIR make_dir(DIR *dp) {
|
||||
return sDIR(dp, [](DIR *dp){ return dp ? closedir(dp) : 1; });
|
||||
}
|
||||
|
@@ -45,7 +45,6 @@ bool fclone_attr(int src, int dest);
|
||||
|
||||
} // extern "C"
|
||||
|
||||
int fd_pathat(int dirfd, const char *name, char *path, size_t size);
|
||||
static inline ssize_t realpath(
|
||||
const char * __restrict__ path, char * __restrict__ buf, size_t bufsiz) {
|
||||
return canonical_path(path, buf, bufsiz);
|
||||
@@ -55,14 +54,27 @@ void full_read(const char *filename, std::string &str);
|
||||
std::string full_read(int fd);
|
||||
std::string full_read(const char *filename);
|
||||
void write_zero(int fd, size_t size);
|
||||
void file_readline(bool trim, FILE *fp, const std::function<bool(std::string_view)> &fn);
|
||||
void file_readline(bool trim, const char *file, const std::function<bool(std::string_view)> &fn);
|
||||
void file_readline(const char *file, const std::function<bool(std::string_view)> &fn);
|
||||
void parse_prop_file(FILE *fp, const std::function<bool(std::string_view, std::string_view)> &fn);
|
||||
void parse_prop_file(const char *file,
|
||||
const std::function<bool(std::string_view, std::string_view)> &fn);
|
||||
std::string resolve_preinit_dir(const char *base_dir);
|
||||
|
||||
// Functor = function<bool(string_view)>
|
||||
template <typename Functor>
|
||||
void file_readline(int fd, Functor &&fn) {
|
||||
file_readline_rs(fd, [&](rust::String &line) -> bool {
|
||||
return fn(std::string_view(line.c_str(), line.size()));
|
||||
});
|
||||
}
|
||||
|
||||
// Functor = function<bool(string_view, string_view)>
|
||||
template <typename Functor>
|
||||
void parse_prop_file(const char *file, Functor &&fn) {
|
||||
parse_prop_file_rs(file, [&](rust::Str key, rust::Str val) -> bool {
|
||||
// Null terminate all strings
|
||||
*(const_cast<char *>(key.data()) + key.size()) = '\0';
|
||||
*(const_cast<char *>(val.data()) + val.size()) = '\0';
|
||||
return fn(std::string_view(key.data(), key.size()), std::string_view(val.data(), val.size()));
|
||||
});
|
||||
}
|
||||
|
||||
using sFILE = std::unique_ptr<FILE, decltype(&fclose)>;
|
||||
using sDIR = std::unique_ptr<DIR, decltype(&closedir)>;
|
||||
sDIR make_dir(DIR *dp);
|
||||
|
@@ -57,12 +57,12 @@ impl<T: Read + Seek> ReadSeekExt for T {
|
||||
}
|
||||
|
||||
pub trait BufReadExt {
|
||||
fn foreach_lines<F: FnMut(&mut String) -> bool>(&mut self, f: F);
|
||||
fn foreach_props<F: FnMut(&str, &str) -> bool>(&mut self, f: F);
|
||||
fn for_each_line<F: FnMut(&mut String) -> bool>(&mut self, f: F);
|
||||
fn for_each_prop<F: FnMut(&str, &str) -> bool>(&mut self, f: F);
|
||||
}
|
||||
|
||||
impl<T: BufRead> BufReadExt for T {
|
||||
fn foreach_lines<F: FnMut(&mut String) -> bool>(&mut self, mut f: F) {
|
||||
fn for_each_line<F: FnMut(&mut String) -> bool>(&mut self, mut f: F) {
|
||||
let mut buf = String::new();
|
||||
loop {
|
||||
match self.read_line(&mut buf) {
|
||||
@@ -81,8 +81,11 @@ impl<T: BufRead> BufReadExt for T {
|
||||
}
|
||||
}
|
||||
|
||||
fn foreach_props<F: FnMut(&str, &str) -> bool>(&mut self, mut f: F) {
|
||||
self.foreach_lines(|line| {
|
||||
fn for_each_prop<F: FnMut(&str, &str) -> bool>(&mut self, mut f: F) {
|
||||
self.for_each_line(|line| {
|
||||
// Reserve an additional byte, because this string will be manually
|
||||
// null terminated on the C++ side, and it may need more space.
|
||||
line.reserve(1);
|
||||
let line = line.trim();
|
||||
if line.starts_with('#') {
|
||||
return true;
|
||||
@@ -874,7 +877,7 @@ pub fn parse_mount_info(pid: &str) -> Vec<MountInfo> {
|
||||
let mut res = vec![];
|
||||
let mut path = format!("/proc/{pid}/mountinfo");
|
||||
if let Ok(file) = Utf8CStr::from_string(&mut path).open(O_RDONLY | O_CLOEXEC) {
|
||||
BufReader::new(file).foreach_lines(|line| {
|
||||
BufReader::new(file).for_each_line(|line| {
|
||||
parse_mount_info_line(line)
|
||||
.map(|info| res.push(info))
|
||||
.is_some()
|
||||
|
@@ -47,6 +47,12 @@ pub mod ffi {
|
||||
|
||||
fn mut_u8_patch(buf: &mut [u8], from: &[u8], to: &[u8]) -> Vec<usize>;
|
||||
fn fork_dont_care() -> i32;
|
||||
|
||||
type FnBoolStrStr;
|
||||
fn call(self: &FnBoolStrStr, key: &str, value: &str) -> bool;
|
||||
|
||||
type FnBoolString;
|
||||
fn call(self: &FnBoolString, key: &mut String) -> bool;
|
||||
}
|
||||
|
||||
extern "Rust" {
|
||||
@@ -56,6 +62,8 @@ pub mod ffi {
|
||||
fn set_log_level_state_cxx(level: LogLevelCxx, enabled: bool);
|
||||
fn exit_on_error(b: bool);
|
||||
fn cmdline_logging();
|
||||
fn parse_prop_file_rs(name: Utf8CStrRef, f: &FnBoolStrStr);
|
||||
fn file_readline_rs(fd: i32, f: &FnBoolString);
|
||||
}
|
||||
|
||||
#[namespace = "rust"]
|
||||
|
@@ -283,7 +283,8 @@ struct Utf8CStr {
|
||||
const char *c_str() const { return this->data(); }
|
||||
size_t size() const { return this->length(); }
|
||||
bool empty() const { return this->length() == 0 ; }
|
||||
operator std::string_view() { return {data(), length()}; }
|
||||
operator std::string_view() const { return {data(), length()}; }
|
||||
bool operator==(std::string_view rhs) const { return std::string_view{data(), length()} == rhs; }
|
||||
|
||||
private:
|
||||
#pragma clang diagnostic push
|
||||
@@ -293,3 +294,18 @@ private:
|
||||
};
|
||||
|
||||
} // namespace rust
|
||||
|
||||
// Bindings for std::function to be callable from Rust
|
||||
struct FnBoolStrStr : public std::function<bool(rust::Str, rust::Str)> {
|
||||
using std::function<bool(rust::Str, rust::Str)>::function;
|
||||
bool call(rust::Str a, rust::Str b) const {
|
||||
return operator()(a, b);
|
||||
}
|
||||
};
|
||||
|
||||
struct FnBoolString : public std::function<bool(rust::String&)> {
|
||||
using std::function<bool(rust::String&)>::function;
|
||||
bool call(rust::String &s) const {
|
||||
return operator()(s);
|
||||
}
|
||||
};
|
@@ -243,7 +243,7 @@ pub fn daemon_entry() {
|
||||
.join_path(MAIN_CONFIG);
|
||||
let mut is_recovery = false;
|
||||
if let Ok(main_config) = tmp_path.open(O_RDONLY | O_CLOEXEC) {
|
||||
BufReader::new(main_config).foreach_props(|key, val| {
|
||||
BufReader::new(main_config).for_each_prop(|key, val| {
|
||||
if key == "RECOVERYMODE" {
|
||||
is_recovery = val == "true";
|
||||
return false;
|
||||
@@ -255,7 +255,7 @@ pub fn daemon_entry() {
|
||||
|
||||
let mut sdk_int = -1;
|
||||
if let Ok(build_prop) = cstr!("/system/build.prop").open(O_RDONLY | O_CLOEXEC) {
|
||||
BufReader::new(build_prop).foreach_props(|key, val| {
|
||||
BufReader::new(build_prop).for_each_prop(|key, val| {
|
||||
if key == "ro.build.version.sdk" {
|
||||
sdk_int = val.parse::<i32>().unwrap_or(-1);
|
||||
return false;
|
||||
@@ -290,7 +290,7 @@ pub fn daemon_entry() {
|
||||
// Cleanup pre-init mounts
|
||||
tmp_path.append_path(ROOTMNT);
|
||||
if let Ok(mount_list) = tmp_path.open(O_RDONLY | O_CLOEXEC) {
|
||||
BufReader::new(mount_list).foreach_lines(|line| {
|
||||
BufReader::new(mount_list).for_each_line(|line| {
|
||||
line.truncate(line.trim_end().len());
|
||||
let item = Utf8CStr::from_string(line);
|
||||
item.unmount().log_ok();
|
||||
@@ -336,7 +336,7 @@ fn switch_cgroup(cgroup: &str, pid: i32) {
|
||||
fn check_data() -> bool {
|
||||
if let Ok(file) = cstr!("/proc/mounts").open(O_RDONLY | O_CLOEXEC) {
|
||||
let mut mnt = false;
|
||||
BufReader::new(file).foreach_lines(|line| {
|
||||
BufReader::new(file).for_each_line(|line| {
|
||||
if line.contains(" /data ") && !line.contains("tmpfs") {
|
||||
mnt = true;
|
||||
return false;
|
||||
|
@@ -88,7 +88,7 @@ fn read_certificate(apk: &mut File, version: i32) -> Vec<u8> {
|
||||
apk.read_exact(&mut comment)?;
|
||||
let mut comment = Cursor::new(&comment);
|
||||
let mut apk_ver = 0;
|
||||
comment.foreach_props(|k, v| {
|
||||
comment.for_each_prop(|k, v| {
|
||||
if k == "versionCode" {
|
||||
apk_ver = v.parse::<i32>().unwrap_or(0);
|
||||
false
|
||||
|
@@ -300,7 +300,8 @@ static bool proc_is_restricted(pid_t pid) {
|
||||
auto bnd = "CapBnd:"sv;
|
||||
uint32_t data[_LINUX_CAPABILITY_U32S_3] = {};
|
||||
ssprintf(buf, sizeof(buf), "/proc/%d/status", pid);
|
||||
file_readline(buf, [&](string_view line) -> bool {
|
||||
owned_fd status_fd = xopen(buf, O_RDONLY | O_CLOEXEC);
|
||||
file_readline(status_fd, [&](string_view line) -> bool {
|
||||
if (line.starts_with(bnd)) {
|
||||
auto p = line.begin();
|
||||
advance(p, bnd.size());
|
||||
|
@@ -60,14 +60,14 @@ static bool patch_rc_scripts(const char *src_path, const char *tmp_path, bool wr
|
||||
|
||||
// First patch init.rc
|
||||
{
|
||||
auto src = xopen_file(xopenat(src_fd, INIT_RC, O_RDONLY | O_CLOEXEC, 0), "re");
|
||||
if (!src) return false;
|
||||
owned_fd src_rc = xopenat(src_fd, INIT_RC, O_RDONLY | O_CLOEXEC, 0);
|
||||
if (src_rc < 0) return false;
|
||||
if (writable) unlinkat(src_fd, INIT_RC, 0);
|
||||
auto dest = xopen_file(
|
||||
auto dest_rc = xopen_file(
|
||||
xopenat(dest_fd, INIT_RC, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0), "we");
|
||||
if (!dest) return false;
|
||||
if (!dest_rc) return false;
|
||||
LOGD("Patching " INIT_RC " in %s\n", src_path);
|
||||
file_readline(false, src.get(), [&dest](string_view line) -> bool {
|
||||
file_readline(src_rc, [&dest_rc](string_view line) -> bool {
|
||||
// Do not start vaultkeeper
|
||||
if (str_contains(line, "start vaultkeeper")) {
|
||||
LOGD("Remove vaultkeeper\n");
|
||||
@@ -76,59 +76,59 @@ static bool patch_rc_scripts(const char *src_path, const char *tmp_path, bool wr
|
||||
// Do not run flash_recovery
|
||||
if (line.starts_with("service flash_recovery")) {
|
||||
LOGD("Remove flash_recovery\n");
|
||||
fprintf(dest.get(), "service flash_recovery /system/bin/true\n");
|
||||
fprintf(dest_rc.get(), "service flash_recovery /system/bin/true\n");
|
||||
return true;
|
||||
}
|
||||
// Samsung's persist.sys.zygote.early will cause Zygote to start before post-fs-data
|
||||
if (line.starts_with("on property:persist.sys.zygote.early=")) {
|
||||
LOGD("Invalidate persist.sys.zygote.early\n");
|
||||
fprintf(dest.get(), "on property:persist.sys.zygote.early.xxxxx=true\n");
|
||||
fprintf(dest_rc.get(), "on property:persist.sys.zygote.early.xxxxx=true\n");
|
||||
return true;
|
||||
}
|
||||
// Else just write the line
|
||||
fprintf(dest.get(), "%s", line.data());
|
||||
fprintf(dest_rc.get(), "%s", line.data());
|
||||
return true;
|
||||
});
|
||||
|
||||
fprintf(dest.get(), "\n");
|
||||
fprintf(dest_rc.get(), "\n");
|
||||
|
||||
// Inject custom rc scripts
|
||||
for (auto &script : rc_list) {
|
||||
// Replace template arguments of rc scripts with dynamic paths
|
||||
replace_all(script, "${MAGISKTMP}", tmp_path);
|
||||
fprintf(dest.get(), "\n%s\n", script.data());
|
||||
fprintf(dest_rc.get(), "\n%s\n", script.data());
|
||||
}
|
||||
rc_list.clear();
|
||||
|
||||
// Inject Magisk rc scripts
|
||||
rust::inject_magisk_rc(fileno(dest.get()), tmp_path);
|
||||
rust::inject_magisk_rc(fileno(dest_rc.get()), tmp_path);
|
||||
|
||||
fclone_attr(fileno(src.get()), fileno(dest.get()));
|
||||
fclone_attr(src_rc, fileno(dest_rc.get()));
|
||||
}
|
||||
|
||||
// Then patch init.zygote*.rc
|
||||
for (dirent *entry; (entry = readdir(src_dir.get()));) {
|
||||
auto name = std::string_view(entry->d_name);
|
||||
if (!name.starts_with("init.zygote") || !name.ends_with(".rc")) continue;
|
||||
auto src = xopen_file(xopenat(src_fd, name.data(), O_RDONLY | O_CLOEXEC, 0), "re");
|
||||
if (!src) continue;
|
||||
owned_fd src_rc = xopenat(src_fd, name.data(), O_RDONLY | O_CLOEXEC, 0);
|
||||
if (src_rc < 0) continue;
|
||||
if (writable) unlinkat(src_fd, name.data(), 0);
|
||||
auto dest = xopen_file(
|
||||
auto dest_rc = xopen_file(
|
||||
xopenat(dest_fd, name.data(), O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0), "we");
|
||||
if (!dest) continue;
|
||||
if (!dest_rc) continue;
|
||||
LOGD("Patching %s in %s\n", name.data(), src_path);
|
||||
file_readline(false, src.get(), [&dest, &tmp_path](string_view line) -> bool {
|
||||
file_readline(src_rc, [&dest_rc, &tmp_path](string_view line) -> bool {
|
||||
if (line.starts_with("service zygote ")) {
|
||||
LOGD("Inject zygote restart\n");
|
||||
fprintf(dest.get(), "%s", line.data());
|
||||
fprintf(dest.get(),
|
||||
fprintf(dest_rc.get(), "%s", line.data());
|
||||
fprintf(dest_rc.get(),
|
||||
" onrestart exec " MAGISK_PROC_CON " 0 0 -- %s/magisk --zygote-restart\n", tmp_path);
|
||||
return true;
|
||||
}
|
||||
fprintf(dest.get(), "%s", line.data());
|
||||
fprintf(dest_rc.get(), "%s", line.data());
|
||||
return true;
|
||||
});
|
||||
fclone_attr(fileno(src.get()), fileno(dest.get()));
|
||||
fclone_attr(src_rc, fileno(dest_rc.get()));
|
||||
}
|
||||
|
||||
return faccessat(src_fd, "init.fission_host.rc", F_OK, 0) == 0;
|
||||
|
@@ -46,7 +46,7 @@ impl MagiskInit {
|
||||
pub(crate) fn parse_config_file(&mut self) {
|
||||
if let Ok(fd) = cstr!("/data/.backup/.magisk").open(O_RDONLY) {
|
||||
let mut reader = BufReader::new(fd);
|
||||
reader.foreach_props(|key, val| {
|
||||
reader.for_each_prop(|key, val| {
|
||||
if key == "PREINITDEVICE" {
|
||||
self.preinit_dev = val.to_string();
|
||||
return false;
|
||||
|
@@ -287,7 +287,7 @@ impl SePolicy {
|
||||
}
|
||||
|
||||
fn load_rules_from_reader<T: BufRead>(&mut self, reader: &mut T) {
|
||||
reader.foreach_lines(|line| {
|
||||
reader.for_each_line(|line| {
|
||||
self.parse_statement(line);
|
||||
true
|
||||
});
|
||||
|
Reference in New Issue
Block a user