#!/system/xbin/bash
# Based on Darktremor Apps2SD version 2.7.5
# Based on Darktremor A2SD 2.6.1-R2 By: Robert Travis Kirton
# Based on the Cyanogen 1.5 Scripts
# Bourne Again Shell (bash) courtesy of mzet (http://pub.mzet.net/bash)
# Zipalign code courtesy of Wes Garner
# Base apps2sd code courtesy of Cyanogen
# Rewritten by Andrew Sutherland for The Evervolv Project (20121003)

if [ -z "$SD_EXT_DIRECTORY" ]; then SD_EXT_DIRECTORY=/sd-ext; fi;

bb="/system/xbin/busybox"
tbox="/system/bin/toolbox"
zalign="/system/xbin/zipalign"
make2fs="/system/bin/mke2fs -T ext4 -O ^has_journal"
fixperms="/system/bin/fix_permissions"
e2fscheck="/system/bin/e2fsck -yf"
tempstorage="/data/local/tmp"
a2sdblk=`$tbox getprop a2sd.mountpoint`
a2sdextpart=`$tbox getprop ev.sdextpart`
ck="\xe2\x9c\x94"
er="\xe2\x9c\x96"
pl="\xe2\x9c\x9a"

help_me() {
    echo "INFO: a2sd=apps dc2sd=dalvik-cache ad2sd=appdata"
    echo "Available commands are:"
    echo "install   : sets a2sd flag [optionaly dc2sd|ad2sd]"
    echo "remove    : clears a2sd/dc2sd/ad2sd flags"
    echo "align     : runs zipalign on all apks"
    echo "fixapk    : runs fix_permissions on all apks"
    echo "diskspace : shows disk usage on $SD_EXT_DIRECTORY"
    echo "cleancache: clears dalvik-cache"
    echo "nocachesd : cleancache and clears dc2sd flag"
    echo "nodatasd  : clears ad2sd flag"
    echo "rmsysdata : remove system appdata if ad2sd is active"
    echo "xdata     : bind mount /data to $SD_EXT_DIRECTORY/xdata"
    echo "noxdata   : clears xdata flag"
    echo "formatext : format $SD_EXT_DIRECTORY to ext4"
    echo "checkext  : checks $SD_EXT_DIRECTORY for errors"
}

abort() {
    $bb echo -e "$er Aborting"
    exit 1
}

exit_success() {
    $bb echo -e "$ck Exiting Success"
    exit
}

exit_fail(){
    $bb echo -e "$er Exiting"
    exit 1
}

reboot_now() {
    $bb echo ""
    $bb echo "Your phone needs to be rebooted"
    read -p "Reboot now? (y|n) " answer
    if [ "$answer" == "y" ]; then
        $bb echo -e "$ck Rebooting..."
        $bb sync
        $bb reboot -f
        exit_success
    fi;
    exit_success
}

set_flag() {
    $bb echo -e "$ck Setting flag $1"
    $bb echo "x" > $SD_EXT_DIRECTORY/.$1
    $bb chmod 644 $SD_EXT_DIRECTORY/.$1
}

unset_flag() {
    $bb echo -e "$ck Removing flag $1"
    $bb rm -rf $SD_EXT_DIRECTORY/.$1 >/dev/null 2>&1
}

set_nocp_flag() {
#    $bb echo -e "$ck Setting nocp flag $1"
    $bb echo "x" > $SD_EXT_DIRECTORY/$1/.nocp
    $bb chmod 644 $SD_EXT_DIRECTORY/$1/.nocp
}

unset_nocp_flag() {
#    $bb echo -e "$ck Removing nocp flag $1"
    $bb rm -rf $SD_EXT_DIRECTORY/$1/.nocp >/dev/null 2>&1
}

set_data_flag() {
#    $bb echo -e "$ck Setting data flag $1"
    $bb echo "x" > /data/.$1
    $bb chmod 644 /data/.$1
}

unset_data_flag() {
#    $bb echo -e "$ck Removing data flag $1"
    $bb rm -rf /data/.$1 >/dev/null 2>&1
}

clear_dir() {
    # We cant just delete the folder since bind
    # mount is still in effect.
    if [ -d "$1" ]; then
        $bb echo -e "$ck Removing contents of $1"
        $bb rm -rf $1/* >/dev/null 2>&1
    else
        $bb echo -e "$er $1 directory not found"
    fi;
}

is_a2sd_active() {
    for ii in .a2sd .dc2sd .xdata .ad2sd; do
        if [ -f $SD_EXT_DIRECTORY/$ii ]; then
            $bb echo -e "$er a2sd is currently active please run 'remove' then reboot and run this command again"
            abort
        fi;
    done;
}

run_zipalign() {
    #do app-private first so people dont freak out
    #if it errors because it is empty
    for ii in app-private app; do
        $bb echo -e "Zipaligning all .apk files in /data/$ii"
        for apk in /data/$ii/*.apk ; do
            $zalign -c 4 $apk
            if [ $? == 1 ]; then
                $bb echo -e "ZipAligning $(basename $apk)"
                $zalign -f 4 $apk $tempstorage/$(basename $apk)
                if [ -e $tempstorage/$(basename $apk) ]; then
                    $bb cp -fp $tempstorage/$(basename $apk) $apk
                    $bb rm -rf $tempstorage/$(basename $apk) >/dev/null 2>&1
                    $bb echo -e "$ck ZipAligning $(basename $apk) complete."
                else
                    $bb echo -e "$er ZipAligning $(basename $apk) failed."
                fi;
            else
                $bb echo -e "$ck ZipAlign already completed on $apk"
            fi;
        done;
    done;
    exit_success
}

install_a2sd() {
    unset_flag a2sd
    unset_flag ad2sd
    unset_flag dc2sd
    unset_data_flag dc2sd
    set_flag a2sd
    $bb echo -e "Would you also like to move DALVIK-CACHE?"
    read -p "You can later undo this with 'nocachesd' (y|n) " answer
    if [ "$answer" == "y" ]; then
        set_flag dc2sd
        unset_data_flag dc2sd
        $bb echo -e "$ck Dalvik-Cache will be moved to $SD_EXT_DIRECTORY on reboot"
    fi;
    $bb echo -e "Would you also like to move APPDATA (/data/data)?"
    read -p "You can later undo this with 'nodatasd'? (y|n) " answer
    if [ "$answer" == "y" ]; then
        set_flag ad2sd
        $bb echo -e "$ck App data will be moved to $SD_EXT_DIRECTORY on reboot"
    fi;
    $bb echo -e ""
    $bb echo -e "$ck Your apps will be moved to $SD_EXT_DIRECTORY on reboot"
    reboot_now
}

remove_a2sd() {
    unset_flag a2sd
    unset_flag ad2sd
    unset_flag dc2sd
    for ll in app app-private app-asec data dalvik-cache; do
        if [ -d $SD_EXT_DIRECTORY/$ll ]; then
            read -p "Would you like to remove the contents of $SD_EXT_DIRECTORY/$ll? (y|n) " answer
            if [ "$answer" == "y" ]; then
                clear_dir "$SD_EXT_DIRECTORY/$ll"
            fi;
        fi;
    done;
    $bb echo -e "$ck Apps2sd will not be active on reboot. Your device will only use internal memory. You will need to restore/reinstall any apps you wish to use."
    reboot_now
}

install_xdata() {
    $bb echo -e "Warning:"
    $bb echo -e "This moves /everything/ on /data to $SD_EXT_DIRECTORY/xdata. You may experience significant performace loss. I highly recommend you use a class6 or 10 sdcard"
    $bb echo -e ""
    $bb echo -e "If you wish to /undo/ this with 'noxdata' your phone will revert back the the way it was before this. So any changes made while on xdata will be lost."
    $bb echo -e ""
    read -p "Do you wish to continue? (y|n) " answer
    if [ "$answer" != "y" ]; then
        abort
    fi;
    unset_flag dc2sd
    unset_flag a2sd
    unset_flag ad2sd
    unset_nocp_flag xdata
    unset_nocp_flag xdata/app
    unset_nocp_flag xdata/app-private
    unset_nocp_flag xdata/data
    unset_data_flag dc2sd
    set_flag xdata
    reboot_now
}

#
# Start main
#

# Make sure only root can run our script
if [[ "$($bb whoami)" != "root" ]]; then
   $bb echo -e "$er This script must be run as root"
   abort
fi

# Check no arguments
if [ $# -eq 0 ]; then
    $bb echo -e "$er This script cannot be run by itself."
    help_me
    abort
fi;

# a2sd is worthless without its partner
if [ ! -x "/system/etc/init.d/10apps2sd" ]; then
    $bb echo -e "$er 10apps2sd is either missing or not executable"
    abort
fi;

# determine the block device
if [[ "$a2sdblk" == "none" || -z "$a2sdblk" ]]; then
    $bb echo -e "$er $SD_EXT_DIRECTORY not mounted properly, it might have errors"
    # 05mountext blindly sets the ev.sdextpart prop to p2 of the sdcard
    if [ -z "$a2sdextpart" ]; then
        $bb echo -e "$er Ext partiton unknown!"
        abort
    else
        a2sdblk=$a2sdextpart
    fi
fi
# make sure block device exists
if [ -b "$a2sdblk" ]; then
    $bb echo -e "$ck Found block device: $a2sdblk"
else
    $bb echo -e "$er Block device doest exist: $a2sdblk"
    $bb echo -e "  Did you partiton your sdcard correctly??"
    abort
fi;

# big switch of actions
case $1
in
    "install")
            install_a2sd
            ;;
    "remove")
            remove_a2sd
            ;;
    "diskspace")
            $bb echo -e "Disk Space statistics on SD card"
            $bb df -h $a2sdblk
            exit_success
            ;;
    "align" | "zipalign" )
            run_zipalign
            exit_success
            ;;
    "fixapk" | "fixpermissions" )
            $fixperms
            exit_success
            ;;
    "cleancache")
            clear_dir "/data/dalvik-cache"
            unset_data_flag dc2sd
            reboot_now
            ;;
    "cachesd")
            $bb echo -e "$er Please run 'install' instead"
            exit_fail
            ;;
    "nocachesd")
            unset_flag dc2sd
            unset_data_flag dc2sd
            clear_dir "/data/dalvik-cache"
            $bb echo -e "Dalvik-Cache will be mounted on internal storage on reboot"
            reboot_now
            ;;
    "datasd")
            $bb echo -e "$er Please run 'install' instead"
            exit_fail
            ;;
    "nodatasd")
            unset_flag ad2sd
            $bb echo -e "Appdata will be mounted on internal storage on reboot"
            reboot_now
            ;;
    "xdata")
            install_xdata
            ;;
    "noxdata")
            unset_flag xdata
            unset_nocp_flag xdata/app
            unset_nocp_flag xdata/app-private
            unset_nocp_flag xdata/data
            read -p "Would you like to remove the contents of $SD_EXT_DIRECTORY/xdata? (y|n) " answer
            if [ "answer" == "y" ]; then
                clear_dir "$SD_EXT_DIRECTORY/xdata"
            fi;
            reboot_now
            ;;
    "rmsysdata")
            if [ -d $SD_EXT_DIRECTORY/data ]; then
                $bb find $SD_EXT_DIRECTORY/data -maxdepth 1 -name com.android.* -exec $bb rm -rf {} \;
                reboot_now
            else
                $bb echo -e "$SD_EXT_DIRECTORY/data not present...nothing to do"
            fi;
            exit_success
            ;;
    "formatext" | "formatsd")
            is_a2sd_active
            $bb echo -e "Warning this will erase everything on $SD_EXT_DIRECTORY"
            read -p "Do you want to continue? (y|n) " answer
            if [ "$answer" != "y" ]; then
                abort
            fi;
            $bb sync
            if ! awk -vDIR="$SD_EXT_DIRECTORY" '$2 == DIR { exit 1; }' /proc/mounts ; then
                $bb echo -e "Unmounting $SD_EXT_DIRECTORY"
                $bb umount "$SD_EXT_DIRECTORY"
            fi
            $bb echo -e "Formating $a2sdblk"
            $make2fs $a2sdblk
            $bb echo -e "$ck done..."
            exit_success
            ;;
    "checkext" | "checksd")
            $bb sync
            if ! awk -vDIR="$SD_EXT_DIRECTORY" '$2 == DIR { exit 1; }' /proc/mounts ; then
                $bb echo "$SD_EXT_DIRECTORY is mounted."
                $bb echo "Forcing check on next boot"
                setprop persist.a2sd.forcecheck true
                reboot_now
            fi
            $bb echo -e "checking $a2sdblk"
            $e2fscheck $a2sdblk
            $bb echo -e "$ck done..."
            if [ $? -gt 2 ]; then
                $bb echo -e "$er e2fsck could not fix all errors"
                $bb echo -e "  you need to run 'formatext'"
                exit_fail
            fi;
            reboot_now
            ;;
    *)
            $bb echo -e "$er Invalid command: $1"
            help_me
            abort
            ;;
esac;
# How the hell did we get here?
exit;
