#!/sbin/sh -x
# Magisk Manager for Recovery Mode (mm) Installer
# (c) 2017-2018, VR25 @ xda-developers
# License: GPL v3+

# detect whether in bootmode
ps | grep zygote | grep -v grep >/dev/null && bootMode=true || bootMode=false
$bootMode || ps -A 2>/dev/null | grep zygote | grep -v grep >/dev/null && bootMode=true
$bootMode || id | grep -q 'uid=0' || bootMode=true

# default perms
umask 022

ui_print() {
  $bootMode && echo -e "$1" || echo -e "ui_print $1\nui_print" >> /proc/self/fd/$OUTFD
}

grep_prop() {
  REGEX="s/^$1=//p"
  shift
  FILES=$@
  [ -z "$FILES" ] && FILES='/system/build.prop'
  sed -n "$REGEX" $FILES 2>/dev/null | head -n 1
}

is_mounted() { mountpoint -q "$1"; }

mount_image() {
	ui_print "- Mounting $1 to $2"
	[ -d "$2" ] || mkdir -p "$2"
	if (! is_mounted $2); then
		loopDevice=
		for LOOP in 0 1 2 3 4 5 6 7; do
			if (! is_mounted $2); then
				loopDevice=/dev/block/loop$LOOP
				[ -f "$loopDevice" ] || mknod $loopDevice b 7 $LOOP 2>/dev/null
				losetup $loopDevice $1
				if [ "$?" -eq "0" ]; then
					mount -t ext4 -o loop $loopDevice $2
					is_mounted $2 || /system/bin/toolbox mount -t ext4 -o loop $loopDevice $2
					is_mounted $2 || /system/bin/toybox mount -t ext4 -o loop $loopDevice $2
				fi
				is_mounted $2 && break
			fi
		done
	fi
}

set_perm() {
  chown $2:$3 "$1" || exit 1
  chmod $4 "$1" || exit 1
  [ -z "$5" ] && chcon 'u:object_r:system_file:s0' "$1" || chcon $5 "$1"
}

set_perm_recursive() {
  find "$1" -type d 2>/dev/null | while read dir; do
	set_perm "$dir" $2 $3 $4 $6
  done
  find "$1" -type f -o -type l 2>/dev/null | while read file; do
	set_perm "$file" $2 $3 $5 $6
  done
}

request_size_check() {
  reqSizeM=`du -s $1 | cut -f1`
  reqSizeM=$((reqSizeM / 1024 + 1))
}

request_zip_size_check() {
  reqSizeM=`unzip -l "$1" | tail -n 1 | awk '{ print int($1 / 1048567 + 1) }'`
}

image_size_check() {
  e2fsck -yf $1 >&2
  curBlocks=`e2fsck -n $1 2>/dev/null | grep $1 | cut -d, -f3 | cut -d\  -f2`;
  curUsedM=`echo "$curBlocks" | cut -d/ -f1`
  curSizeM=`echo "$curBlocks" | cut -d/ -f1`
  curFreeM=$(((curSizeM - curUsedM) * 4 / 1024))
  curUsedM=$((curUsedM * 4 / 1024 + 1))
  curSizeM=$((curSizeM * 4 / 1024))
}

mod_info() {
  grep_prop "$1" $INSTALLER/module.prop
}

print_modname() {
  ui_print " "
  ui_print "$(mod_info name) ($(mod_info id)) $(mod_info version)"
  ui_print "$(mod_info author)"
  ui_print "Powered by Magisk (@topjohnwu)"
  ui_print " "
}

set_permissions() {
  # Only some special files require specific permissions
  # The default permissions should be good enough for most cases

  # Here are some examples for the set_perm functions:

  # set_perm_recursive  <dirname>                <owner> <group> <dirpermission> <filepermission> <contexts> (default: u:object_r:system_file:s0)
  # set_perm_recursive  $modPath/system/lib       0       0       0755            0644

  # set_perm  <filename>                         <owner> <group> <permission> <contexts> (default: u:object_r:system_file:s0)
  # set_perm  $modPath/system/bin/app_process32   0       2000    0755         u:object_r:zygote_exec:s0
  # set_perm  $modPath/system/bin/dex2oat         0       2000    0755         u:object_r:dex2oat_exec:s0
  # set_perm  $modPath/system/lib/libart.so       0       0       0644

  # The following is default permissions, DO NOT remove
  set_perm_recursive  $tmpModPath  0  0  0755  0644
  set_perm /data/media/mm 0  0  0755
}

OUTFD=$2
ZIP="$3"

readlink /proc/$$/fd/$OUTFD 2>/dev/null | grep /tmp >/dev/null
if [ "$?" -eq "0" ]; then
  OUTFD=0

  for FD in `ls /proc/$$/fd`; do
	readlink /proc/$$/fd/$FD 2>/dev/null | grep pipe >/dev/null
	if [ "$?" -eq "0" ]; then
	  ps | grep " 3 $FD " | grep -v grep >/dev/null
	  if [ "$?" -eq "0" ]; then
		OUTFD=$FD
		break
	  fi
	fi
  done
fi

tmpDir=/dev/tmp
INSTALLER=$tmpDir/install
mountPath=$tmpDir/magisk_img
$bootMode && imgName=magisk_merge.img || imgName=magisk.img
[ -d /data/adb/magisk ] && IMG=/data/adb/$imgName || IMG=/data/$imgName

if [ ! -d /data/adb/magisk ] && [ ! -d /data/magisk ]; then
	ui_print " "
	ui_print "(!) 不支持安装或安装的版本"
	ui_print " "
	exit 1
fi

# initial cleanup
rm -rf $tmpDir 2>/dev/null
mkdir -p $INSTALLER 2>/dev/null

unzip -o "$ZIP" 'common/*' module.prop -d $INSTALLER >&2

modID="`grep_prop id $INSTALLER/module.prop`"
tmpModPath=$mountPath/$modID
modPath=$tmpModPath

# find modPath
if $bootMode; then
  for mountPoint in /sbin/.core/img /magisk; do
    if [ -d "$mountPoint/.core" ] || [ -d "$mountPoint/lost+found" ]; then
      mountPoint=$mountPoint
      modPath=$mountPoint/$modID
      mkdir -p $modPath 2>/dev/null
      break
    fi
  done
  [[ -d $modPath ]] || { echo -e "\n(!) Magisk mount point not found\n"; exit 1; }
  is_mounted $mountPoint || { echo -e "\n(!) Magisk is not activated!... abort\n"; exit 1; }
fi

# Print mod name
print_modname

$bootMode || ui_print "- 导入分区"
mount -o ro /system 2>/dev/null
mount -o ro /vendor 2>/dev/null
mount /data 2>/dev/null
mount /cache 2>/dev/null

request_zip_size_check "$ZIP"

if [ -f "$IMG" ]; then
  ui_print "- $IMG detected!"
  image_size_check $IMG
  if [ "$reqSizeM" -gt "$curFreeM" ]; then
	SIZE=$(((reqSizeM + curUsedM) / 32 * 32 + 64))
	ui_print "- Resizing $IMG to ${SIZE}M..."
	resize2fs $IMG ${SIZE}M >&2
  fi
else
  SIZE=$((reqSizeM / 32 * 32 + 64));
  ui_print "- Creating $IMG with size ${SIZE}M"
  make_ext4fs -l ${SIZE}M $IMG >&2
fi

mount_image $IMG $mountPath
if ! is_mounted $mountPath; then
  ui_print " "
  ui_print "(!) $IMG mount failed... abort"
  ui_print " "
  exit 1
fi

##########################################################################################
# module-specific code
##########################################################################################

# create module paths
rm -rf $tmpModPath 2>/dev/null
mkdir -p $tmpModPath
  
# extract module files
ui_print "- 安装中..."
unzip -o "$ZIP" -d $INSTALLER >&2
cd $INSTALLER
mv mm /data/media/
mv README.md $tmpModPath/

##########################################################################################

# module info
cp $INSTALLER/module.prop $tmpModPath/

# update info for Magisk Manager
if $bootMode; then
  touch $modPath/update
  cp $INSTALLER/module.prop $modPath/
fi

ui_print "- 解压文件..."
set_permissions

$bootMode || ui_print "- Unmounting partitions"
umount $mountPath
losetup -d $loopDevice
rmdir $mountPath

# shrink the image if possible
image_size_check $IMG
NEWDATASIZE=$((curUsedM / 32 * 32 + 32))
if [ "$curSizeM" -gt "$NEWDATASIZE" ]; then
  ui_print "- Shrinking $IMG to ${NEWDATASIZE}M..."
  resize2fs $IMG ${NEWDATASIZE}M >&2
fi

if ! $bootMode; then
  umount /system
  umount /vendor 2>/dev/null
fi

ui_print "- 完成！(^_^)ノ"
ui_print " "

##########################################################################################
# module-specific code
##########################################################################################

if $bootMode; then
	ui_print "(i) 食用方法：在Rec终端输入"/data/media/mm"即可"
else
	ln -s /data/media/mm /sbin
	ui_print "(i) Run mm on terminal to use it now"
	ui_print "- Next time, no need to reinstall -- run /data/media/mm"
fi

ui_print "- mm survives the standard TWRP factory reset"
ui_print " "

##########################################################################################

exit 0
