Magisk/native/jni/init/early_mount.cpp

188 lines
4.6 KiB
C++
Raw Normal View History

2019-05-27 09:29:43 +02:00
#include <sys/mount.h>
#include <sys/sysmacros.h>
#include <string.h>
#include <stdio.h>
#include <utils.h>
#include <logging.h>
2019-06-16 21:45:32 +02:00
#include <selinux.h>
2019-05-27 09:29:43 +02:00
#include "init.h"
using namespace std;
2019-05-27 11:55:46 +02:00
struct devinfo {
int major;
int minor;
char devname[32];
char partname[32];
};
static vector<devinfo> dev_list;
static void parse_device(devinfo *dev, const char *uevent) {
2019-05-27 09:29:43 +02:00
dev->partname[0] = '\0';
2019-05-27 11:55:46 +02:00
parse_prop_file(uevent, [=](string_view key, string_view value) -> bool {
if (key == "MAJOR")
dev->major = atoi(value.data());
else if (key == "MINOR")
dev->minor = atoi(value.data());
else if (key == "DEVNAME")
strcpy(dev->devname, value.data());
else if (key == "PARTNAME")
strcpy(dev->partname, value.data());
2019-05-27 09:29:43 +02:00
2019-05-27 11:55:46 +02:00
return true;
});
}
2019-05-27 09:29:43 +02:00
static void collect_devices() {
char path[128];
struct dirent *entry;
2019-05-27 11:55:46 +02:00
devinfo dev;
2019-05-27 09:29:43 +02:00
DIR *dir = xopendir("/sys/dev/block");
if (dir == nullptr)
return;
while ((entry = readdir(dir))) {
if (entry->d_name == "."sv || entry->d_name == ".."sv)
continue;
sprintf(path, "/sys/dev/block/%s/uevent", entry->d_name);
parse_device(&dev, path);
dev_list.push_back(dev);
}
closedir(dir);
}
2019-06-24 10:21:33 +02:00
static dev_t setup_block(const char *partname, char *block_dev = nullptr) {
2019-05-27 09:29:43 +02:00
if (dev_list.empty())
collect_devices();
for (;;) {
for (auto &dev : dev_list) {
if (strcasecmp(dev.partname, partname) == 0) {
xmkdir("/dev", 0755);
if (block_dev) {
sprintf(block_dev, "/dev/block/%s", dev.devname);
xmkdir("/dev/block", 0755);
}
LOGD("Found %s: [%s] (%d, %d)\n", dev.partname, dev.devname, dev.major, dev.minor);
2019-06-24 10:21:33 +02:00
dev_t rdev = makedev(dev.major, dev.minor);
mknod(block_dev ? block_dev : "/dev/root", S_IFBLK | 0600, rdev);
return rdev;
}
2019-05-27 09:29:43 +02:00
}
// Wait 10ms and try again
usleep(10000);
dev_list.clear();
collect_devices();
2019-05-27 09:29:43 +02:00
}
}
2019-06-22 12:14:33 +02:00
bool MagiskInit::read_dt_fstab(const char *name, char *partname, char *fstype) {
2019-05-27 09:29:43 +02:00
char path[128];
int fd;
2019-06-16 07:25:09 +02:00
sprintf(path, "%s/fstab/%s/dev", cmd->dt_dir, name);
2019-05-27 09:29:43 +02:00
if ((fd = xopen(path, O_RDONLY | O_CLOEXEC)) >= 0) {
read(fd, path, sizeof(path));
close(fd);
// Some custom treble use different names, so use what we read
char *part = rtrim(strrchr(path, '/') + 1);
2019-06-16 07:25:09 +02:00
sprintf(partname, "%s%s", part, strend(part, cmd->slot) ? cmd->slot : "");
sprintf(path, "%s/fstab/%s/type", cmd->dt_dir, name);
2019-05-27 09:29:43 +02:00
if ((fd = xopen(path, O_RDONLY | O_CLOEXEC)) >= 0) {
2019-05-27 11:55:46 +02:00
read(fd, fstype, 32);
2019-05-27 09:29:43 +02:00
close(fd);
return true;
}
}
return false;
}
#define link_root(name) \
if (is_lnk("/system_root" name)) \
cp_afc("/system_root" name, name)
#define mount_root(name) \
if (!is_lnk("/" #name) && read_dt_fstab(#name, partname, fstype)) { \
LOGD("Early mount " #name "\n"); \
setup_block(partname, block_dev); \
xmkdir("/" #name, 0755); \
xmount(block_dev, "/" #name, fstype, MS_RDONLY, nullptr); \
mnt_##name = true; \
}
2019-06-16 21:45:32 +02:00
void LegacyInit::early_mount() {
2019-05-27 09:29:43 +02:00
char partname[32];
char fstype[32];
char block_dev[64];
2019-06-16 21:45:32 +02:00
mount_root(system);
mount_root(vendor);
mount_root(product);
mount_root(odm);
}
2019-05-27 09:29:43 +02:00
void SARCompatInit::early_mount() {
2019-06-16 21:45:32 +02:00
char partname[32];
char fstype[32];
char block_dev[64];
LOGD("Early mount system_root\n");
sprintf(partname, "system%s", cmd->slot);
setup_block(partname, block_dev);
xmkdir("/system_root", 0755);
if (xmount(block_dev, "/system_root", "ext4", MS_RDONLY, nullptr))
xmount(block_dev, "/system_root", "erofs", MS_RDONLY, nullptr);
xmkdir("/system", 0755);
xmount("/system_root/system", "/system", nullptr, MS_BIND, nullptr);
link_root("/vendor");
link_root("/product");
link_root("/odm");
2019-05-27 09:29:43 +02:00
mount_root(vendor);
mount_root(product);
mount_root(odm);
}
2019-06-16 21:45:32 +02:00
static void switch_root(const string &path) {
LOGD("Switch root to %s\n", path.data());
vector<string> mounts;
parse_mnt("/proc/mounts", [&](mntent *me) {
if (me->mnt_dir != "/"sv && me->mnt_dir != path)
mounts.emplace_back(me->mnt_dir);
return true;
});
for (auto &dir : mounts) {
auto new_path = path + dir;
mkdir(new_path.data(), 0755);
xmount(dir.data(), new_path.c_str(), nullptr, MS_MOVE, nullptr);
}
chdir(path.data());
xmount(path.data(), "/", nullptr, MS_MOVE, nullptr);
chroot(".");
}
void SARInit::early_mount() {
char partname[32];
LOGD("Early mount system_root\n");
sprintf(partname, "system%s", cmd->slot);
2019-06-24 10:21:33 +02:00
system_dev = setup_block(partname);
xmkdir("/system_root", 0755);
if (xmount("/dev/root", "/system_root", "ext4", MS_RDONLY, nullptr))
xmount("/dev/root", "/system_root", "erofs", MS_RDONLY, nullptr);
switch_root("/system_root");
}
2019-06-16 21:45:32 +02:00
#define umount_root(name) \
if (mnt_##name) \
umount("/" #name);
2019-06-22 12:14:33 +02:00
void MagiskInit::cleanup() {
BaseInit::cleanup();
2019-06-16 21:45:32 +02:00
umount(SELINUX_MNT);
umount_root(system);
umount_root(vendor);
umount_root(product);
umount_root(odm);
}