#!/system/bin/sh -x

#
# script to start up Magisk from an exploit
# including working permission asking notifications on android 10
# created by j4nn @ xda
# modified by Ri_Butz @ telegram
# must be run within a root shell to work - it has 3 stages:
#
# ./magisk-start.sh -1
# ./magisk-start.sh -2
# ./magisk-start.sh -3
#
# if called like './magisk-start.sh --fresh -2' it would clean up magisk db
# and do a fresh clean start with no defined su permissions
#

FRESH=false
[ "$1" = "--fresh" ] && {
  FRESH=true
  shift
}
CLEAN=false
[ "$1" = "--clean" ] && {
  CLEAN=true
  shift
}

if [ ! -e /data/adb/magisk ]; then
  CLEAN=true
fi

case "$1" in
  -1) exec ./magiskpolicy --live --magisk "allow dumpstate * * *" ;;
  -2) STAGE=2 ;;
  -3) STAGE=3 ;;
  *) echo "Usage: magisk-start.sh [--fresh or --clean] <-1 | -2 | -3>"; exit 1 ;;
esac

if [ "$STAGE" = "2" ]
then
######################## STAGE 2 ########################
if ! grep -q ' /cache ' /proc/mounts; then
  mount -t tmpfs -o 'mode=0755' tmpfs /cache
fi

if $FRESH; then
  rm -rf /data/adb/magisk
  rm -f /data/adb/magisk.db
  mkdir /data/adb/magisk
  chmod 700 /data/adb
  cp -a magisk/* /data/adb/magisk
  chmod -R 755 /data/adb/magisk
  chown -R root:root /data/adb/magisk
  chcon -R u:object_r:magisk_file:s0 /data/adb/magisk
fi

if $CLEAN; then
  rm -rf /data/adb/*
  mkdir /data/adb/magisk
  mkdir /data/adb/modules
  mkdir /data/adb/post-fs-data.d
  mkdir /data/adb/service.d
  chmod 700 /data/adb
  cp -a magisk/* /data/adb/magisk
  chmod -R 755 /data/adb/*
  chown -R root:root /data/adb/magisk
  chcon -R u:object_r:magisk_file:s0 /data/adb/magisk
fi

mount_sbin() {
  mount -t tmpfs -o 'mode=0755' magisk /sbin
  chcon u:object_r:rootfs:s0 /sbin
}

if mount | grep -q rootfs; then
  # Legacy rootfs
  mount -o rw,remount /
  rm -rf /root
  mkdir /root
  chmod 750 /root
  ln /sbin/* /root
  mount -o ro,remount /
  mount_sbin
  ln -s /root/* /sbin
elif [ -e /sbin ]; then
  # Legacy SAR
  mount_sbin
  mkdir -p /dev/sysroot
  block=$(mount | grep ' / ' | awk '{ print $1 }')
  [ $block = "/dev/root" ] && block=/dev/block/dm-0
  mount -o ro $block /dev/sysroot
  for file in /dev/sysroot/sbin/*; do
    [ ! -e $file ] && break
    if [ -L $file ]; then
      cp -af $file /sbin
    else
      sfile=/sbin/$(basename $file)
      touch $sfile
      mount -o bind $file $sfile
    fi
  done
  umount -l /dev/sysroot
  rm -rf /dev/sysroot
else
  echo "sbin not found"
  exit
fi

for f in magisk32 magisk64 magiskpolicy stub.apk
do
  cp -a magisk/$f /sbin || { echo "magisk zip is not unpacked!"; umount /sbin; exit 1; }
done

chmod 755 /sbin/*
ln -s /sbin/magisk64 /sbin/magisk
ln -s /sbin/magiskpolicy /sbin/supolicy
ln -s /sbin/magisk /sbin/su
ln -s /sbin/magisk /sbin/resetprop
ln -s /sbin/magisk /sbin/magiskhide

mkdir -p /sbin/.magisk/mirror; chmod 755 /sbin/.magisk/mirror
mkdir /sbin/.magisk/block; chmod 000 /sbin/.magisk/block
mkdir /sbin/.magisk/worker

echo "KEEPVERITY=true" > /sbin/.magisk/config
echo "KEEPFORCEENCRYPT=false" >> /sbin/.magisk/config
echo "PATCHVBMETAFLAG=false" >> /sbin/.magisk/config
echo "RECOVERYMODE=false" >> /sbin/.magisk/config
chmod 000 /sbin/.magisk/config
chmod 755 /sbin

/sbin/magisk --daemon

MP=`pidof magiskd`
while [ -z "$MP" ] ; do sleep 1; MP=`pidof magiskd`; done
echo "$MP" > /sbin/.magisk/escalate
while [ -e /sbin/.magisk/escalate ]; do sleep 1; done

else
######################## STAGE 3 ########################

echo -e '#!/system/bin/sh\n/sbin/magisk --daemon' > /sbin/.magisk/magiskd
chmod 755 /sbin/.magisk/magiskd
chcon u:object_r:dumpstate_exec:s0 /sbin/.magisk/magiskd

SVC=`getprop init.svc.dumpstate`
timeout=10; while [ $timeout -gt 0 ] && ! stop dumpstate ; do sleep 1; timeout=$(($timeout - 1)); done
killall -9 magiskd
stop dumpstate || { echo "failed to stop a service"; exit 1; }

mount -o bind /sbin/.magisk/magiskd /system/bin/dumpstate
start dumpstate
timeout=10
until [ $timeout -le 0 ]
do
  MP=`pidof magiskd`
  [ -n "$MP" ] && break
  sleep 1
  timeout=$(($timeout - 1))
done
stop dumpstate
umount /system/bin/dumpstate
rm -f /sbin/.magisk/magiskd
[ "$SVC" = "running" ] && start dumpstate

MAGISKTMP=/sbin

export MAGISKTMP
MAKEDEV=1 $MAGISKTMP/magisk --preinit-device 2>&1

RULESCMD=""
for r in $MAGISKTMP/.magisk/preinit/*/sepolicy.rule; do
  [ -f "$r" ] || continue
  RULESCMD="$RULESCMD --apply $r"
done

if [ -d /sys/fs/selinux ]; then
  if [ -f /vendor/etc/selinux/precompiled_sepolicy ]; then
    ./magiskpolicy --load /vendor/etc/selinux/precompiled_sepolicy --live --magisk $RULESCMD 2>&1
  elif [ -f /sepolicy ]; then
    ./magiskpolicy --load /sepolicy --live --magisk $RULESCMD 2>&1
  else
    ./magiskpolicy --live --magisk $RULESCMD 2>&1
  fi
fi

$MAGISKTMP/magisk resetprop -n sys.boot_completed 0
$MAGISKTMP/magisk --post-fs-data
$MAGISKTMP/magisk --service
$MAGISKTMP/magisk resetprop -n sys.boot_completed 1
$MAGISKTMP/magisk --boot-complete

fi