Merge remote-tracking branch 'john/master' into development

This commit is contained in:
Viktor De Pasquale 2019-05-01 09:05:22 +02:00
commit 065051a360
20 changed files with 103 additions and 101 deletions

View File

@ -23,7 +23,6 @@ import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.zip.ZipEntry; import java.util.zip.ZipEntry;
@ -95,7 +94,7 @@ public class DownloadModuleService extends Service {
.setDownloadProgressListener(progress) .setDownloadProgressListener(progress)
.execForInputStream().getResult(); .execForInputStream().getResult();
OutputStream out = new BufferedOutputStream(new FileOutputStream(output)); OutputStream out = new BufferedOutputStream(new FileOutputStream(output));
processZip(in, out, repo.isNewInstaller()); processZip(in, out);
Intent intent = new Intent(this, ClassMap.get(FlashActivity.class)); Intent intent = new Intent(this, ClassMap.get(FlashActivity.class));
intent.setData(Uri.fromFile(output)) intent.setData(Uri.fromFile(output))
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
@ -120,25 +119,23 @@ public class DownloadModuleService extends Service {
removeNotification(progress); removeNotification(progress);
} }
private void processZip(InputStream in, OutputStream out, boolean inject) private void processZip(InputStream in, OutputStream out)
throws IOException { throws IOException {
try (ZipInputStream zin = new ZipInputStream(in); try (ZipInputStream zin = new ZipInputStream(in);
ZipOutputStream zout = new ZipOutputStream(out)) { ZipOutputStream zout = new ZipOutputStream(out)) {
if (inject) { // Inject latest module-installer.sh as update-binary
// Inject latest module-installer.sh as update-binary zout.putNextEntry(new ZipEntry("META-INF/"));
zout.putNextEntry(new ZipEntry("META-INF/")); zout.putNextEntry(new ZipEntry("META-INF/com/"));
zout.putNextEntry(new ZipEntry("META-INF/com/")); zout.putNextEntry(new ZipEntry("META-INF/com/google/"));
zout.putNextEntry(new ZipEntry("META-INF/com/google/")); zout.putNextEntry(new ZipEntry("META-INF/com/google/android/"));
zout.putNextEntry(new ZipEntry("META-INF/com/google/android/")); zout.putNextEntry(new ZipEntry("META-INF/com/google/android/update-binary"));
zout.putNextEntry(new ZipEntry("META-INF/com/google/android/update-binary")); try (InputStream update_bin = Networking.get(Const.Url.MODULE_INSTALLER)
try (InputStream update_bin = Networking.get(Const.Url.MODULE_INSTALLER) .execForInputStream().getResult()) {
.execForInputStream().getResult()) { ShellUtils.pump(update_bin, zout);
ShellUtils.pump(update_bin, zout);
}
zout.putNextEntry(new ZipEntry("META-INF/com/google/android/updater-script"));
zout.write("#MAGISK\n".getBytes(StandardCharsets.UTF_8));
} }
zout.putNextEntry(new ZipEntry("META-INF/com/google/android/updater-script"));
zout.write("#MAGISK\n".getBytes("UTF-8"));
int off = -1; int off = -1;
ZipEntry entry; ZipEntry entry;
@ -148,7 +145,7 @@ public class DownloadModuleService extends Service {
String path = entry.getName().substring(off); String path = entry.getName().substring(off);
if (path.isEmpty()) if (path.isEmpty())
continue; continue;
if (inject && path.startsWith("META-INF")) if (path.startsWith("META-INF"))
continue; continue;
zout.putNextEntry(new ZipEntry(path)); zout.putNextEntry(new ZipEntry(path));
if (!entry.isDirectory()) if (!entry.isDirectory())

View File

@ -7,8 +7,6 @@ import android.os.Parcelable;
import com.topjohnwu.magisk.Const; import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.utils.Utils; import com.topjohnwu.magisk.utils.Utils;
import com.topjohnwu.net.Networking;
import com.topjohnwu.net.Request;
import java.text.DateFormat; import java.text.DateFormat;
import java.util.Date; import java.util.Date;
@ -91,18 +89,6 @@ public class Repo extends BaseModule {
return String.format(Const.Url.FILE_URL, getId(), file); return String.format(Const.Url.FILE_URL, getId(), file);
} }
public boolean isNewInstaller() {
try (Request install = Networking.get(getFileUrl("install.sh"))) {
if (install.connect().isSuccess()) {
// Double check whether config.sh exists
try (Request config = Networking.get(getFileUrl("config.sh"))) {
return !config.connect().isSuccess();
}
}
return false;
}
}
public String getLastUpdateString() { public String getLastUpdateString() {
return DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM).format(mLastUpdate); return DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM).format(mLastUpdate);
} }

View File

@ -1,5 +1,5 @@
APP_ABI := armeabi-v7a x86 APP_ABI := armeabi-v7a x86
APP_CFLAGS := -Oz -fomit-frame-pointer -flto \ APP_CFLAGS := -Wall -Oz -fomit-frame-pointer -flto \
-D__MVSTR=${MAGISK_VERSION} -D__MCODE=${MAGISK_VER_CODE} -D__MVSTR=${MAGISK_VERSION} -D__MCODE=${MAGISK_VER_CODE}
APP_LDFLAGS := -flto APP_LDFLAGS := -flto
APP_CPPFLAGS := -std=c++17 APP_CPPFLAGS := -std=c++17

View File

@ -207,7 +207,7 @@ void node_entry::create_module_tree(const char *module) {
void node_entry::clone_skeleton() { void node_entry::clone_skeleton() {
DIR *dir; DIR *dir;
struct dirent *entry; struct dirent *entry;
struct node_entry *dummy; node_entry *dummy;
// Clone the structure // Clone the structure
auto full_path = get_path(); auto full_path = get_path();
@ -498,20 +498,20 @@ void unlock_blocks() {
struct dirent *entry; struct dirent *entry;
int fd, dev, OFF = 0; int fd, dev, OFF = 0;
if ((dev = xopen("/dev/block", O_RDONLY | O_CLOEXEC)) < 0) if (!(dir = xopendir("/dev/block")))
return; return;
dir = xfdopendir(dev); dev = dirfd(dir);
while((entry = readdir(dir))) { while((entry = readdir(dir))) {
if (entry->d_type == DT_BLK) { if (entry->d_type == DT_BLK) {
if ((fd = openat(dev, entry->d_name, O_RDONLY)) < 0) if ((fd = openat(dev, entry->d_name, O_RDONLY | O_CLOEXEC)) < 0)
continue; continue;
if (ioctl(fd, BLKROSET, &OFF) == -1) if (ioctl(fd, BLKROSET, &OFF) < 0)
PLOGE("unlock %s", entry->d_name); PLOGE("unlock %s", entry->d_name);
close(fd); close(fd);
} }
} }
close(dev); closedir(dir);
} }
static bool log_dump = false; static bool log_dump = false;

View File

@ -38,10 +38,9 @@ using namespace std;
#ifdef MAGISK_DEBUG #ifdef MAGISK_DEBUG
static FILE *kmsg; static FILE *kmsg;
static char kbuf[4096];
static int vprintk(const char *fmt, va_list ap) { static int vprintk(const char *fmt, va_list ap) {
vsprintf(kbuf, fmt, ap); fprintf(kmsg, "magiskinit: ");
return fprintf(kmsg, "magiskinit: %s", kbuf); return vfprintf(kmsg, fmt, ap);
} }
static void setup_klog() { static void setup_klog() {

@ -1 +1 @@
Subproject commit 1dcc6befca9c7a5a89d8dfd95943220bd534d6cb Subproject commit a57ccd7378e6858f9b2a564c75517ed4b41fcd39

@ -1 +1 @@
Subproject commit 88f18909db731a627456f26d779445f84e449536 Subproject commit d37f6b20107e952064e3f77e9d6915a9c09d10a6

@ -1 +1 @@
Subproject commit 641b453d9db536ee020851bfcb1dc39f61006f0a Subproject commit 398e36c756a3067de8e2b35dd380baef040dfe0d

@ -1 +1 @@
Subproject commit 3626b5c40e2457629ac60a563dde523be7c10bb4 Subproject commit 3c69a905b16df149e1bda12f25e0522073a24678

@ -1 +1 @@
Subproject commit 4d7d59c49675eef4a18c2b1f73e630bf675811f9 Subproject commit c61cf3916dc8f19ef2236078ff87f7a33fce6a52

@ -1 +1 @@
Subproject commit 3d566cd519017eee1a400e7961ff14058dfaf33c Subproject commit b5be61cc06088bb07f488f9baf7d447ff47b37c1

View File

@ -422,8 +422,8 @@ void LZ4FEncoder::write_header() {
FilterOutStream::write(outbuf, write); FilterOutStream::write(outbuf, write);
} }
LZ4Decoder::LZ4Decoder() : init(false), buf_off(0), total(0), block_sz(0), LZ4Decoder::LZ4Decoder() : outbuf(new char[LZ4_UNCOMPRESSED]), buf(new char[LZ4_COMPRESSED]),
outbuf(new char[LZ4_UNCOMPRESSED]), buf(new char[LZ4_COMPRESSED]) {} init(false), block_sz(0), buf_off(0), total(0) {}
LZ4Decoder::~LZ4Decoder() { LZ4Decoder::~LZ4Decoder() {
delete[] outbuf; delete[] outbuf;
@ -476,8 +476,8 @@ uint64_t LZ4Decoder::finalize() {
return total; return total;
} }
LZ4Encoder::LZ4Encoder() : init(false), buf_off(0), out_total(0), in_total(0), LZ4Encoder::LZ4Encoder() : outbuf(new char[LZ4_COMPRESSED]), buf(new char[LZ4_UNCOMPRESSED]),
outbuf(new char[LZ4_COMPRESSED]), buf(new char[LZ4_UNCOMPRESSED]) {} init(false), buf_off(0), out_total(0), in_total(0) {}
LZ4Encoder::~LZ4Encoder() { LZ4Encoder::~LZ4Encoder() {
delete[] outbuf; delete[] outbuf;

View File

@ -165,7 +165,7 @@ void magisk_cpio::backup(const char *orig) {
res = lhs->first.compare(rhs->first); res = lhs->first.compare(rhs->first);
} else if (lhs == o.entries.end()) { } else if (lhs == o.entries.end()) {
res = 1; res = 1;
} else if (rhs == entries.end()) { } else {
res = -1; res = -1;
} }

View File

@ -2,6 +2,7 @@
#include "magiskpolicy.h" #include "magiskpolicy.h"
#include "sepolicy.h" #include "sepolicy.h"
#include "flags.h"
static void allowSuClient(const char *target) { static void allowSuClient(const char *target) {
if (!sepol_exists(target)) if (!sepol_exists(target))
@ -47,7 +48,7 @@ void sepol_magisk_rules() {
sepol_attradd(SEPOL_PROC_DOMAIN, "bluetoothdomain"); sepol_attradd(SEPOL_PROC_DOMAIN, "bluetoothdomain");
sepol_attradd(SEPOL_FILE_DOMAIN, "mlstrustedobject"); sepol_attradd(SEPOL_FILE_DOMAIN, "mlstrustedobject");
// Let init daemon transit context // Let init transit to SEPOL_PROC_DOMAIN
sepol_allow("kernel", "kernel", "process", "setcurrent"); sepol_allow("kernel", "kernel", "process", "setcurrent");
sepol_allow("kernel", SEPOL_PROC_DOMAIN, "process", "dyntransition"); sepol_allow("kernel", SEPOL_PROC_DOMAIN, "process", "dyntransition");
@ -148,7 +149,7 @@ void sepol_magisk_rules() {
sepol_allow(SEPOL_PROC_DOMAIN, "tmpfs", "filesystem", "unmount"); sepol_allow(SEPOL_PROC_DOMAIN, "tmpfs", "filesystem", "unmount");
sepol_allow("kernel", ALL, "file", "read"); sepol_allow("kernel", ALL, "file", "read");
// Allow su to do anything to any files/dir/links // Allow us to do anything to any files/dir/links
sepol_allow(SEPOL_PROC_DOMAIN, ALL, "file", ALL); sepol_allow(SEPOL_PROC_DOMAIN, ALL, "file", ALL);
sepol_allow(SEPOL_PROC_DOMAIN, ALL, "dir", ALL); sepol_allow(SEPOL_PROC_DOMAIN, ALL, "dir", ALL);
sepol_allow(SEPOL_PROC_DOMAIN, ALL, "lnk_file", ALL); sepol_allow(SEPOL_PROC_DOMAIN, ALL, "lnk_file", ALL);
@ -157,6 +158,10 @@ void sepol_magisk_rules() {
sepol_allow(SEPOL_PROC_DOMAIN, ALL, "chr_file", ALL); sepol_allow(SEPOL_PROC_DOMAIN, ALL, "chr_file", ALL);
sepol_allow(SEPOL_PROC_DOMAIN, ALL, "fifo_file", ALL); sepol_allow(SEPOL_PROC_DOMAIN, ALL, "fifo_file", ALL);
// Allow us to do any ioctl on all block devices
if (policydb->policyvers >= POLICYDB_VERSION_XPERMS_IOCTL)
sepol_allowxperm(SEPOL_PROC_DOMAIN, ALL, "blk_file", "0x0000-0xFFFF");
// Allow all binder transactions // Allow all binder transactions
sepol_allow(ALL, SEPOL_PROC_DOMAIN, "binder", ALL); sepol_allow(ALL, SEPOL_PROC_DOMAIN, "binder", ALL);
@ -184,12 +189,14 @@ void sepol_magisk_rules() {
// Allow update engine to source addon.d.sh // Allow update engine to source addon.d.sh
sepol_allow("update_engine", "adb_data_file", "dir", ALL); sepol_allow("update_engine", "adb_data_file", "dir", ALL);
// Remove all dontaudit #ifdef MAGISK_DEBUG
// Remove all dontaudit in debug mode
avtab_ptr_t av; avtab_ptr_t av;
avtab_for_each(&policydb->te_avtab, av, { avtab_for_each(&policydb->te_avtab, av, {
if (av->key.specified == AVTAB_AUDITDENY || av->key.specified == AVTAB_XPERMS_DONTAUDIT) if (av->key.specified == AVTAB_AUDITDENY || av->key.specified == AVTAB_XPERMS_DONTAUDIT)
avtab_remove_node(&policydb->te_avtab, av); avtab_remove_node(&policydb->te_avtab, av);
}) })
#endif
log_cb.w = bak; log_cb.w = bak;
} }

View File

@ -17,7 +17,7 @@
// 0x18000020 = FLAG_ACTIVITY_NEW_TASK|FLAG_ACTIVITY_MULTIPLE_TASK|FLAG_INCLUDE_STOPPED_PACKAGES // 0x18000020 = FLAG_ACTIVITY_NEW_TASK|FLAG_ACTIVITY_MULTIPLE_TASK|FLAG_INCLUDE_STOPPED_PACKAGES
static inline const char *get_command(const struct su_request *to) { static inline const char *get_command(const su_request *to) {
if (to->command[0]) if (to->command[0])
return to->command; return to->command;
if (to->shell[0]) if (to->shell[0])
@ -25,21 +25,21 @@ static inline const char *get_command(const struct su_request *to) {
return DEFAULT_SHELL; return DEFAULT_SHELL;
} }
static inline void get_user(char *user, struct su_info *info) { static inline void get_user(char *user, su_info *info) {
sprintf(user, "%d", sprintf(user, "%d",
info->cfg[SU_MULTIUSER_MODE] == MULTIUSER_MODE_USER info->cfg[SU_MULTIUSER_MODE] == MULTIUSER_MODE_USER
? info->uid / 100000 ? info->uid / 100000
: 0); : 0);
} }
static inline void get_uid(char *uid, struct su_info *info) { static inline void get_uid(char *uid, su_info *info) {
sprintf(uid, "%d", sprintf(uid, "%d",
info->cfg[SU_MULTIUSER_MODE] == MULTIUSER_MODE_OWNER_MANAGED info->cfg[SU_MULTIUSER_MODE] == MULTIUSER_MODE_OWNER_MANAGED
? info->uid % 100000 ? info->uid % 100000
: info->uid); : info->uid);
} }
static void silent_run(const char **args, struct su_info *info) { static void silent_run(const char **args, su_info *info) {
char component[128]; char component[128];
sprintf(component, "%s/a.m", info->str[SU_MANAGER].data()); sprintf(component, "%s/a.m", info->str[SU_MANAGER].data());
char user[8]; char user[8];
@ -62,7 +62,7 @@ static void silent_run(const char **args, struct su_info *info) {
exec_command(exec); exec_command(exec);
} }
void app_log(struct su_context *ctx) { void app_log(su_context *ctx) {
char fromUid[8]; char fromUid[8];
get_uid(fromUid, ctx->info); get_uid(fromUid, ctx->info);
@ -88,7 +88,7 @@ void app_log(struct su_context *ctx) {
silent_run(cmd, ctx->info); silent_run(cmd, ctx->info);
} }
void app_notify(struct su_context *ctx) { void app_notify(su_context *ctx) {
char fromUid[8]; char fromUid[8];
get_uid(fromUid, ctx->info); get_uid(fromUid, ctx->info);
@ -104,7 +104,7 @@ void app_notify(struct su_context *ctx) {
silent_run(cmd, ctx->info); silent_run(cmd, ctx->info);
} }
void app_connect(const char *socket, struct su_info *info) { void app_connect(const char *socket, su_info *info) {
const char *cmd[] = { const char *cmd[] = {
START_ACTIVITY, "request", START_ACTIVITY, "request",
"--es", "socket", socket, "--es", "socket", socket,
@ -113,7 +113,7 @@ void app_connect(const char *socket, struct su_info *info) {
silent_run(cmd, info); silent_run(cmd, info);
} }
void socket_send_request(int fd, struct su_info *info) { void socket_send_request(int fd, su_info *info) {
write_key_token(fd, "uid", info->uid); write_key_token(fd, "uid", info->uid);
write_string_be(fd, "eof"); write_string_be(fd, "eof");
} }

View File

@ -83,7 +83,6 @@ static void pump_async(int input, int output) {
*/ */
int pts_open(char *slave_name, size_t slave_name_size) { int pts_open(char *slave_name, size_t slave_name_size) {
int fdm; int fdm;
char sn_tmp[256];
// Open master ptmx device // Open master ptmx device
fdm = open("/dev/ptmx", O_RDWR); fdm = open("/dev/ptmx", O_RDWR);

View File

@ -60,16 +60,16 @@ struct su_request : public su_req_base {
} __attribute__((packed)); } __attribute__((packed));
struct su_context { struct su_context {
struct su_info *info; su_info *info;
struct su_request req; su_request req;
pid_t pid; pid_t pid;
}; };
// connect.c // connect.c
void app_log(struct su_context *ctx); void app_log(su_context *ctx);
void app_notify(struct su_context *ctx); void app_notify(su_context *ctx);
void app_connect(const char *socket, struct su_info *info); void app_connect(const char *socket, su_info *info);
void socket_send_request(int fd, struct su_info *info); void socket_send_request(int fd, su_info *info);
#endif #endif

View File

@ -26,8 +26,8 @@ static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER;
static su_info *cache; static su_info *cache;
su_info::su_info(unsigned uid) : su_info::su_info(unsigned uid) :
uid(uid), access(DEFAULT_SU_ACCESS), _lock(PTHREAD_MUTEX_INITIALIZER), uid(uid), count(0), access(DEFAULT_SU_ACCESS), mgr_st({}), ref(0),
count(0), ref(0), timestamp(0), mgr_st({}) {} timestamp(0), _lock(PTHREAD_MUTEX_INITIALIZER) {}
su_info::~su_info() { su_info::~su_info() {
pthread_mutex_destroy(&_lock); pthread_mutex_destroy(&_lock);
@ -90,7 +90,7 @@ static void database_check(su_info *info) {
validate_manager(info->str[SU_MANAGER], uid / 100000, &info->mgr_st); validate_manager(info->str[SU_MANAGER], uid / 100000, &info->mgr_st);
} }
static struct su_info *get_su_info(unsigned uid) { static su_info *get_su_info(unsigned uid) {
su_info *info = nullptr; su_info *info = nullptr;
// Get from cache or new instance // Get from cache or new instance
@ -235,7 +235,7 @@ void su_daemon_handler(int client, struct ucred *credential) {
// Abort upon any error occurred // Abort upon any error occurred
log_cb.ex = exit; log_cb.ex = exit;
struct su_context ctx = { su_context ctx = {
.info = info, .info = info,
.pid = credential->pid .pid = credential->pid
}; };

View File

@ -80,9 +80,23 @@ if [ -d /system/addon.d ]; then
ui_print "- Adding addon.d survival script" ui_print "- Adding addon.d survival script"
mount -o rw,remount /system mount -o rw,remount /system
ADDOND=/system/addon.d/99-magisk.sh ADDOND=/system/addon.d/99-magisk.sh
echo '#!/sbin/sh' > $ADDOND cat <<EOF > $ADDOND
echo '# ADDOND_VERSION=2' >> $ADDOND #!/sbin/sh
echo 'exec sh /data/adb/magisk/addon.d.sh "$@"' >> $ADDOND # ADDOND_VERSION=2
if [ -f /data/adb/magisk/addon.d.sh ]; then
exec sh /data/adb/magisk/addon.d.sh "\$@"
else
OUTFD=\$(ps | grep -v 'grep' | grep -oE 'update(.*)' | cut -d" " -f3)
ui_print() { echo -e "ui_print \$1\nui_print" >> /proc/self/fd/\$OUTFD; }
ui_print "************************"
ui_print "* Magisk addon.d failed"
ui_print "************************"
ui_print "! Cannot find Magisk binaries - was data wiped or not decrypted?"
ui_print "! Reflash OTA from decrypted recovery or reflash Magisk"
fi
EOF
chmod 755 $ADDOND chmod 755 $ADDOND
fi fi

View File

@ -1,11 +1,9 @@
########################################################################################## #########################################
# #
# Magisk General Utility Functions # Magisk General Utility Functions
# by topjohnwu # by topjohnwu
# #
# Used everywhere in Magisk #########################################
#
##########################################################################################
########## ##########
# Presets # Presets
@ -167,40 +165,42 @@ find_block() {
return 1 return 1
} }
mount_part() {
local PART=$1
local POINT=/${PART}
[ -L $POINT ] && rm -f $POINT
mkdir $POINT 2>/dev/null
is_mounted $POINT && return
ui_print "- Mounting $PART"
mount -o ro $POINT 2>/dev/null
if ! is_mounted $POINT; then
local BLOCK=`find_block $PART$SLOT`
mount -o ro $BLOCK $POINT
fi
is_mounted $POINT || abort "! Cannot mount $POINT"
}
mount_partitions() { mount_partitions() {
# Check A/B slot # Check A/B slot
SLOT=`grep_cmdline androidboot.slot_suffix` SLOT=`grep_cmdline androidboot.slot_suffix`
if [ -z $SLOT ]; then if [ -z $SLOT ]; then
SLOT=_`grep_cmdline androidboot.slot` SLOT=`grep_cmdline androidboot.slot`
[ $SLOT = "_" ] && SLOT= [ -z $SLOT ] || SLOT=_${SLOT}
fi fi
[ -z $SLOT ] || ui_print "- Current boot slot: $SLOT" [ -z $SLOT ] || ui_print "- Current boot slot: $SLOT"
ui_print "- Mounting /system, /vendor" mount_part system
mkdir /system 2>/dev/null
[ -f /system/build.prop ] || is_mounted /system || mount -o ro /system 2>/dev/null
if ! is_mounted /system && ! [ -f /system/build.prop ]; then
SYSTEMBLOCK=`find_block system$SLOT`
mount -o ro $SYSTEMBLOCK /system
fi
[ -f /system/build.prop ] || is_mounted /system || abort "! Cannot mount /system"
grep -qE '/dev/root|/system_root' /proc/mounts && SYSTEM_ROOT=true || SYSTEM_ROOT=false
if [ -f /system/init.rc ]; then if [ -f /system/init.rc ]; then
SYSTEM_ROOT=true SYSTEM_ROOT=true
[ -L /system_root ] && rm -f /system_root
mkdir /system_root 2>/dev/null mkdir /system_root 2>/dev/null
mount --move /system /system_root mount --move /system /system_root
mount -o bind /system_root/system /system mount -o bind /system_root/system /system
else
grep -qE '/dev/root|/system_root' /proc/mounts && SYSTEM_ROOT=true || SYSTEM_ROOT=false
fi fi
[ -L /system/vendor ] && mount_part vendor
$SYSTEM_ROOT && ui_print "- Device is system-as-root" $SYSTEM_ROOT && ui_print "- Device is system-as-root"
if [ -L /system/vendor ]; then
mkdir /vendor 2>/dev/null
is_mounted /vendor || mount -o ro /vendor 2>/dev/null
if ! is_mounted /vendor; then
VENDORBLOCK=`find_block vendor$SLOT`
mount -o ro $VENDORBLOCK /vendor
fi
is_mounted /vendor || abort "! Cannot mount /vendor"
fi
} }
get_flags() { get_flags() {