int uevent_dump_main(int argc, char *argv[]) { int opt; static struct option long_options[] = { {"help", no_argument, 0, 'h'}, {0, 0, 0, 0} }; int long_index = 0; while ((opt = getopt_long(argc, argv, "h", long_options, &long_index)) != -1) { switch (opt) { case 'h': uevent_dump_usage(false); return EXIT_SUCCESS; default: uevent_dump_usage(true); return EXIT_FAILURE; } } // There should be no other arguments if (argc - optind != 0) { uevent_dump_usage(true); return EXIT_FAILURE; } LOGV("mbtool version %s (%s)", get_mbtool_version(), get_git_version()); // Start probing for devices device_init(true); // Kill uevent thread and close uevent socket device_close(); return EXIT_SUCCESS; }
int init_main(int argc, char *argv[]) { for (int i = 1; i < argc; ++i) { if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) { init_usage(true); return EXIT_SUCCESS; } } umask(0); mkdir("/dev", 0755); mkdir("/proc", 0755); mkdir("/sys", 0755); mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"); mkdir("/dev/pts", 0755); mkdir("/dev/socket", 0755); mount("devpts", "/dev/pts", "devpts", 0, nullptr); mount("proc", "/proc", "proc", 0, nullptr); mount("sysfs", "/sys", "sysfs", 0, nullptr); open_devnull_stdio(); util::log_set_logger(std::make_shared<util::KmsgLogger>()); if (klogctl(KLOG_CONSOLE_LEVEL, nullptr, 8) < 0) { LOGE("Failed to set loglevel: %s", strerror(errno)); } LOGV("Booting up with version %s (%s)", get_mbtool_version(), get_git_version()); // Start probing for devices device_init(); std::string fstab = find_fstab(); if (fstab.empty()) { LOGE("Failed to find a suitable fstab file"); emergency_reboot(); return EXIT_FAILURE; } mkdir("/system", 0755); mkdir("/cache", 0770); mkdir("/data", 0771); util::chown("/cache", "system", "cache", 0); util::chown("/data", "system", "system", 0); fix_arter97(); // Mount fstab and write new redacted version if (!mount_fstab(fstab, true)) { LOGE("Failed to mount fstab"); emergency_reboot(); return EXIT_FAILURE; } LOGE("Successfully mounted fstab"); fix_file_contexts(); add_mbtool_services(); strip_manual_mounts(); struct stat sb; if (stat("/sepolicy", &sb) == 0) { if (!patch_sepolicy("/sepolicy", "/sepolicy")) { LOGW("Failed to patch /sepolicy"); emergency_reboot(); return EXIT_FAILURE; } } // Kill uevent thread and close uevent socket device_close(); // Unmount partitions umount("/dev/pts"); umount("/dev"); umount("/proc"); umount("/sys"); // Do not remove these as Android 6.0 init's stage 1 no longer creates these // (platform/system/core commit a1f6a4b13921f61799be14a2544bdbf95958eae7) //rmdir("/dev"); //rmdir("/proc"); //rmdir("/sys"); // Start real init unlink("/init"); rename("/init.orig", "/init"); LOGD("Launching real init ..."); execlp("/init", "/init", nullptr); LOGE("Failed to exec real init: %s", strerror(errno)); emergency_reboot(); return EXIT_FAILURE; }
static bool initialize_adb() { bool ret = true; const char *version = get_mbtool_version(); ret = write_file("/sys/class/android_usb/android0/enable", "0", 1) && ret; ret = write_file("/sys/class/android_usb/android0/idVendor", "18D1", 4) && ret; ret = write_file("/sys/class/android_usb/android0/idProduct", "4EE7", 4) && ret; ret = write_file("/sys/class/android_usb/android0/f_ffs/aliases", "adb", 3) && ret; ret = write_file("/sys/class/android_usb/android0/functions", "adb", 3) && ret; ret = write_file("/sys/class/android_usb/android0/iManufacturer", "mbtool", 6) && ret; ret = write_file("/sys/class/android_usb/android0/iProduct", "miniadbd", 8) && ret; ret = write_file("/sys/class/android_usb/android0/iSerial", version, strlen(version)) && ret; ret = write_file("/sys/class/android_usb/android0/enable", "1", 1) && ret; // Create functionfs paths if (!util::mkdir_recursive(USB_FFS_ADB_PATH, 0770)) { LOGW("%s: Failed to create directory: %s", USB_FFS_ADB_PATH, strerror(errno)); ret = false; } if (!util::mount("adb", USB_FFS_ADB_PATH, "functionfs", 0, "")) { LOGW("%s: Failed to mount functionfs: %s", USB_FFS_ADB_PATH, strerror(errno)); ret = false; } // Set environment variables ret = setenv("PATH", "/system/bin", 1) == 0 && ret; ret = setenv("LD_LIBRARY_PATH", "/system/lib", 1) == 0 && ret; ret = setenv("ANDROID_DATA", "/data", 1) == 0 && ret; ret = setenv("ANDROID_ROOT", "/system", 1) == 0 && ret; // Use TWRP's legacy property workspace hack. TouchWiz's sh binary segfaults // if there's no property service (i.e. no /dev/__properties__ and no valid // ANDROID_PROPERTY_WORKSPACE environment variable). This doesn't actually // start a "real" properties service (getprop and setprop will never work), // but it's enough to prevent the segfaults. char tmp[32]; int propfd, propsz; legacy_properties_init(); // Load /default.prop std::unordered_map<std::string, std::string> props; util::file_get_all_properties("/default.prop", &props); for (auto const &pair : props) { legacy_property_set(pair.first.c_str(), pair.second.c_str()); } // Load /system/build.prop props.clear(); util::file_get_all_properties("/system/build.prop", &props); for (auto const &pair : props) { legacy_property_set(pair.first.c_str(), pair.second.c_str()); } legacy_get_property_workspace(&propfd, &propsz); snprintf(tmp, sizeof(tmp), "%d,%d", dup(propfd), propsz); char *orig_prop_env = getenv("ANDROID_PROPERTY_WORKSPACE"); LOGD("Original properties environment: %s", orig_prop_env ? orig_prop_env : "null"); setenv("ANDROID_PROPERTY_WORKSPACE", tmp, 1); LOGD("Switched to legacy properties environment: %s", tmp); return ret; }
int daemon_main(int argc, char *argv[]) { int opt; bool fork_flag = false; bool replace_flag = false; static struct option long_options[] = { {"daemonize", no_argument, 0, 'd'}, {"replace", no_argument, 0, 'r'}, {"help", no_argument, 0, 'h'}, {0, 0, 0, 0} }; int long_index = 0; while ((opt = getopt_long(argc, argv, "drh", long_options, &long_index)) != -1) { switch (opt) { case 'd': fork_flag = true; break; case 'r': replace_flag = true; break; case 'h': daemon_usage(0); return EXIT_SUCCESS; default: daemon_usage(1); return EXIT_FAILURE; } } // There should be no other arguments if (argc - optind != 0) { daemon_usage(1); return EXIT_FAILURE; } // Patch SELinux policy to make init permissive patch_loaded_sepolicy(); // Allow untrusted_app to connect to our daemon patch_sepolicy_daemon(); // Set version property if we're the system mbtool (i.e. launched by init) // Possible to override this with another program by double forking, letting // 2nd child reparent to init, and then calling execve("/mbtool", ...), but // meh ... if (getppid() == 1) { if (!util::set_property("ro.multiboot.version", get_mbtool_version())) { std::printf("Failed to set 'ro.multiboot.version' to '%s'\n", get_mbtool_version()); } } if (replace_flag) { PROCTAB *proc = openproc(PROC_FILLCOM | PROC_FILLSTAT); if (proc) { pid_t curpid = getpid(); while (proc_t *info = readproc(proc, nullptr)) { if (strcmp(info->cmd, "mbtool") == 0 // This is mbtool && info->cmdline // And we can see the command line && info->cmdline[1] // And argc > 1 && strstr(info->cmdline[1], "daemon") // And it's a daemon process && info->tid != curpid) { // And we're not killing ourself // Kill the daemon process std::printf("Killing PID %d\n", info->tid); kill(info->tid, SIGTERM); } freeproc(info); } closeproc(proc); } // Give processes a chance to exit usleep(500000); } // Set up logging if (!util::mkdir_parent(MULTIBOOT_LOG_DAEMON, 0775) && errno != EEXIST) { fprintf(stderr, "Failed to create parent directory of %s: %s\n", MULTIBOOT_LOG_DAEMON, strerror(errno)); return EXIT_FAILURE; } autoclose::file fp(autoclose::fopen(MULTIBOOT_LOG_DAEMON, "w")); if (!fp) { fprintf(stderr, "Failed to open log file %s: %s\n", MULTIBOOT_LOG_DAEMON, strerror(errno)); return EXIT_FAILURE; } fix_multiboot_permissions(); // mbtool logging log::log_set_logger(std::make_shared<log::StdioLogger>(fp.get(), true)); if (fork_flag) { run_daemon_fork(); } else { return run_daemon() ? EXIT_SUCCESS : EXIT_FAILURE; } }