379 lines
9.1 KiB
C
379 lines
9.1 KiB
C
/*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <sys/stat.h>
|
|
#include <sys/mount.h>
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <sys/wait.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <dirent.h>
|
|
|
|
#include "devices.h"
|
|
#include "../lib/log.h"
|
|
#include "../lib/util.h"
|
|
#include "../lib/fstab.h"
|
|
#include "../lib/inject.h"
|
|
#include "../version.h"
|
|
#include "adb.h"
|
|
#include "../hooks.h"
|
|
#include "encryption.h"
|
|
|
|
#define EXEC_MASK (S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)
|
|
#define REALDATA "/realdata"
|
|
#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 void run_multirom(void)
|
|
{
|
|
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);
|
|
|
|
char *cmd[] = { path, NULL };
|
|
do
|
|
{
|
|
ERROR("Running multirom");
|
|
int res = run_cmd(cmd);
|
|
if(res == 0)
|
|
break;
|
|
else
|
|
ERROR("MultiROM exited with status code %d!", res);
|
|
}
|
|
while(restart);
|
|
}
|
|
|
|
static void mount_and_run(struct fstab *fstab)
|
|
{
|
|
struct fstab_part *p = fstab_find_first_by_path(fstab, "/data");
|
|
if(!p)
|
|
{
|
|
ERROR("Failed to find /data partition in fstab\n");
|
|
return;
|
|
}
|
|
|
|
if(wait_for_file(p->device, 5) < 0)
|
|
{
|
|
ERROR("Waiting too long for dev %s", p->device);
|
|
return;
|
|
}
|
|
|
|
mkdir(REALDATA, 0755);
|
|
|
|
int enc_res = encryption_before_mount(fstab);
|
|
if(enc_res == ENC_RES_ERR)
|
|
ERROR("Decryption failed, trying to mount anyway - might be unencrypted device.");
|
|
else if(enc_res == ENC_RES_BOOT_INTERNAL)
|
|
return;
|
|
|
|
int mount_err = -1;
|
|
struct fstab_part *p_itr = p;
|
|
do
|
|
{
|
|
// Remove nosuid flag, because secondary ROMs have
|
|
// su binaries on /data
|
|
p_itr->mountflags &= ~(MS_NOSUID);
|
|
|
|
if(mount(p_itr->device, REALDATA, p_itr->type, p_itr->mountflags, p_itr->options) >= 0)
|
|
mount_err = 0;
|
|
else
|
|
mount_err = -errno;
|
|
}
|
|
while(mount_err < 0 && (p_itr = fstab_find_next_by_path(fstab, "/data", p_itr)));
|
|
|
|
if(mount_err < 0)
|
|
{
|
|
ERROR("Failed to mount /realdata, err %d, trying all filesystems\n", mount_err);
|
|
|
|
fstab_dump(fstab);
|
|
|
|
const char *fs_types[] = { "ext4", "f2fs", "ext3", "ext2" };
|
|
const char *fs_opts [] = {
|
|
"barrier=1,data=ordered,nomblk_io_submit,noauto_da_alloc,errors=panic", // ext4
|
|
"inline_xattr,flush_merge,errors=recover", // f2fs
|
|
"", // ext3
|
|
"" // ext2
|
|
};
|
|
|
|
int mounted = 0;
|
|
size_t i;
|
|
for(i = 0; i < ARRAY_SIZE(fs_types); ++i)
|
|
{
|
|
ERROR("Trying to mount %s with fs %s\n", p->device, fs_types[i]);
|
|
if(mount(p->device, REALDATA, fs_types[i], p->mountflags, fs_opts[i]) >= 0)
|
|
{
|
|
ERROR("/realdata successfuly mounted with fs %s\n", fs_types[i]);
|
|
mounted = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!mounted)
|
|
{
|
|
ERROR("Failed to mount /realdata with all possible filesystems!");
|
|
return;
|
|
}
|
|
}
|
|
|
|
if(find_multirom() == -1)
|
|
{
|
|
ERROR("Could not find multirom folder!");
|
|
return;
|
|
}
|
|
|
|
adb_init(path_multirom);
|
|
run_multirom();
|
|
adb_quit();
|
|
|
|
return;
|
|
fail:
|
|
// REMOVE. DEBUGGING
|
|
while(1)
|
|
{
|
|
sleep(1);
|
|
}
|
|
}
|
|
|
|
static int is_charger_mode(void)
|
|
{
|
|
char buff[2048] = { 0 };
|
|
|
|
FILE *f = fopen("/proc/cmdline", "r");
|
|
if(!f)
|
|
return 0;
|
|
|
|
fgets(buff, sizeof(buff), f);
|
|
fclose(f);
|
|
|
|
return (strstr(buff, "androidboot.mode=charger") != NULL);
|
|
}
|
|
|
|
static void fixup_symlinks(void)
|
|
{
|
|
static const char *init_links[] = { "/sbin/ueventd", "/sbin/watchdogd" };
|
|
|
|
size_t i;
|
|
ssize_t len;
|
|
char buff[64];
|
|
struct stat info;
|
|
|
|
for(i = 0; i < ARRAY_SIZE(init_links); ++i)
|
|
{
|
|
if(lstat(init_links[i], &info) < 0 || !S_ISLNK(info.st_mode))
|
|
continue;
|
|
|
|
if (info.st_size < sizeof(buff)-1)
|
|
{
|
|
len = readlink(init_links[i], buff, sizeof(buff)-1);
|
|
if(len >= 0)
|
|
{
|
|
buff[len] = 0;
|
|
// if the symlink already points to ../init, skip it.
|
|
if(strcmp(buff, "../init") == 0)
|
|
continue;
|
|
}
|
|
}
|
|
|
|
ERROR("Fixing up symlink '%s' -> '%s' to '%s' -> '../init')\n", init_links[i], buff, init_links[i]);
|
|
unlink(init_links[i]);
|
|
symlink("../init", init_links[i]);
|
|
}
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int i, res;
|
|
static char *const cmd[] = { "/init", NULL };
|
|
struct fstab *fstab = NULL;
|
|
char *inject_path = NULL;
|
|
char *mrom_dir = NULL;
|
|
int force_inject = 0;
|
|
|
|
for(i = 1; i < argc; ++i)
|
|
{
|
|
if(strcmp(argv[i], "-v") == 0)
|
|
{
|
|
printf("%d\n", VERSION_TRAMPOLINE);
|
|
fflush(stdout);
|
|
return 0;
|
|
}
|
|
else if(strstartswith(argv[i], "--inject="))
|
|
inject_path = argv[i] + strlen("--inject=");
|
|
else if(strstartswith(argv[i], "--mrom_dir="))
|
|
mrom_dir = argv[i] + strlen("--mrom_dir=");
|
|
else if(strcmp(argv[i], "-f") == 0)
|
|
force_inject = 1;
|
|
}
|
|
|
|
if(inject_path)
|
|
{
|
|
if(!mrom_dir)
|
|
{
|
|
printf("--mrom_dir=[path to multirom's data dir] needs to be specified!\n");
|
|
fflush(stdout);
|
|
return 1;
|
|
}
|
|
|
|
mrom_set_dir(mrom_dir);
|
|
mrom_set_log_tag("trampoline_inject");
|
|
return inject_bootimg(inject_path, force_inject);
|
|
}
|
|
|
|
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();
|
|
// output all messages to dmesg,
|
|
// but it is possible to filter out INFO messages
|
|
klog_set_level(6);
|
|
|
|
mrom_set_log_tag("trampoline");
|
|
ERROR("Running trampoline v%d\n", VERSION_TRAMPOLINE);
|
|
|
|
if(is_charger_mode())
|
|
{
|
|
ERROR("Charger mode detected, skipping multirom\n");
|
|
goto run_main_init;
|
|
}
|
|
|
|
#if MR_DEVICE_HOOKS >= 3
|
|
tramp_hook_before_device_init();
|
|
#endif
|
|
|
|
ERROR("Initializing devices...");
|
|
devices_init();
|
|
ERROR("Done initializing");
|
|
|
|
if(wait_for_file("/dev/graphics/fb0", 5) < 0)
|
|
{
|
|
ERROR("Waiting too long for fb0");
|
|
goto exit;
|
|
}
|
|
|
|
fstab = fstab_auto_load();
|
|
if(!fstab)
|
|
goto exit;
|
|
|
|
#if 0
|
|
fstab_dump(fstab); //debug
|
|
#endif
|
|
|
|
// REMOVE, DEBUGGING!
|
|
//adb_init("/adb_sbin/");
|
|
|
|
// mount and run multirom from sdcard
|
|
mount_and_run(fstab);
|
|
|
|
exit:
|
|
if(fstab)
|
|
fstab_destroy(fstab);
|
|
|
|
// close and destroy everything
|
|
devices_close();
|
|
|
|
run_main_init:
|
|
if(access(KEEP_REALDATA, F_OK) < 0)
|
|
{
|
|
umount(REALDATA);
|
|
umount("/dev/pts");
|
|
umount("/dev");
|
|
rmdir("/dev/pts");
|
|
rmdir("/dev/socket");
|
|
rmdir("/dev");
|
|
rmdir(REALDATA);
|
|
encryption_destroy();
|
|
}
|
|
|
|
umount("/proc");
|
|
umount("/sys");
|
|
rmdir("/proc");
|
|
rmdir("/sys");
|
|
|
|
ERROR("Running main_init\n");
|
|
|
|
fixup_symlinks();
|
|
|
|
chmod("/main_init", EXEC_MASK);
|
|
rename("/main_init", "/init");
|
|
|
|
res = execve(cmd[0], cmd, NULL);
|
|
ERROR("execve returned %d %d %s\n", res, errno, strerror(errno));
|
|
return 0;
|
|
}
|