/* * This file is part of MultiROM. * * MultiROM is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * MultiROM is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MultiROM. If not, see . */ #include #include #include #include #include #include #include #include #include "devices.h" #include "log.h" #include "util.h" #include "../version.h" #define EXEC_MASK (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) #define REALDATA "/realdata" #define BOOT_DEV "/dev/block/mmcblk0p2" #define MULTIROM_BIN "multirom" #define BUSYBOX_BIN "busybox" #define KEEP_REALDATA "/dev/.keep_realdata" // Not defined in android includes? #define MS_RELATIME (1<<21) static char path_multirom[64] = { 0 }; static int find_multirom(void) { int i; struct stat info; static const char *paths[] = { REALDATA"/media/0/multirom", // 4.2 REALDATA"/media/multirom", NULL, }; for(i = 0; paths[i]; ++i) { if(stat(paths[i], &info) < 0) continue; strcpy(path_multirom, paths[i]); return 0; } return -1; } static int run_multirom_bin(char *path) { ERROR("Running multirom"); pid_t pID = fork(); if(pID == 0) { char * cmd[] = { path, NULL }; int res = execve(cmd[0], cmd, NULL); ERROR("exec failed %d %d %s\n", res, errno, strerror(errno)); _exit(127); } else { int status = 0; while(waitpid(pID, &status, WNOHANG) == 0) usleep(300000); ERROR("MultiROM exited with status %d", status); return status; } } static void run_multirom(void) { if(find_multirom() == -1) { ERROR("Could not find multirom folder!"); return; } char path[256]; struct stat info; // busybox sprintf(path, "%s/%s", path_multirom, BUSYBOX_BIN); if (stat(path, &info) < 0) { ERROR("Could not find busybox: %s", path); return; } chmod(path, EXEC_MASK); // restart after crash sprintf(path, "%s/restart_after_crash", path_multirom); int restart = (stat(path, &info) >= 0); // multirom sprintf(path, "%s/%s", path_multirom, MULTIROM_BIN); if (stat(path, &info) < 0) { ERROR("Could not find multirom: %s", path); return; } chmod(path, EXEC_MASK); do { if(run_multirom_bin(path) == 0) break; } while(restart); } struct part_info { uint64_t size; char *name; }; #define PARTS_SIZE 24 int find_data_dev(char *data_dev) { FILE *f = fopen("/proc/partitions", "r"); if(!f) return -1; int res = -1; struct part_info parts[PARTS_SIZE]; memset(parts, 0, sizeof(parts)); int i = 0; int y, part_ok; char *p; char line[1024]; // skip the first line fgets(line, sizeof(line), f); while(fgets(line, sizeof(line), f)) { p = strtok(line, " \t\n"); part_ok = 0; for(y = 0; p != NULL; ++y) { switch(y) { case 2: parts[i].size = atol(p); break; case 3: { free(parts[i].name); parts[i].name = malloc(strlen(p)+1); strcpy(parts[i].name, p); part_ok = 1; break; } } p = strtok(NULL, " \t\n"); } if(part_ok) { if(++i >= PARTS_SIZE) return -1; } } fclose(f); uint64_t max = 0; int idx = -1; for(y = 0; y < i; ++y) { if(strstr(parts[y].name, "mmcblk0p") != parts[y].name) continue; ERROR("got part %s, size %d", parts[y].name, (int)parts[y].size); if(parts[y].size > max) { idx = y; max = parts[y].size; } } if(idx == -1) goto exit; sprintf(data_dev, "/dev/block/%s", parts[idx].name); res = 0; ERROR("booting %s, size %d", parts[idx].name, (int)parts[idx].size); exit: for(y = 0; y < i; ++y) free(parts[y].name); return res; } int main(int argc, char *argv[]) { int i; for(i = 1; i < argc; ++i) { if(strcmp(argv[i], "-v") == 0) { printf("%d\n", VERSION_TRAMPOLINE); return 0; } } umask(000); // Init only the little we need, leave the rest for real init mkdir("/dev", 0755); mkdir("/dev/pts", 0755); mkdir("/dev/socket", 0755); mkdir("/proc", 0755); mkdir("/sys", 0755); mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755"); mount("devpts", "/dev/pts", "devpts", 0, NULL); mount("proc", "/proc", "proc", 0, NULL); mount("sysfs", "/sys", "sysfs", 0, NULL); klog_init(); ERROR("Running trampoline v%d\n", VERSION_TRAMPOLINE); ERROR("Initializing devices..."); devices_init(); ERROR("Done initializing"); int ok = 1; if(wait_for_file(BOOT_DEV, 5) < 0) { ERROR("Waing too long for data block dev"); ok = 0; } if(wait_for_file("/dev/graphics/fb0", 5) < 0) { ERROR("Waiting too long for fb0"); ok = 0; } // mount and run multirom from sdcard if(ok) { char data_dev[128]; mkdir(REALDATA, 0755); if (find_data_dev(data_dev) == 0 && mount(data_dev, REALDATA, "ext4", MS_RELATIME | MS_NOATIME, "user_xattr,acl,barrier=1,data=ordered,discard,nomblk_io_submit") >= 0) { run_multirom(); } else ERROR("Failed to mount /realdata %d\n", errno); } // close and destroy everything devices_close(); struct stat info; if(stat(KEEP_REALDATA, &info) < 0) { umount(REALDATA); umount("/dev/pts"); umount("/dev"); rmdir("/dev/pts"); rmdir("/dev/socket"); rmdir("/dev"); } umount("/proc"); umount("/sys"); rmdir("/proc"); rmdir("/sys"); chmod("/main_init", EXEC_MASK); // run the main init char *cmd[] = { "/main_init", (char *)0 }; int res = execve("/main_init", cmd, NULL); ERROR("execve returned %d %d %s\n", res, errno, strerror(errno)); return 0; }