diff --git a/native/jni/init/getinfo.cpp b/native/jni/init/getinfo.cpp index c5103fe4d..42fba9263 100644 --- a/native/jni/init/getinfo.cpp +++ b/native/jni/init/getinfo.cpp @@ -15,57 +15,58 @@ vector mount_list; template using chars = integer_sequence; +// If quoted, parsing ends when we find char in [breaks] +// If not quoted, parsing ends when we find char in [breaks] + [escapes] template -static string extract_qutoed_str_until(chars, chars, - string_view sv, size_t &begin, bool "ed) { +static string extract_quoted_str_until(chars, chars, + string_view str, size_t &pos, bool "ed) { string result; char match_array[] = {escapes..., breaks..., '"'}; - string_view match(match_array, sizeof(match_array)); - for (auto end = begin;; ++end) { - end = sv.find_first_of(match, end); - if (end == string_view::npos || ((sv[end] == breaks) || ...) || - (!quoted && ((sv[end] == escapes) || ...))) { - result.append(sv.substr(begin, end - begin)); - begin = end; + string_view match(match_array, std::size(match_array)); + for (size_t cur = pos;; ++cur) { + cur = str.find_first_of(match, cur); + if (cur == string_view::npos || + ((str[cur] == breaks) || ...) || + (!quoted && ((str[cur] == escapes) || ...))) { + result.append(str.substr(pos, cur - pos)); + pos = cur; return result; } - if (sv[end] == '"') { + if (str[cur] == '"') { quoted = !quoted; - result.append(sv.substr(begin, end - begin)); - begin = end + 1; + result.append(str.substr(pos, cur - pos)); + pos = cur + 1; } } } -//[pair_split][key][assign_split][assign][assign_split][value][pair_split] -template -static auto parse(chars, chars, chars, string_view sv) { - vector> kv; - char next_array[] = {pair_spilt...}; - string_view next(next_array, sizeof(next_array)); - char skip_array[] = {assign..., assign_split...}; - string_view skip(skip_array, sizeof(skip_array)); +// Parse string into key value pairs. +// The string format: [delim][key][padding]=[padding][value][delim] +template +static kv_pairs parse_impl(chars, string_view str) { + kv_pairs kv; + char skip_array[] = {'=', padding...}; + string_view skip(skip_array, std::size(skip_array)); bool quoted = false; - for (size_t cur = 0u; cur < sv.size(); - cur = sv.find_first_not_of(next, cur)) { - auto key = extract_qutoed_str_until(chars{}, - chars{}, sv, cur, quoted); - cur = sv.find_first_not_of(skip, cur); - if (((cur == string_view::npos) || ... || (sv[cur] == pair_spilt))) { + for (size_t pos = 0u; pos < str.size(); pos = str.find_first_not_of(delim, pos)) { + auto key = extract_quoted_str_until( + chars{}, chars<'='>{}, str, pos, quoted); + pos = str.find_first_not_of(skip, pos); + if (pos == string_view::npos || str[pos] == delim) { kv.emplace_back(key, ""); continue; } - auto value = extract_qutoed_str_until(chars{}, chars<>{}, sv, cur, quoted); + auto value = extract_quoted_str_until(chars{}, chars<>{}, str, pos, quoted); kv.emplace_back(key, value); } return kv; } -static auto parse_cmdline(string_view sv) { - return parse(chars<' '>{}, chars<'='>{}, chars<>{}, sv); +static kv_pairs parse_cmdline(string_view str) { + return parse_impl<' '>(chars<>{}, str); } -static auto parse_bootconfig(string_view sv) { - return parse(chars<'\n'>{}, chars<'='>{}, chars<' '>{}, sv); +static kv_pairs parse_bootconfig(string_view str) { + return parse_impl<'\n'>(chars<' '>{}, str); } #define test_bit(bit, array) (array[bit / 8] & (1 << (bit % 8))) @@ -158,17 +159,54 @@ void setup_klog() { } } -#define read_dt(name, key) \ -sprintf(file_name, "%s/" name, cmd->dt_dir); \ -if (access(file_name, R_OK) == 0){ \ - string data = full_read(file_name); \ - if (!data.empty()) { \ - data.pop_back(); \ - strcpy(cmd->key, data.data()); \ - } \ +void BootConfig::set(const kv_pairs &kv) { + for (const auto &[key, value] : kv) { + if (key == "androidboot.slot_suffix") { + strlcpy(slot, value.data(), sizeof(slot)); + } else if (key == "androidboot.slot") { + slot[0] = '_'; + strlcpy(slot + 1, value.data(), sizeof(slot) - 1); + } else if (key == "skip_initramfs") { + skip_initramfs = true; + } else if (key == "androidboot.force_normal_boot") { + force_normal_boot = !value.empty() && value[0] == '1'; + } else if (key == "rootwait") { + rootwait = true; + } else if (key == "androidboot.android_dt_dir") { + strlcpy(dt_dir, value.data(), sizeof(dt_dir)); + } else if (key == "androidboot.hardware") { + strlcpy(hardware, value.data(), sizeof(hardware)); + } else if (key == "androidboot.hardware.platform") { + strlcpy(hardware_plat, value.data(), sizeof(hardware_plat)); + } else if (key == "androidboot.fstab_suffix") { + strlcpy(fstab_suffix, value.data(), sizeof(fstab_suffix)); + } + } } -void load_kernel_info(cmdline *cmd) { +void BootConfig::print() { + LOGD("skip_initramfs=[%d]\n", skip_initramfs); + LOGD("force_normal_boot=[%d]\n", force_normal_boot); + LOGD("rootwait=[%d]\n", rootwait); + LOGD("slot=[%s]\n", slot); + LOGD("dt_dir=[%s]\n", dt_dir); + LOGD("fstab_suffix=[%s]\n", fstab_suffix); + LOGD("hardware=[%s]\n", hardware); + LOGD("hardware.platform=[%s]\n", hardware_plat); +} + +#define read_dt(name, key) \ +snprintf(file_name, sizeof(file_name), "%s/" name, config->key); \ +if (access(file_name, R_OK) == 0) { \ + string data = full_read(file_name); \ + if (!data.empty()) { \ + data.pop_back(); \ + LOGD(name "=[%s]\n", data.data()); \ + strlcpy(config->key, data.data(), sizeof(config->key)); \ + } \ +} + +void load_kernel_info(BootConfig *config) { // Get kernel data using procfs and sysfs xmkdir("/proc", 0755); xmount("proc", "/proc", "proc", 0, nullptr); @@ -181,85 +219,31 @@ void load_kernel_info(cmdline *cmd) { // Log to kernel setup_klog(); - for (const auto&[key, value] : parse_cmdline(full_read("/proc/cmdline"))) { - if (key == "androidboot.slot_suffix") { - strcpy(cmd->slot, value.data()); - } else if (key == "androidboot.slot") { - cmd->slot[0] = '_'; - strcpy(cmd->slot + 1, value.data()); - } else if (key == "skip_initramfs") { - cmd->skip_initramfs = true; - } else if (key == "androidboot.force_normal_boot") { - cmd->force_normal_boot = value[0] == '1'; - } else if (key == "rootwait") { - cmd->rootwait = true; - } else if (key == "androidboot.android_dt_dir") { - strcpy(cmd->dt_dir, value.data()); - } else if (key == "androidboot.hardware") { - strcpy(cmd->hardware, value.data()); - } else if (key == "androidboot.hardware.platform") { - strcpy(cmd->hardware_plat, value.data()); - } else if (key == "androidboot.fstab_suffix") { - strcpy(cmd->fstab_suffix, value.data()); - } - } - + config->set(parse_cmdline(full_read("/proc/cmdline"))); LOGD("Kernel cmdline info:\n"); - LOGD("skip_initramfs=[%d]\n", cmd->skip_initramfs); - LOGD("force_normal_boot=[%d]\n", cmd->force_normal_boot); - LOGD("rootwait=[%d]\n", cmd->rootwait); - LOGD("slot=[%s]\n", cmd->slot); - LOGD("dt_dir=[%s]\n", cmd->dt_dir); - LOGD("fstab_suffix=[%s]\n", cmd->fstab_suffix); - LOGD("hardware=[%s]\n", cmd->hardware); - LOGD("hardware.platform=[%s]\n", cmd->hardware_plat); - - for (const auto&[key, value] : parse_bootconfig(full_read("/proc/bootconfig"))) { - if (key == "androidboot.slot_suffix") { - strcpy(cmd->slot, value.data()); - } else if (key == "androidboot.force_normal_boot") { - cmd->force_normal_boot = value[0] == '1'; - } else if (key == "androidboot.android_dt_dir") { - strcpy(cmd->dt_dir, value.data()); - } else if (key == "androidboot.hardware") { - strcpy(cmd->hardware, value.data()); - } else if (key == "androidboot.hardware.platform") { - strcpy(cmd->hardware_plat, value.data()); - } else if (key == "androidboot.fstab_suffix") { - strcpy(cmd->fstab_suffix, value.data()); - } - } + config->print(); + config->set(parse_bootconfig(full_read("/proc/bootconfig"))); LOGD("Boot config info:\n"); - LOGD("force_normal_boot=[%d]\n", cmd->force_normal_boot); - LOGD("slot=[%s]\n", cmd->slot); - LOGD("dt_dir=[%s]\n", cmd->dt_dir); - LOGD("fstab_suffix=[%s]\n", cmd->fstab_suffix); - LOGD("hardware=[%s]\n", cmd->hardware); - LOGD("hardware.platform=[%s]\n", cmd->hardware_plat); + config->print(); parse_prop_file("/.backup/.magisk", [=](auto key, auto value) -> bool { if (key == "RECOVERYMODE" && value == "true") { LOGD("Running in recovery mode, waiting for key...\n"); - cmd->skip_initramfs = !check_key_combo(); + config->skip_initramfs = !check_key_combo(); return false; } return true; }); - if (cmd->dt_dir[0] == '\0') - strcpy(cmd->dt_dir, DEFAULT_DT_DIR); + if (config->dt_dir[0] == '\0') + strlcpy(config->dt_dir, DEFAULT_DT_DIR, sizeof(config->dt_dir)); + LOGD("Device tree:\n"); char file_name[128]; read_dt("fstab_suffix", fstab_suffix) read_dt("hardware", hardware) read_dt("hardware.platform", hardware_plat) - - LOGD("Device tree info:\n"); - LOGD("dt_dir=[%s]\n", cmd->dt_dir); - LOGD("fstab_suffix=[%s]\n", cmd->fstab_suffix); - LOGD("hardware=[%s]\n", cmd->hardware); - LOGD("hardware.platform=[%s]\n", cmd->hardware_plat); } bool check_two_stage() { diff --git a/native/jni/init/init.cpp b/native/jni/init/init.cpp index 720b9fabc..734c7976d 100644 --- a/native/jni/init/init.cpp +++ b/native/jni/init/init.cpp @@ -56,7 +56,7 @@ static int dump_manager(const char *path, mode_t mode) { class RecoveryInit : public BaseInit { public: - RecoveryInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {} + RecoveryInit(char *argv[], BootConfig *cmd) : BaseInit(argv, cmd) {} void start() override { LOGD("Ramdisk is recovery, abort\n"); rename("/.backup/init", "/init"); @@ -141,25 +141,25 @@ int main(int argc, char *argv[]) { return 1; BaseInit *init; - cmdline cmd{}; + BootConfig config{}; if (argc > 1 && argv[1] == "selinux_setup"sv) { setup_klog(); init = new SecondStageInit(argv); } else { // This will also mount /sys and /proc - load_kernel_info(&cmd); + load_kernel_info(&config); - if (cmd.skip_initramfs) - init = new SARInit(argv, &cmd); - else if (cmd.force_normal_boot) - init = new FirstStageInit(argv, &cmd); + if (config.skip_initramfs) + init = new SARInit(argv, &config); + else if (config.force_normal_boot) + init = new FirstStageInit(argv, &config); else if (access("/sbin/recovery", F_OK) == 0 || access("/system/bin/recovery", F_OK) == 0) - init = new RecoveryInit(argv, &cmd); + init = new RecoveryInit(argv, &config); else if (check_two_stage()) - init = new FirstStageInit(argv, &cmd); + init = new FirstStageInit(argv, &config); else - init = new RootFSInit(argv, &cmd); + init = new RootFSInit(argv, &config); } // Run the main routine diff --git a/native/jni/init/init.hpp b/native/jni/init/init.hpp index 8b7258cdf..88edd6864 100644 --- a/native/jni/init/init.hpp +++ b/native/jni/init/init.hpp @@ -2,7 +2,9 @@ #include "raw_data.hpp" -struct cmdline { +using kv_pairs = std::vector>; + +struct BootConfig { bool skip_initramfs; bool force_normal_boot; bool rootwait; @@ -11,6 +13,9 @@ struct cmdline { char fstab_suffix[32]; char hardware[32]; char hardware_plat[32]; + + void set(const kv_pairs &); + void print(); }; struct fstab_entry { @@ -32,7 +37,7 @@ struct fstab_entry { extern std::vector mount_list; bool unxz(int fd, const uint8_t *buf, size_t size); -void load_kernel_info(cmdline *cmd); +void load_kernel_info(BootConfig *config); bool check_two_stage(); void setup_klog(); @@ -42,13 +47,13 @@ void setup_klog(); class BaseInit { protected: - cmdline *cmd = nullptr; + BootConfig *config = nullptr; char **argv = nullptr; [[noreturn]] void exec_init(); void read_dt_fstab(std::vector &fstab); public: - BaseInit(char *argv[], cmdline *cmd) : cmd(cmd), argv(argv) {} + BaseInit(char *argv[], BootConfig *config) : config(config), argv(argv) {} virtual ~BaseInit() = default; virtual void start() = 0; }; @@ -56,7 +61,7 @@ public: class MagiskInit : public BaseInit { protected: mmap_data self; - mmap_data config; + mmap_data magisk_config; std::string custom_rules_dir; void mount_with_dt(); @@ -64,7 +69,7 @@ protected: void setup_tmp(const char *path); void mount_rules_dir(const char *dev_base, const char *mnt_base); public: - MagiskInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {} + MagiskInit(char *argv[], BootConfig *cmd) : BaseInit(argv, cmd) {} }; class SARBase : virtual public MagiskInit { @@ -86,7 +91,7 @@ class FirstStageInit : public BaseInit { private: void prepare(); public: - FirstStageInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) { + FirstStageInit(char *argv[], BootConfig *cmd) : BaseInit(argv, cmd) { LOGD("%s\n", __FUNCTION__); }; void start() override { @@ -106,7 +111,7 @@ private: void early_mount(); void first_stage_prep(); public: - SARInit(char *argv[], cmdline *cmd) : MagiskInit(argv, cmd), is_two_stage(false) { + SARInit(char *argv[], BootConfig *cmd) : MagiskInit(argv, cmd), is_two_stage(false) { LOGD("%s\n", __FUNCTION__); }; void start() override { @@ -136,7 +141,7 @@ private: void early_mount(); public: - RootFSInit(char *argv[], cmdline *cmd) : MagiskInit(argv, cmd) { + RootFSInit(char *argv[], BootConfig *cmd) : MagiskInit(argv, cmd) { LOGD("%s\n", __FUNCTION__); } void start() override { diff --git a/native/jni/init/mount.cpp b/native/jni/init/mount.cpp index 714c3d2d8..527440e90 100644 --- a/native/jni/init/mount.cpp +++ b/native/jni/init/mount.cpp @@ -105,12 +105,12 @@ if (access(#val, F_OK) == 0) {\ } void BaseInit::read_dt_fstab(vector &fstab) { - if (access(cmd->dt_dir, F_OK) != 0) + if (access(config->dt_dir, F_OK) != 0) return; char cwd[128]; getcwd(cwd, sizeof(cwd)); - chdir(cmd->dt_dir); + chdir(config->dt_dir); run_finally cd([&]{ chdir(cwd); }); if (access("fstab", F_OK) != 0) @@ -159,7 +159,7 @@ void MagiskInit::mount_with_dt() { if (is_lnk(entry.mnt_point.data())) continue; // Derive partname from dev - sprintf(blk_info.partname, "%s%s", basename(entry.dev.data()), cmd->slot); + sprintf(blk_info.partname, "%s%s", basename(entry.dev.data()), config->slot); setup_block(true); xmkdir(entry.mnt_point.data(), 0755); xmount(blk_info.block_dev, entry.mnt_point.data(), entry.type.data(), MS_RDONLY, nullptr); @@ -300,7 +300,7 @@ void SARBase::backup_files() { self = mmap_data::ro("/proc/self/exe"); if (access("/.backup/.magisk", R_OK) == 0) - config = mmap_data::ro("/.backup/.magisk"); + magisk_config = mmap_data::ro("/.backup/.magisk"); } void SARBase::mount_system_root() { @@ -320,13 +320,13 @@ void SARBase::mount_system_root() { if (dev >= 0) goto mount_root; - sprintf(blk_info.partname, "system%s", cmd->slot); + sprintf(blk_info.partname, "system%s", config->slot); dev = setup_block(false); if (dev >= 0) goto mount_root; // Poll forever if rootwait was given in cmdline - } while (cmd->rootwait); + } while (config->rootwait); // We don't really know what to do at this point... LOGE("Cannot find root partition, abort\n"); @@ -396,7 +396,7 @@ void MagiskInit::setup_tmp(const char *path) { xmkdir(BLOCKDIR, 0); int fd = xopen(INTLROOT "/config", O_WRONLY | O_CREAT, 0); - xwrite(fd, config.buf, config.sz); + xwrite(fd, magisk_config.buf, magisk_config.sz); close(fd); fd = xopen("magiskinit", O_WRONLY | O_CREAT, 0755); xwrite(fd, self.buf, self.sz); diff --git a/native/jni/init/rootdir.cpp b/native/jni/init/rootdir.cpp index 6db917bf1..e7e44f230 100644 --- a/native/jni/init/rootdir.cpp +++ b/native/jni/init/rootdir.cpp @@ -372,7 +372,7 @@ void MagiskProxy::start() { // Backup stuffs before removing them self = mmap_data::ro("/sbin/magisk"); - config = mmap_data::ro("/.backup/.magisk"); + magisk_config = mmap_data::ro("/.backup/.magisk"); auto magisk = mmap_data::ro("/sbin/magisk32.xz"); auto magisk64 = mmap_data::ro("/sbin/magisk64.xz"); char custom_rules_dir[64]; diff --git a/native/jni/init/twostage.cpp b/native/jni/init/twostage.cpp index f2387349b..639e727e6 100644 --- a/native/jni/init/twostage.cpp +++ b/native/jni/init/twostage.cpp @@ -57,7 +57,7 @@ static void read_fstab_file(const char *fstab_file, vector &fstab) extern uint32_t patch_verity(void *buf, uint32_t size); void FirstStageInit::prepare() { - if (cmd->force_normal_boot) { + if (config->force_normal_boot) { xmkdirs(FSR "/system/bin", 0755); rename("/init" /* magiskinit */, FSR "/system/bin/init"); symlink("/system/bin/init", FSR "/init"); @@ -78,7 +78,7 @@ void FirstStageInit::prepare() { fstab_file[0] = '\0'; // Find existing fstab file - for (const char *suffix : { cmd->fstab_suffix, cmd->hardware, cmd->hardware_plat }) { + for (const char *suffix : {config->fstab_suffix, config->hardware, config->hardware_plat }) { if (suffix[0] == '\0') continue; for (const char *prefix: { "odm/etc/fstab", "vendor/etc/fstab", "fstab" }) { @@ -111,9 +111,9 @@ exit_loop: if (fstab_file[0] == '\0') { const char *suffix = - cmd->fstab_suffix[0] ? cmd->fstab_suffix : - (cmd->hardware[0] ? cmd->hardware : - (cmd->hardware_plat[0] ? cmd->hardware_plat : nullptr)); + config->fstab_suffix[0] ? config->fstab_suffix : + (config->hardware[0] ? config->hardware : + (config->hardware_plat[0] ? config->hardware_plat : nullptr)); if (suffix == nullptr) { LOGE("Cannot determine fstab suffix!\n"); return; @@ -241,7 +241,7 @@ void SARInit::first_stage_prep() { string tmp_dir = read_string(client); chdir(tmp_dir.data()); int cfg = xopen(INTLROOT "/config", O_WRONLY | O_CREAT, 0); - xwrite(cfg, config.buf, config.sz); + xwrite(cfg, magisk_config.buf, magisk_config.sz); close(cfg); restore_folder(ROOTOVL, overlays);