Setup logging infra in the Rust side

This commit is contained in:
topjohnwu 2022-07-01 04:53:41 -07:00
parent 3817167ba1
commit b4863eb51b
20 changed files with 194 additions and 48 deletions

View File

@ -6,7 +6,7 @@
#undef _FORTIFY_SOURCE #undef _FORTIFY_SOURCE
extern int __vloge(const char* fmt, va_list ap); extern void __vloge(const char* fmt, va_list ap);
static inline __noreturn __printflike(1, 2) void __fortify_fatal(const char* fmt, ...) { static inline __noreturn __printflike(1, 2) void __fortify_fatal(const char* fmt, ...) {
va_list args; va_list args;

View File

@ -5,3 +5,4 @@
#include "../files.hpp" #include "../files.hpp"
#include "../misc.hpp" #include "../misc.hpp"
#include "../logging.hpp" #include "../logging.hpp"
#include <base-rs.hpp>

View File

@ -2,41 +2,52 @@
#include <cstdlib> #include <cstdlib>
#include <flags.h> #include <flags.h>
#include <base.hpp>
#include "logging.hpp" // Just need to include it somewhere
#include <base-rs.cpp>
using namespace std; using namespace std;
int nop_log(const char *, va_list) { return 0; } void nop_log(const char *, va_list) {}
void nop_ex(int) {}
log_callback log_cb = { log_callback log_cb = {
.d = nop_log, .d = nop_log,
.i = nop_log, .i = nop_log,
.w = nop_log, .w = nop_log,
.e = nop_log, .e = nop_log,
.ex = nop_ex
}; };
static bool EXIT_ON_ERROR = false;
void no_logging() { static void fmt_and_log_with_rs(LogLevel level, const char *fmt, va_list ap) {
log_cb.d = nop_log; char buf[4096];
log_cb.i = nop_log; int len = vsnprintf(buf, sizeof(buf), fmt, ap);
log_cb.w = nop_log; if (len > 0 && buf[len - 1] == '\n') {
log_cb.e = nop_log; // It's unfortunate that all logging on the C++ side always manually include
log_cb.ex = nop_ex; // a newline at the end due to how it was originally implemented.
// The logging infrastructure on the rust side does NOT expect a newline
// at the end, so we will have to strip it out before sending it over.
buf[len - 1] = '\0';
}
log_with_rs(level, buf);
} }
static int vprintfe(const char *fmt, va_list ap) { #define rlog(prio) [](auto fmt, auto ap) { fmt_and_log_with_rs(LogLevel::prio, fmt, ap); }
return vfprintf(stderr, fmt, ap); static void forward_logging_to_rs() {
log_cb.d = rlog(Debug);
log_cb.i = rlog(Info);
log_cb.w = rlog(Warn);
log_cb.e = rlog(Error);
} }
void cmdline_logging() { void cmdline_logging() {
log_cb.d = vprintfe; rs::logging::cmdline_logging();
log_cb.i = vprintf; forward_logging_to_rs();
log_cb.w = vprintfe; }
log_cb.e = vprintfe;
log_cb.ex = exit; void exit_on_error(bool b) {
rs::logging::exit_on_error(b);
EXIT_ON_ERROR = b;
} }
#define LOG_BODY(prio) { \ #define LOG_BODY(prio) { \
@ -54,9 +65,9 @@ void LOGD(const char *fmt, ...) {}
#endif #endif
void LOGI(const char *fmt, ...) { LOG_BODY(i) } void LOGI(const char *fmt, ...) { LOG_BODY(i) }
void LOGW(const char *fmt, ...) { LOG_BODY(w) } void LOGW(const char *fmt, ...) { LOG_BODY(w) }
void LOGE(const char *fmt, ...) { LOG_BODY(e); log_cb.ex(EXIT_FAILURE); } void LOGE(const char *fmt, ...) { LOG_BODY(e); if (EXIT_ON_ERROR) exit(EXIT_FAILURE); }
// Export raw symbol to fortify compat // Export raw symbol to fortify compat
extern "C" int __vloge(const char* fmt, va_list ap) { extern "C" void __vloge(const char* fmt, va_list ap) {
return log_cb.e(fmt, ap); log_cb.e(fmt, ap);
} }

View File

@ -4,11 +4,10 @@
#include <cstdarg> #include <cstdarg>
struct log_callback { struct log_callback {
int (*d)(const char* fmt, va_list ap); void (*d)(const char* fmt, va_list ap);
int (*i)(const char* fmt, va_list ap); void (*i)(const char* fmt, va_list ap);
int (*w)(const char* fmt, va_list ap); void (*w)(const char* fmt, va_list ap);
int (*e)(const char* fmt, va_list ap); void (*e)(const char* fmt, va_list ap);
void (*ex)(int code);
}; };
extern log_callback log_cb; extern log_callback log_cb;
@ -19,8 +18,7 @@ void LOGW(const char *fmt, ...) __printflike(1, 2);
void LOGE(const char *fmt, ...) __printflike(1, 2); void LOGE(const char *fmt, ...) __printflike(1, 2);
#define PLOGE(fmt, args...) LOGE(fmt " failed with %d: %s\n", ##args, errno, std::strerror(errno)) #define PLOGE(fmt, args...) LOGE(fmt " failed with %d: %s\n", ##args, errno, std::strerror(errno))
int nop_log(const char *, va_list); void nop_log(const char *, va_list);
void nop_ex(int);
void no_logging();
void cmdline_logging(); void cmdline_logging();
void exit_on_error(bool b);

View File

@ -11,6 +11,8 @@
#include <resetprop.hpp> #include <resetprop.hpp>
#include <flags.h> #include <flags.h>
#include <core-rs.cpp>
#include "core.hpp" #include "core.hpp"
using namespace std; using namespace std;

View File

@ -166,22 +166,22 @@ extern "C" int magisk_log_print(int prio, const char *tag, const char *fmt, ...)
return ret; return ret;
} }
#define mlog(prio) [](auto fmt, auto ap){ return magisk_log(ANDROID_LOG_##prio, fmt, ap); } #define mlog(prio) [](auto fmt, auto ap){ magisk_log(ANDROID_LOG_##prio, fmt, ap); }
void magisk_logging() { void magisk_logging() {
log_cb.d = mlog(DEBUG); log_cb.d = mlog(DEBUG);
log_cb.i = mlog(INFO); log_cb.i = mlog(INFO);
log_cb.w = mlog(WARN); log_cb.w = mlog(WARN);
log_cb.e = mlog(ERROR); log_cb.e = mlog(ERROR);
log_cb.ex = nop_ex; exit_on_error(false);
} }
#define alog(prio) [](auto fmt, auto ap){ return __android_log_vprint(ANDROID_LOG_##prio, "Magisk", fmt, ap); } #define alog(prio) [](auto fmt, auto ap){ __android_log_vprint(ANDROID_LOG_##prio, "Magisk", fmt, ap); }
void android_logging() { void android_logging() {
log_cb.d = alog(DEBUG); log_cb.d = alog(DEBUG);
log_cb.i = alog(INFO); log_cb.i = alog(INFO);
log_cb.w = alog(WARN); log_cb.w = alog(WARN);
log_cb.e = alog(ERROR); log_cb.e = alog(ERROR);
log_cb.ex = nop_ex; exit_on_error(false);
} }
void start_log_daemon() { void start_log_daemon() {

View File

@ -127,6 +127,7 @@ int magisk_main(int argc, char *argv[]) {
#if 0 #if 0
/* Entry point for testing stuffs */ /* Entry point for testing stuffs */
else if (argv[1] == "--test"sv) { else if (argv[1] == "--test"sv) {
rust_test_entry();
return 0; return 0;
} }
#endif #endif

View File

@ -8,6 +8,7 @@
#include <functional> #include <functional>
#include <socket.hpp> #include <socket.hpp>
#include <core-rs.hpp>
#define AID_ROOT 0 #define AID_ROOT 0
#define AID_SHELL 2000 #define AID_SHELL 2000

View File

@ -119,9 +119,9 @@ static bool check_key_combo() {
static FILE *kmsg; static FILE *kmsg;
static char kmsg_buf[4096]; static char kmsg_buf[4096];
static int vprintk(const char *fmt, va_list ap) { static void vprintk(const char *fmt, va_list ap) {
vsnprintf(kmsg_buf + 12, sizeof(kmsg_buf) - 12, fmt, ap); vsnprintf(kmsg_buf + 12, sizeof(kmsg_buf) - 12, fmt, ap);
return fprintf(kmsg, "%s", kmsg_buf); fprintf(kmsg, "%s", kmsg_buf);
} }
void setup_klog() { void setup_klog() {
// Shut down first 3 fds // Shut down first 3 fds
@ -150,7 +150,7 @@ void setup_klog() {
kmsg = fdopen(fd, "w"); kmsg = fdopen(fd, "w");
setbuf(kmsg, nullptr); setbuf(kmsg, nullptr);
log_cb.d = log_cb.i = log_cb.w = log_cb.e = vprintk; log_cb.d = log_cb.i = log_cb.w = log_cb.e = vprintk;
log_cb.ex = nop_ex; exit_on_error(false);
strcpy(kmsg_buf, "magiskinit: "); strcpy(kmsg_buf, "magiskinit: ");
// Disable kmsg rate limiting // Disable kmsg rate limiting

View File

@ -13,8 +13,6 @@
using namespace std; using namespace std;
static bool verbose = false;
#ifdef APPLET_STUB_MAIN #ifdef APPLET_STUB_MAIN
#define system_property_set __system_property_set #define system_property_set __system_property_set
#define system_property_find __system_property_find #define system_property_find __system_property_find
@ -297,10 +295,9 @@ void load_prop_file(const char *filename, bool prop_svc) {
} }
int resetprop_main(int argc, char *argv[]) { int resetprop_main(int argc, char *argv[]) {
log_cb.d = [](auto fmt, auto ap) -> int { return verbose ? vfprintf(stderr, fmt, ap) : 0; };
bool prop_svc = true; bool prop_svc = true;
bool persist = false; bool persist = false;
bool verbose = false;
char *argv0 = argv[0]; char *argv0 = argv[0];
--argc; --argc;
@ -340,6 +337,9 @@ int resetprop_main(int argc, char *argv[]) {
++argv; ++argv;
} }
if (!verbose)
log_cb.d = nop_log;
switch (argc) { switch (argc) {
case 0: case 0:
print_props(persist); print_props(persist);

View File

@ -311,7 +311,7 @@ void su_daemon_handler(int client, const sock_cred *cred) {
LOGD("su: fork handler\n"); LOGD("su: fork handler\n");
// Abort upon any error occurred // Abort upon any error occurred
log_cb.ex = exit; exit_on_error(true);
// ack // ack
write_int(client, 0); write_int(client, 0);

View File

@ -17,15 +17,15 @@ using namespace std;
void *self_handle = nullptr; void *self_handle = nullptr;
static int zygisk_log(int prio, const char *fmt, va_list ap); static void zygisk_log(int prio, const char *fmt, va_list ap);
#define zlog(prio) [](auto fmt, auto ap){ return zygisk_log(ANDROID_LOG_##prio, fmt, ap); } #define zlog(prio) [](auto fmt, auto ap){ zygisk_log(ANDROID_LOG_##prio, fmt, ap); }
static void zygisk_logging() { static void zygisk_logging() {
log_cb.d = zlog(DEBUG); log_cb.d = zlog(DEBUG);
log_cb.i = zlog(INFO); log_cb.i = zlog(INFO);
log_cb.w = zlog(WARN); log_cb.w = zlog(WARN);
log_cb.e = zlog(ERROR); log_cb.e = zlog(ERROR);
log_cb.ex = nop_ex; exit_on_error(false);
} }
// Make sure /proc/self/environ is sanitized // Make sure /proc/self/environ is sanitized
@ -114,7 +114,7 @@ static void zygisk_init() {
// The following code runs in zygote/app process // The following code runs in zygote/app process
static int zygisk_log(int prio, const char *fmt, va_list ap) { static void zygisk_log(int prio, const char *fmt, va_list ap) {
// If we don't have log pipe set, ask magiskd for it // If we don't have log pipe set, ask magiskd for it
// This could happen multiple times in zygote because it was closed to prevent crashing // This could happen multiple times in zygote because it was closed to prevent crashing
if (logd_fd < 0) { if (logd_fd < 0) {
@ -139,13 +139,12 @@ static int zygisk_log(int prio, const char *fmt, va_list ap) {
sigaddset(&mask, SIGPIPE); sigaddset(&mask, SIGPIPE);
pthread_sigmask(SIG_BLOCK, &mask, &orig_mask); pthread_sigmask(SIG_BLOCK, &mask, &orig_mask);
} }
int ret = magisk_log(prio, fmt, ap); magisk_log(prio, fmt, ap);
if (sig) { if (sig) {
timespec ts{}; timespec ts{};
sigtimedwait(&mask, nullptr, &ts); sigtimedwait(&mask, nullptr, &ts);
pthread_sigmask(SIG_SETMASK, &orig_mask, nullptr); pthread_sigmask(SIG_SETMASK, &orig_mask, nullptr);
} }
return ret;
} }
static inline bool should_load_modules(uint32_t flags) { static inline bool should_load_modules(uint32_t flags) {

View File

@ -5,6 +5,9 @@ version = 3
[[package]] [[package]]
name = "base" name = "base"
version = "0.1.0" version = "0.1.0"
dependencies = [
"cxx",
]
[[package]] [[package]]
name = "cc" name = "cc"

View File

@ -4,3 +4,4 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
cxx = "1.0.69"

View File

@ -0,0 +1,25 @@
pub use logging::*;
mod logging;
#[cxx::bridge]
pub mod ffi {
pub enum LogLevel {
Error,
Warn,
Info,
Debug,
}
extern "Rust" {
fn log_with_rs(level: LogLevel, msg: &str);
}
}
#[cxx::bridge(namespace = "rs::logging")]
pub mod ffi2 {
extern "Rust" {
fn cmdline_logging();
fn exit_on_error(b: bool);
}
}

View File

@ -0,0 +1,91 @@
use std::fmt::Arguments;
use std::process::exit;
use crate::ffi::LogLevel;
// We don't need to care about thread safety, because all
// logger changes will only happen on the main thread.
pub static mut LOGGER: Logger = Logger {
d: nop_log,
i: nop_log,
w: nop_log,
e: nop_log,
};
static mut EXIT_ON_ERROR: bool = false;
#[derive(Copy, Clone)]
pub struct Logger {
pub d: fn(args: Arguments),
pub i: fn(args: Arguments),
pub w: fn(args: Arguments),
pub e: fn(args: Arguments),
}
pub fn nop_log(_: Arguments) {}
fn println(args: Arguments) { println!("{}", args); }
fn eprintln(args: Arguments) { eprintln!("{}", args); }
pub fn log_with_rs(level: LogLevel, msg: &str) {
log_impl(level, format_args!("{}", msg));
}
pub fn exit_on_error(b: bool) {
unsafe { EXIT_ON_ERROR = b; }
}
pub fn cmdline_logging() {
let logger = Logger {
d: eprintln,
i: println,
w: eprintln,
e: eprintln,
};
unsafe {
LOGGER = logger;
EXIT_ON_ERROR = true;
}
}
pub fn log_impl(level: LogLevel, args: Arguments) {
let logger = unsafe { LOGGER };
let aoe = unsafe { EXIT_ON_ERROR };
match level {
LogLevel::Error => {
(logger.e)(args);
if aoe { exit(1); }
}
LogLevel::Warn => (logger.w)(args),
LogLevel::Info => (logger.i)(args),
LogLevel::Debug => (logger.d)(args),
_ => ()
}
}
#[macro_export]
macro_rules! error {
($($arg:tt)+) => ($crate::log_impl($crate::ffi::LogLevel::Error, format_args!($($arg)+)))
}
#[macro_export]
macro_rules! warn {
($($arg:tt)+) => ($crate::log_impl($crate::ffi::LogLevel::Warn, format_args!($($arg)+)))
}
#[macro_export]
macro_rules! info {
($($arg:tt)+) => ($crate::log_impl($crate::ffi::LogLevel::Info, format_args!($($arg)+)))
}
#[cfg(debug_assertions)]
#[macro_export]
macro_rules! debug {
($($arg:tt)+) => ($crate::log_impl($crate::ffi::LogLevel::Debug, format_args!($($arg)+)))
}
#[cfg(not(debug_assertions))]
#[macro_export]
macro_rules! debug {
($($arg:tt)+) => ()
}

View File

@ -0,0 +1 @@
pub use base;

View File

@ -0,0 +1,10 @@
pub use base;
#[cxx::bridge]
pub mod ffi {
extern "Rust" {
fn rust_test_entry();
}
}
fn rust_test_entry() {}

View File

@ -0,0 +1 @@
pub use base;

View File

@ -0,0 +1 @@
pub use base;