Files
Magisk/native/src/init/init.rs
2025-02-14 14:24:13 -08:00

159 lines
4.4 KiB
Rust

use crate::{
ffi::{magisk_proxy_main, BootConfig, MagiskInit},
logging::setup_klog,
};
use base::{
cstr, debug, info,
libc::{basename, getpid, mount, umask},
raw_cstr, FsPath, LibcReturn, LoggedResult, ResultExt, Utf8CStr,
};
use std::{
ffi::{c_char, CStr},
ptr::null,
};
impl MagiskInit {
fn new(argv: *mut *mut c_char) -> Self {
Self {
preinit_dev: String::new(),
mount_list: Vec::new(),
argv,
config: BootConfig {
skip_initramfs: false,
force_normal_boot: false,
rootwait: false,
emulator: false,
slot: [0; 3],
dt_dir: [0; 64],
fstab_suffix: [0; 32],
hardware: [0; 32],
hardware_plat: [0; 32],
partition_map: Vec::new(),
},
}
}
pub(crate) fn legacy_system_as_root(&mut self) {
info!("Legacy SAR Init");
self.prepare_data();
if self.mount_system_root() {
self.redirect_second_stage();
} else {
self.patch_ro_root();
}
}
pub(crate) fn rootfs(&mut self) {
info!("RootFS Init");
self.prepare_data();
debug!("Restoring /init\n");
FsPath::from(cstr!("/.backup/init"))
.rename_to(FsPath::from(cstr!("/init")))
.log()
.ok();
self.patch_rw_root();
}
pub(crate) fn recovery(&self) {
info!("Ramdisk is recovery, abort");
self.restore_ramdisk_init();
FsPath::from(cstr!("/.backup")).remove_all().ok();
}
pub(crate) fn restore_ramdisk_init(&self) {
FsPath::from(cstr!("/init")).remove().ok();
let orig_init = FsPath::from(unsafe { Utf8CStr::from_ptr_unchecked(self.backup_init()) });
if orig_init.exists() {
orig_init.rename_to(FsPath::from(cstr!("/init"))).log().ok();
} else {
// If the backup init is missing, this means that the boot ramdisk
// was created from scratch, and the real init is in a separate CPIO,
// which is guaranteed to be placed at /system/bin/init.
FsPath::from(cstr!("/system/bin/init"))
.symlink_to(FsPath::from(cstr!("/init")))
.log()
.ok();
}
}
fn start(&mut self) -> LoggedResult<()> {
if !FsPath::from(cstr!("/proc/cmdline")).exists() {
FsPath::from(cstr!("/proc")).mkdir(0o755)?;
unsafe {
mount(
raw_cstr!("proc"),
raw_cstr!("/proc"),
raw_cstr!("proc"),
0,
null(),
)
}
.as_os_err()?;
self.mount_list.push("/proc".to_string());
}
if !FsPath::from(cstr!("/sys/block")).exists() {
FsPath::from(cstr!("/sys")).mkdir(0o755)?;
unsafe {
mount(
raw_cstr!("sysfs"),
raw_cstr!("/sys"),
raw_cstr!("sysfs"),
0,
null(),
)
}
.as_os_err()?;
self.mount_list.push("/sys".to_string());
}
setup_klog();
self.config.init();
let argv1 = unsafe { *self.argv.offset(1) };
if !argv1.is_null() && unsafe { CStr::from_ptr(argv1) == c"selinux_setup" } {
self.second_stage();
} else if self.config.skip_initramfs {
self.legacy_system_as_root();
} else if self.config.force_normal_boot {
self.first_stage();
} else if FsPath::from(cstr!("/sbin/recovery")).exists()
|| FsPath::from(cstr!("/system/bin/recovery")).exists()
{
self.recovery();
} else if self.check_two_stage() {
self.first_stage();
} else {
self.rootfs();
}
// Finally execute the original init
self.exec_init();
Ok(())
}
}
#[no_mangle]
pub unsafe extern "C" fn main(
argc: i32,
argv: *mut *mut c_char,
_envp: *const *const c_char,
) -> i32 {
umask(0);
let name = basename(*argv);
if CStr::from_ptr(name) == c"magisk" {
return magisk_proxy_main(argc, argv);
}
if getpid() == 1 {
MagiskInit::new(argv).start().log().ok();
}
1
}