mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-02 22:45:27 +00:00
1cd45b53b1
Some devices (mainly new Samsung phones we're talking here...) using A only system-as-root refuse to load ramdisk when booted with boot no matter what we do. With many A only system-as-root devices, even though their boot image is kernel only, we can still be able to add a ramdisk section into the image and force the kernel to use it as rootfs. However the bootloader on devices like the S10 simply does not load anything within boot image into memory other than the kernel. This gives as the only option is to install Magisk on the recovery partition. This commits adds proper support for these kind of scenarios.
674 lines
17 KiB
C++
674 lines
17 KiB
C++
/* init.cpp - Pre-init Magisk support
|
|
*
|
|
* This code has to be compiled statically to work properly.
|
|
*
|
|
* To unify Magisk support for both legacy "normal" devices and new skip_initramfs devices,
|
|
* magisk binary compilation is split into two parts - first part only compiles "magisk".
|
|
* The python build script will load the magisk main binary and compress with lzma2, dumping
|
|
* the results into "dump.h". The "magisk" binary is embedded into this binary, and will
|
|
* get extracted to the overlay folder along with init.magisk.rc.
|
|
*
|
|
* This tool does all pre-init operations to setup a Magisk environment, which pathces rootfs
|
|
* on the fly, providing fundamental support such as init, init.rc, and sepolicy patching.
|
|
*
|
|
* Magiskinit is also responsible for constructing a proper rootfs on skip_initramfs devices.
|
|
* On skip_initramfs devices, it will parse kernel cmdline, mount sysfs, parse through
|
|
* uevent files to make the system (or vendor if available) block device node, then copy
|
|
* rootfs files from system.
|
|
*
|
|
* This tool will be replaced with the real init to continue the boot process, but hardlinks are
|
|
* preserved as it also provides CLI for sepolicy patching (magiskpolicy)
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <dirent.h>
|
|
#include <fcntl.h>
|
|
#include <libgen.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <sys/mount.h>
|
|
#include <sys/sendfile.h>
|
|
#include <sys/sysmacros.h>
|
|
#include <functional>
|
|
#include <string_view>
|
|
|
|
#include <xz.h>
|
|
#include <magisk.h>
|
|
#include <magiskpolicy.h>
|
|
#include <selinux.h>
|
|
#include <cpio.h>
|
|
#include <utils.h>
|
|
#include <flags.h>
|
|
|
|
#include "binaries.h"
|
|
#ifdef USE_64BIT
|
|
#include "binaries_arch64.h"
|
|
#else
|
|
#include "binaries_arch.h"
|
|
#endif
|
|
#include "magiskrc.h"
|
|
|
|
#define DEFAULT_DT_DIR "/proc/device-tree/firmware/android"
|
|
|
|
static int test_main(int argc, char *argv[]);
|
|
|
|
constexpr const char *init_applet[] =
|
|
{ "magiskpolicy", "supolicy", "init_test", nullptr };
|
|
constexpr int (*init_applet_main[])(int, char *[]) =
|
|
{ magiskpolicy_main, magiskpolicy_main, test_main, nullptr };
|
|
|
|
struct cmdline {
|
|
bool system_as_root;
|
|
char slot[3];
|
|
char dt_dir[128];
|
|
};
|
|
|
|
struct device {
|
|
dev_t major;
|
|
dev_t minor;
|
|
char devname[32];
|
|
char partname[32];
|
|
char path[64];
|
|
};
|
|
|
|
struct raw_data {
|
|
void *buf;
|
|
size_t sz;
|
|
};
|
|
|
|
static bool unxz(int fd, const uint8_t *buf, size_t size) {
|
|
uint8_t out[8192];
|
|
xz_crc32_init();
|
|
struct xz_dec *dec = xz_dec_init(XZ_DYNALLOC, 1 << 26);
|
|
struct xz_buf b = {
|
|
.in = buf,
|
|
.in_pos = 0,
|
|
.in_size = size,
|
|
.out = out,
|
|
.out_pos = 0,
|
|
.out_size = sizeof(out)
|
|
};
|
|
enum xz_ret ret;
|
|
do {
|
|
ret = xz_dec_run(dec, &b);
|
|
if (ret != XZ_OK && ret != XZ_STREAM_END)
|
|
return false;
|
|
write(fd, out, b.out_pos);
|
|
b.out_pos = 0;
|
|
} while (b.in_pos != size);
|
|
return true;
|
|
}
|
|
|
|
static void decompress_ramdisk() {
|
|
constexpr char tmp[] = "tmp.cpio";
|
|
constexpr char ramdisk_xz[] = "ramdisk.cpio.xz";
|
|
if (access(ramdisk_xz, F_OK))
|
|
return;
|
|
uint8_t *buf;
|
|
size_t sz;
|
|
mmap_ro(ramdisk_xz, buf, sz);
|
|
int fd = open(tmp, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC);
|
|
unxz(fd, buf, sz);
|
|
munmap(buf, sz);
|
|
close(fd);
|
|
cpio_mmap cpio(tmp);
|
|
cpio.extract();
|
|
unlink(tmp);
|
|
unlink(ramdisk_xz);
|
|
}
|
|
|
|
static int dump_magisk(const char *path, mode_t mode) {
|
|
int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, mode);
|
|
if (fd < 0)
|
|
return 1;
|
|
if (!unxz(fd, magisk_xz, sizeof(magisk_xz)))
|
|
return 1;
|
|
close(fd);
|
|
return 0;
|
|
}
|
|
|
|
static int dump_manager(const char *path, mode_t mode) {
|
|
int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, mode);
|
|
if (fd < 0)
|
|
return 1;
|
|
if (!unxz(fd, manager_xz, sizeof(manager_xz)))
|
|
return 1;
|
|
close(fd);
|
|
return 0;
|
|
}
|
|
|
|
class MagiskInit {
|
|
private:
|
|
cmdline cmd{};
|
|
raw_data init{};
|
|
raw_data config{};
|
|
int root = -1;
|
|
char **argv;
|
|
bool load_sepol = false;
|
|
bool mnt_system = false;
|
|
bool mnt_vendor = false;
|
|
bool mnt_product = false;
|
|
bool mnt_odm = false;
|
|
|
|
void load_kernel_info();
|
|
void preset();
|
|
void early_mount();
|
|
void setup_rootfs();
|
|
bool read_dt_fstab(const char *mnt_point, char *partname, char *partfs);
|
|
bool patch_sepolicy();
|
|
void cleanup();
|
|
|
|
public:
|
|
explicit MagiskInit(char *argv[]) : argv(argv) {}
|
|
void setup_overlay();
|
|
void re_exec_init();
|
|
void start();
|
|
void test();
|
|
};
|
|
|
|
static inline void parse_cmdline(const std::function<void (std::string_view, const char *)> &fn) {
|
|
char cmdline[4096];
|
|
int fd = open("/proc/cmdline", O_RDONLY | O_CLOEXEC);
|
|
cmdline[read(fd, cmdline, sizeof(cmdline))] = '\0';
|
|
close(fd);
|
|
|
|
char *tok, *eql, *tmp, *saveptr;
|
|
saveptr = cmdline;
|
|
while ((tok = strtok_r(nullptr, " \n", &saveptr)) != nullptr) {
|
|
eql = strchr(tok, '=');
|
|
if (eql) {
|
|
*eql = '\0';
|
|
if (eql[1] == '"') {
|
|
tmp = strchr(saveptr, '"');
|
|
if (tmp != nullptr) {
|
|
*tmp = '\0';
|
|
saveptr[-1] = ' ';
|
|
saveptr = tmp + 1;
|
|
eql++;
|
|
}
|
|
}
|
|
fn(tok, eql + 1);
|
|
} else {
|
|
fn(tok, "");
|
|
}
|
|
}
|
|
}
|
|
|
|
void MagiskInit::load_kernel_info() {
|
|
// Communicate with kernel using procfs and sysfs
|
|
mkdir("/proc", 0755);
|
|
xmount("proc", "/proc", "proc", 0, nullptr);
|
|
mkdir("/sys", 0755);
|
|
xmount("sysfs", "/sys", "sysfs", 0, nullptr);
|
|
|
|
char cmdline[4096];
|
|
int fd = open("/proc/cmdline", O_RDONLY | O_CLOEXEC);
|
|
cmdline[read(fd, cmdline, sizeof(cmdline))] = '\0';
|
|
close(fd);
|
|
|
|
bool skip_initramfs = false;
|
|
bool enter_recovery = false;
|
|
bool kirin = false;
|
|
|
|
parse_cmdline([&](auto key, auto value) -> void {
|
|
LOGD("cmdline: [%s]=[%s]\n", key.data(), value);
|
|
if (key == "androidboot.slot_suffix") {
|
|
strcpy(cmd.slot, value);
|
|
} else if (key == "androidboot.slot") {
|
|
cmd.slot[0] = '_';
|
|
strcpy(cmd.slot + 1, value);
|
|
} else if (key == "skip_initramfs") {
|
|
skip_initramfs = true;
|
|
} else if (key == "androidboot.android_dt_dir") {
|
|
strcpy(cmd.dt_dir, value);
|
|
} else if (key == "enter_recovery") {
|
|
enter_recovery = value[0] == '1';
|
|
} else if (key == "androidboot.hardware") {
|
|
kirin = strstr(value, "kirin") || strstr(value, "hi3660");
|
|
}
|
|
});
|
|
|
|
parse_prop_file("/.backup/.magisk", [&](auto key, auto value) -> bool {
|
|
if (key == "RECOVERYMODE" && value == "true")
|
|
cmd.system_as_root = true;
|
|
return true;
|
|
});
|
|
|
|
if (kirin && enter_recovery) {
|
|
// Inform that we are actually booting as recovery
|
|
if (!cmd.system_as_root) {
|
|
if (FILE *f = fopen("/.backup/.magisk", "ae"); f) {
|
|
fprintf(f, "RECOVERYMODE=true\n");
|
|
fclose(f);
|
|
}
|
|
cmd.system_as_root = true;
|
|
}
|
|
}
|
|
|
|
cmd.system_as_root |= skip_initramfs;
|
|
|
|
if (cmd.dt_dir[0] == '\0')
|
|
strcpy(cmd.dt_dir, DEFAULT_DT_DIR);
|
|
|
|
LOGD("system_as_root[%d] slot[%s] dt_dir[%s]\n", cmd.system_as_root, cmd.slot, cmd.dt_dir);
|
|
}
|
|
|
|
void MagiskInit::preset() {
|
|
root = open("/", O_RDONLY | O_CLOEXEC);
|
|
|
|
if (cmd.system_as_root) {
|
|
// Clear rootfs
|
|
const char *excl[] = { "overlay", "proc", "sys", nullptr };
|
|
excl_list = excl;
|
|
frm_rf(root);
|
|
excl_list = nullptr;
|
|
} else {
|
|
decompress_ramdisk();
|
|
|
|
// Revert original init binary
|
|
rename("/.backup/init", "/init");
|
|
rm_rf("/.backup");
|
|
|
|
// Do not go further if device is booting into recovery
|
|
if (access("/sbin/recovery", F_OK) == 0)
|
|
re_exec_init();
|
|
}
|
|
}
|
|
|
|
static inline void parse_device(struct device *dev, const char *uevent) {
|
|
dev->partname[0] = '\0';
|
|
FILE *fp = xfopen(uevent, "r");
|
|
char buf[64];
|
|
while (fgets(buf, sizeof(buf), fp)) {
|
|
if (strncmp(buf, "MAJOR", 5) == 0) {
|
|
sscanf(buf, "MAJOR=%ld", (long*) &dev->major);
|
|
} else if (strncmp(buf, "MINOR", 5) == 0) {
|
|
sscanf(buf, "MINOR=%ld", (long*) &dev->minor);
|
|
} else if (strncmp(buf, "DEVNAME", 7) == 0) {
|
|
sscanf(buf, "DEVNAME=%s", dev->devname);
|
|
} else if (strncmp(buf, "PARTNAME", 8) == 0) {
|
|
sscanf(buf, "PARTNAME=%s", dev->partname);
|
|
}
|
|
}
|
|
fclose(fp);
|
|
LOGD("%s [%s] (%u, %u)\n", dev->devname, dev->partname, (unsigned) dev->major, (unsigned) dev->minor);
|
|
}
|
|
|
|
static bool setup_block(struct device *dev, const char *partname) {
|
|
char path[128];
|
|
struct dirent *entry;
|
|
DIR *dir = opendir("/sys/dev/block");
|
|
if (dir == nullptr)
|
|
return false;
|
|
bool found = false;
|
|
while ((entry = readdir(dir))) {
|
|
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
|
|
continue;
|
|
sprintf(path, "/sys/dev/block/%s/uevent", entry->d_name);
|
|
parse_device(dev, path);
|
|
if (strcasecmp(dev->partname, partname) == 0) {
|
|
sprintf(dev->path, "/dev/block/%s", dev->devname);
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
closedir(dir);
|
|
|
|
if (!found)
|
|
return false;
|
|
|
|
mkdir("/dev", 0755);
|
|
mkdir("/dev/block", 0755);
|
|
mknod(dev->path, S_IFBLK | 0600, makedev(dev->major, dev->minor));
|
|
return true;
|
|
}
|
|
|
|
static inline bool is_lnk(const char *name) {
|
|
struct stat st;
|
|
if (lstat(name, &st))
|
|
return false;
|
|
return S_ISLNK(st.st_mode);
|
|
}
|
|
|
|
#define link_root(part) \
|
|
if (is_lnk("/system_root" part)) \
|
|
cp_afc("/system_root" part, part)
|
|
|
|
#define mount_root(part) \
|
|
if (!is_lnk("/" #part) && read_dt_fstab(#part, partname, fstype)) { \
|
|
setup_block(&dev, partname); \
|
|
xmkdir("/" #part, 0755); \
|
|
xmount(dev.path, "/" #part, fstype, MS_RDONLY, nullptr); \
|
|
mnt_##part = true; \
|
|
}
|
|
|
|
void MagiskInit::early_mount() {
|
|
struct device dev;
|
|
char partname[32];
|
|
char fstype[32];
|
|
|
|
if (cmd.system_as_root) {
|
|
sprintf(partname, "system%s", cmd.slot);
|
|
setup_block(&dev, partname);
|
|
xmkdir("/system_root", 0755);
|
|
xmount(dev.path, "/system_root", "ext4", MS_RDONLY, nullptr);
|
|
xmkdir("/system", 0755);
|
|
xmount("/system_root/system", "/system", nullptr, MS_BIND, nullptr);
|
|
|
|
// Android Q
|
|
if (is_lnk("/system_root/init"))
|
|
load_sepol = true;
|
|
|
|
// System-as-root with monolithic sepolicy
|
|
if (access("/system_root/sepolicy", F_OK) == 0)
|
|
cp_afc("/system_root/sepolicy", "/sepolicy");
|
|
|
|
// Copy if these partitions are symlinks
|
|
link_root("/vendor");
|
|
link_root("/product");
|
|
link_root("/odm");
|
|
} else {
|
|
mount_root(system);
|
|
}
|
|
|
|
mount_root(vendor);
|
|
mount_root(product);
|
|
mount_root(odm);
|
|
}
|
|
|
|
void MagiskInit::setup_rootfs() {
|
|
bool patch_init = patch_sepolicy();
|
|
|
|
if (cmd.system_as_root) {
|
|
// Clone rootfs except /system
|
|
int system_root = open("/system_root", O_RDONLY | O_CLOEXEC);
|
|
const char *excl[] = { "system", nullptr };
|
|
excl_list = excl;
|
|
clone_dir(system_root, root);
|
|
close(system_root);
|
|
excl_list = nullptr;
|
|
}
|
|
|
|
// Override /sepolicy if exist
|
|
rename("/magisk_sepolicy", "/sepolicy");
|
|
|
|
if (patch_init) {
|
|
constexpr char SYSTEM_INIT[] = "/system/bin/init";
|
|
// If init is symlink, copy it to rootfs so we can patch
|
|
struct stat st;
|
|
lstat("/init", &st);
|
|
if (S_ISLNK(st.st_mode))
|
|
cp_afc(SYSTEM_INIT, "/init");
|
|
|
|
char *addr;
|
|
size_t size;
|
|
mmap_rw("/init", addr, size);
|
|
for (char *p = addr; p < addr + size; ++p) {
|
|
if (memcmp(p, SPLIT_PLAT_CIL, sizeof(SPLIT_PLAT_CIL)) == 0) {
|
|
// Force init to load /sepolicy
|
|
memset(p, 'x', sizeof(SPLIT_PLAT_CIL) - 1);
|
|
p += sizeof(SPLIT_PLAT_CIL) - 1;
|
|
} else if (memcmp(p, SYSTEM_INIT, sizeof(SYSTEM_INIT)) == 0) {
|
|
// Force execute /init instead of /system/bin/init
|
|
strcpy(p, "/init");
|
|
p += sizeof(SYSTEM_INIT) - 1;
|
|
}
|
|
}
|
|
munmap(addr, size);
|
|
}
|
|
|
|
// Handle ramdisk overlays
|
|
int fd = open("/overlay", O_RDONLY | O_CLOEXEC);
|
|
if (fd >= 0) {
|
|
mv_dir(fd, root);
|
|
close(fd);
|
|
rmdir("/overlay");
|
|
}
|
|
|
|
// Patch init.rc
|
|
FILE *rc = xfopen("/init.rc", "ae");
|
|
char pfd_svc[8], ls_svc[8];
|
|
gen_rand_str(pfd_svc, sizeof(pfd_svc));
|
|
do {
|
|
gen_rand_str(ls_svc, sizeof(ls_svc));
|
|
} while (strcmp(pfd_svc, ls_svc) == 0);
|
|
fprintf(rc, magiskrc, pfd_svc, pfd_svc, ls_svc);
|
|
fclose(rc);
|
|
|
|
// Don't let init run in init yet
|
|
lsetfilecon("/init", "u:object_r:rootfs:s0");
|
|
|
|
// Create hardlink mirror of /sbin to /root
|
|
mkdir("/root", 0750);
|
|
clone_attr("/sbin", "/root");
|
|
int rootdir = xopen("/root", O_RDONLY | O_CLOEXEC);
|
|
int sbin = xopen("/sbin", O_RDONLY | O_CLOEXEC);
|
|
link_dir(sbin, rootdir);
|
|
}
|
|
|
|
bool MagiskInit::patch_sepolicy() {
|
|
bool patch_init = false;
|
|
|
|
if (access(SPLIT_PLAT_CIL, R_OK) == 0)
|
|
patch_init = true; /* Split sepolicy */
|
|
else if (access("/sepolicy", R_OK) == 0)
|
|
load_policydb("/sepolicy"); /* Monolithic sepolicy */
|
|
else
|
|
return false; /* No SELinux */
|
|
|
|
// Mount selinuxfs to communicate with kernel
|
|
xmount("selinuxfs", SELINUX_MNT, "selinuxfs", 0, nullptr);
|
|
|
|
if (patch_init)
|
|
load_split_cil();
|
|
|
|
sepol_magisk_rules();
|
|
sepol_allow(SEPOL_PROC_DOMAIN, ALL, ALL, ALL);
|
|
dump_policydb("/magisk_sepolicy");
|
|
|
|
// Load policy to kernel so we can label rootfs
|
|
if (load_sepol)
|
|
dump_policydb(SELINUX_LOAD);
|
|
|
|
// Remove OnePlus stupid debug sepolicy and use our own
|
|
if (access("/sepolicy_debug", F_OK) == 0) {
|
|
unlink("/sepolicy_debug");
|
|
link("/magisk_sepolicy", "/sepolicy_debug");
|
|
}
|
|
|
|
// Enable selinux functions
|
|
selinux_builtin_impl();
|
|
|
|
return patch_init;
|
|
}
|
|
|
|
bool MagiskInit::read_dt_fstab(const char *mnt_point, char *partname, char *partfs) {
|
|
char path[128];
|
|
int fd;
|
|
sprintf(path, "%s/fstab/%s/dev", cmd.dt_dir, mnt_point);
|
|
if ((fd = xopen(path, O_RDONLY | O_CLOEXEC)) >= 0) {
|
|
read(fd, path, sizeof(path));
|
|
close(fd);
|
|
char *name = rtrim(strrchr(path, '/') + 1);
|
|
sprintf(partname, "%s%s", name, strend(name, cmd.slot) ? cmd.slot : "");
|
|
sprintf(path, "%s/fstab/%s/type", cmd.dt_dir, mnt_point);
|
|
if ((fd = xopen(path, O_RDONLY | O_CLOEXEC)) >= 0) {
|
|
read(fd, partfs, 32);
|
|
close(fd);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
#define umount_root(part) \
|
|
if (mnt_##part) \
|
|
umount("/" #part);
|
|
|
|
void MagiskInit::cleanup() {
|
|
umount(SELINUX_MNT);
|
|
umount("/sys");
|
|
umount("/proc");
|
|
umount_root(system);
|
|
umount_root(vendor);
|
|
umount_root(product);
|
|
umount_root(odm);
|
|
}
|
|
|
|
static inline void patch_socket_name(const char *path) {
|
|
uint8_t *buf;
|
|
char name[sizeof(MAIN_SOCKET)];
|
|
size_t size;
|
|
mmap_rw(path, buf, size);
|
|
for (int i = 0; i < size; ++i) {
|
|
if (memcmp(buf + i, MAIN_SOCKET, sizeof(MAIN_SOCKET)) == 0) {
|
|
gen_rand_str(name, sizeof(name));
|
|
memcpy(buf + i, name, sizeof(name));
|
|
i += sizeof(name);
|
|
}
|
|
if (memcmp(buf + i, LOG_SOCKET, sizeof(LOG_SOCKET)) == 0) {
|
|
gen_rand_str(name, sizeof(name));
|
|
memcpy(buf + i, name, sizeof(name));
|
|
i += sizeof(name);
|
|
}
|
|
}
|
|
munmap(buf, size);
|
|
}
|
|
|
|
void MagiskInit::setup_overlay() {
|
|
char path[128];
|
|
int fd;
|
|
|
|
// Wait for early-init start
|
|
while (access(EARLYINIT, F_OK) != 0)
|
|
usleep(10);
|
|
setcon("u:r:" SEPOL_PROC_DOMAIN ":s0");
|
|
unlink(EARLYINIT);
|
|
|
|
// Mount the /sbin tmpfs overlay
|
|
xmount("tmpfs", "/sbin", "tmpfs", 0, nullptr);
|
|
chmod("/sbin", 0755);
|
|
setfilecon("/sbin", "u:object_r:rootfs:s0");
|
|
|
|
// Dump binaries
|
|
mkdir(MAGISKTMP, 0755);
|
|
fd = xopen(MAGISKTMP "/config", O_WRONLY | O_CREAT, 0000);
|
|
write(fd, config.buf, config.sz);
|
|
close(fd);
|
|
fd = xopen("/sbin/magiskinit", O_WRONLY | O_CREAT, 0755);
|
|
write(fd, init.buf, init.sz);
|
|
close(fd);
|
|
dump_magisk("/sbin/magisk", 0755);
|
|
patch_socket_name("/sbin/magisk");
|
|
setfilecon("/sbin/magisk", "u:object_r:" SEPOL_FILE_DOMAIN ":s0");
|
|
setfilecon("/sbin/magiskinit", "u:object_r:" SEPOL_FILE_DOMAIN ":s0");
|
|
|
|
// Create applet symlinks
|
|
for (int i = 0; applet_names[i]; ++i) {
|
|
sprintf(path, "/sbin/%s", applet_names[i]);
|
|
xsymlink("/sbin/magisk", path);
|
|
}
|
|
for (int i = 0; init_applet[i]; ++i) {
|
|
sprintf(path, "/sbin/%s", init_applet[i]);
|
|
xsymlink("/sbin/magiskinit", path);
|
|
}
|
|
|
|
// Create symlinks pointing back to /root
|
|
DIR *dir = xopendir("/root");
|
|
struct dirent *entry;
|
|
fd = xopen("/sbin", O_RDONLY);
|
|
while((entry = xreaddir(dir))) {
|
|
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
|
|
continue;
|
|
snprintf(path, PATH_MAX, "/root/%s", entry->d_name);
|
|
xsymlinkat(path, fd, entry->d_name);
|
|
}
|
|
closedir(dir);
|
|
close(fd);
|
|
|
|
close(xopen(EARLYINITDONE, O_RDONLY | O_CREAT, 0));
|
|
exit(0);
|
|
}
|
|
|
|
void MagiskInit::re_exec_init() {
|
|
cleanup();
|
|
execv("/init", argv);
|
|
exit(1);
|
|
}
|
|
|
|
void MagiskInit::start() {
|
|
// Prevent file descriptor confusion
|
|
mknod("/null", S_IFCHR | 0666, makedev(1, 3));
|
|
int null = open("/null", O_RDWR | O_CLOEXEC);
|
|
unlink("/null");
|
|
xdup3(null, STDIN_FILENO, O_CLOEXEC);
|
|
xdup3(null, STDOUT_FILENO, O_CLOEXEC);
|
|
xdup3(null, STDERR_FILENO, O_CLOEXEC);
|
|
if (null > STDERR_FILENO)
|
|
close(null);
|
|
|
|
load_kernel_info();
|
|
|
|
full_read("/init", &init.buf, &init.sz);
|
|
full_read("/.backup/.magisk", &config.buf, &config.sz);
|
|
|
|
preset();
|
|
early_mount();
|
|
setup_rootfs();
|
|
}
|
|
|
|
void MagiskInit::test() {
|
|
cmdline_logging();
|
|
log_cb.ex = nop_ex;
|
|
|
|
chdir(dirname(argv[0]));
|
|
chroot(".");
|
|
chdir("/");
|
|
|
|
load_kernel_info();
|
|
preset();
|
|
early_mount();
|
|
setup_rootfs();
|
|
cleanup();
|
|
}
|
|
|
|
static int test_main(int argc, char *argv[]) {
|
|
MagiskInit init(argv);
|
|
init.test();
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
umask(0);
|
|
|
|
for (int i = 0; init_applet[i]; ++i) {
|
|
if (strcmp(basename(argv[0]), init_applet[i]) == 0)
|
|
return (*init_applet_main[i])(argc, argv);
|
|
}
|
|
|
|
if (argc > 1 && strcmp(argv[1], "-x") == 0) {
|
|
if (strcmp(argv[2], "magisk") == 0)
|
|
return dump_magisk(argv[3], 0755);
|
|
else if (strcmp(argv[2], "manager") == 0)
|
|
return dump_manager(argv[3], 0644);
|
|
}
|
|
|
|
MagiskInit init(argv);
|
|
|
|
// Run the main routine
|
|
init.start();
|
|
|
|
// Close all file descriptors
|
|
for (int i = 0; i < 30; ++i)
|
|
close(i);
|
|
|
|
// Launch daemon to setup overlay
|
|
if (fork_dont_care() == 0)
|
|
init.setup_overlay();
|
|
|
|
init.re_exec_init();
|
|
}
|