#!/system/bin/sh
#
# Switch2SD (S2SD)
#
# Script to switch the app and dalvik-cache directories to the ext partition
# in the SD card
#
# It allows to use the phone internal memory only for the data. Which in my
# opinion it is what it was intended for. Check with Freespace from Google Play
# the enourmous save in internal memory and how much of the SDext is used!!
#
# Developed by:
#
# Miche1asso @ XDA
# Michelasso @ androidiani.com
#
# Version 1.07

#
# /system/xbin first to hopefully get access to the last busybox installed
PATH=/system/xbin:/sbin:/system/bin
S2SD_LOG=/data/log/S2SD_log.txt
#
# fix the /data/log directory if needed
#
if [ ! -d /data/log ]; then
	# remove it if anything else. Fail through if not existent
	logwrapper rm /data/log 
	mkdir /data/log
fi
# To log is a Constitutional right. Allow everyone
logwrapper chmod 777 /data/log
#
# And now start the real execution!!
log -p i -t Switch2SD "Starting Switch2SD"
echo "#" >> $S2SD_LOG
echo $(date "+%Y-%m-%d %H:%M:%S"): Switch2SD started >> $S2SD_LOG
#
# busybox must be installed.
BB=$(busybox which busybox)
# If there is no busybox there is nothing to do. Report and exit
# 
if [ -z $BB ]; then
	log -p e -t Switch2SD "busybox not present. Root your phone and install busybox"
	log -p e -t Switch2SD "Switch2SD ended"
	echo $(date "+%Y-%m-%d %H:%M:%S"): busybox not present. Root your phone and install busybox >> $S2SD_LOG
	echo $(date "+%Y-%m-%d %H:%M:%S"): Switch2SD ended >> $S2SD_LOG
	exit 1
fi
LBB="logwrapper $BB"
BBDIR="/cache/.busybox"
#
alias EXIT="rm -r $BBDIR; mount -o remount,ro /system; exit "
#
# stupid e2fs apps ask for this file even if empty...
mount -o remount,rw /system
touch /etc/mtab
# Prepare a temporary copy of the applets links anyway. They might be messed up
# let's also define a clean exit
#
$LBB rm -r $BBDIR
$LBB mkdir -p $BBDIR
$BB --install -s $BBDIR
log -p d -t Switch2SD "busybox applets in $($BB ls -ld $BBDIR 2>&1)"
#
PATH=$BBDIR:$PATH
#
# First  collect some info about the SD card device
#
SD_FAT_PARTION=$($BB grep sdcard /res/recovery.fstab | awk '{print $3}')
log -p d -t Switch2SD "SD FAT partition is $SD_FAT_PARTION"
echo $(date "+%Y-%m-%d %H:%M:%S"): SD FAT partition is $SD_FAT_PARTION >> $S2SD_LOG
#                                                                                 
# Exit if the partition is already mounted. We don't want to mess up with its files
#
if [ "$($BB mount | grep /data/app)" != "" ]
then
	log -p w -t Switch2SD "Switch2SD or similar script has already run. Exiting..."
	echo $(date "+%Y-%m-%d %H:%M:%S"): Switch2SD or similar script has already run. Exiting >> $S2SD_LOG
	EXIT 1
fi
#
# Choose directory /sd-ext to mount the SD ext partition
# This is compatible with some Google Play apps like Freespace
#
SD_EXT_DIRECTORY=/sd-ext
#
# Check $SD_EXT_DIRECTORY isn't already mounted and clean any possible garbage
# Don't logwrap the check. It won't work.
#
if [ "$(mount | grep $SD_EXT_DIRECTORY)" = "" ]
then 
# mount rootfs r/w                                                          
	$LBB mount -o remount,rw / /
#
# make sure $SD_EXT_DIRECTORY is a directory removing anything if present
	$LBB rm -rf $SD_EXT_DIRECTORY
	$LBB mkdir $SD_EXT_DIRECTORY
	$LBB chmod 755 $SD_EXT_DIRECTORY
	log -p i -t Switch2SD "Directory $SD_EXT_DIRECTORY created"
	echo $(date "+%Y-%m-%d %H:%M:%S"): Directory $SD_EXT_DIRECTORY created >> $S2SD_LOG
#
# mount rootfs r/o                                                          
	$LBB mount -o remount,ro / /
else
	log -p e -t Switch2SD "$SD_EXT_DIRECTORY is already mounted. Exiting..."
	echo $(date "+%Y-%m-%d %H:%M:%S"): $SD_EXT_DIRECTORY is already mounted. Exiting >> $S2SD_LOG
	EXIT 1
fi

# find SD Card. This works for most phones. It can be extended.
# Loop for N times 1 sec each until SD is ready. 
SD_EXT_PART="NONE"
for i in `seq 1 9`; do
    for MMC_NUM in `seq 0 9`
    do
	MMC_TYPE=`cat /sys/block/mmcblk$MMC_NUM/device/type`
        if [ "$MMC_TYPE" = "SD" ]
        then
        # 2nd partition of sdcard should be $SD_EXT_PART if exist
            SD_EXT_PART=/dev/block/mmcblk${MMC_NUM}p2
            break
        fi
    done
    if [ $SD_EXT_PART != "NONE" ]; then                                                 
		break;
    fi
    log -p w -t Switch2SD "Loop $i: Waiting for SD card to be ready"
    echo $(date "+%Y-%m-%d %H:%M:%S"): Loop $i: Waiting for SD card to be ready >> $S2SD_LOG
    sleep 1
done
#
if [ $SD_EXT_PART = "NONE" ]; then                                                                              
	SD_EXT_PART=/dev/block/mmcblk0p2
	log -p e -t Switch2SD "SD card not recognized yet. Assuming partition is $SD_EXT_PART"
	echo $(date "+%Y-%m-%d %H:%M:%S"): SD card not recognized yet. Assuming partition is $SD_EXT_PART >> $S2SD_LOG
else
	log -p i -t Switch2SD "SD ext partition is $SD_EXT_PART"
	echo $(date "+%Y-%m-%d %H:%M:%S"): SD ext partition is $SD_EXT_PART >> $S2SD_LOG
fi
#
if [ "$(mount | grep $SD_EXT_PART)" != "" ]; then
#
# Something is wrong. The partition is already in use
#
	log -p e -t Switch2SD "$SD_EXT_PART is already mounted. Exiting..."                                                                  
	echo $(date "+%Y-%m-%d %H:%M:%S"): Switch2SD $SD_EXT_PART is already mounted. Exiting >> $S2SD_LOG                                   
	EXIT 1                                                                                                                                    
fi
#
if [ ! -b "$SD_EXT_PART" ]; then
#                                                                                                    
# SD_EXT_PART is there but it is not a block device?                          
#                                                                                                     
	log -p e -t Switch2SD "The partiton $SD_EXT_PART is not a block device. The SD card may be corrupted"
	log -p e -t Switch2SD "Please format it in FAT32 and partition it again"
	log -p e -t Switch2SD "$SD_EXT_PART is $(ls -l $SD_EXT_PART)"                    
	echo $(date "+%Y-%m-%d %H:%M:%S"): The partiton $SD_EXT_PART is not a block device. The SD card may be corrupted >> $S2SD_LOG
	echo $(date "+%Y-%m-%d %H:%M:%S"): Please format it in FAT32 and partition it again >> $S2SD_LOG                    
	echo $(date "+%Y-%m-%d %H:%M:%S"): $SD_EXT_PART is $(ls -l $SD_EXT_PART) >> $S2SD_LOG
	EXIT 5
fi

# Some kernels still supporting ext4 don't support huge files..
if [ ! -x "`which tune2fs`" ]; then
	log -p w -t Switch2SD "tune2fs not found. It is highly suggested to install it"
	echo $(date "+%Y-%m-%d %H:%M:%S"): tune2fs not found. It is highly suggested to install it >> $S2SD_LOG
elif [ "$(tune2fs -l $SD_EXT_PART | grep huge_file)" != "" ]; then
	log -p w -t Switch2SD "huge_file property detected on $SD_EXT_PART. Fixing.."
	echo $(date "+%Y-%m-%d %H:%M:%S"): huge_file property detected on $SD_EXT_PART. Fixing.. >> $S2SD_LOG
#
	tune2fs -O ^huge_file $SD_EXT_PART
	e2fsck -pf $SD_EXT_PART
else
	log -p w -t Switch2SD "No huge_file property detected on $SD_EXT_PART"
	echo $(date "+%Y-%m-%d %H:%M:%S"): No huge_file property detected on $SD_EXT_PART>> $S2SD_LOG
fi
sync
	
# fsck the sdcard filesystem first
if [ -x "`which e2fsck`" ]; then
	log -p w -t Switch2SD "Running e2fsck on $SD_EXT_PART"
	echo $(date "+%Y-%m-%d %H:%M:%S"): Running e2fsck on $SD_EXT_PART >> $S2SD_LOG
	e2fsck -pf $SD_EXT_PART
	e2fsk_exitcode=$?
else
	log -p w -t Switch2SD "Executable e2fsck not found. It is highly suggested to install it" 
	log -p w -t Switch2SD "Assuming no filesystem errors"
	echo $(date "+%Y-%m-%d %H:%M:%S"): "executable e2fsck not found. It is highly suggested to install it" >> $S2SD_LOG
	echo $(date "+%Y-%m-%d %H:%M:%S"): "Assuming no filesystem errors" >> $S2SD_LOG
	e2fsk_exitcode=0
fi
sync
# set property with exit code in case an error occurs
if [ "$e2fsk_exitcode" -lt 2 ]
then
	log -p i -t Switch2SD "Partition $SD_EXT_PART checked. Mounting $SD_EXT_DIRECTORY"
	echo $(date "+%Y-%m-%d %H:%M:%S"): "Partition $SD_EXT_PART checked. Mounting $SD_EXT_DIRECTORY" >> $S2SD_LOG
else
	log -p e -t Switch2SD "Unable to repair filesystem $SD_EXT_PART"
	log -p e -t Switch2SD "You need to repair the second partition from Linux or reformat the partion"
	echo $(date "+%Y-%m-%d %H:%M:%S"): Unable to repair filesystem $SD_EXT_PART >> $S2SD_LOG
	echo $(date "+%Y-%m-%d %H:%M:%S"): You need to repair the second partition from Linux or reformat the partion >> $S2SD_LOG
	echo $(date "+%Y-%m-%d %H:%M:%S"): "$(e2fsck -pf $SD_EXT_PART 2>&1)" >> $S2SD_LOG 
	EXIT 3
fi			
#
# mount and set permissions
# ext4 first. Linux may allow to mount non ext4 partitions as such
#
$LBB mount -o noatime,nodiratime,barrier=0 -t ext4 $SD_EXT_PART $SD_EXT_DIRECTORY
$LBB mount -o noatime,nodiratime,barrier=0 -t ext3 $SD_EXT_PART $SD_EXT_DIRECTORY
$LBB mount -o noatime,nodiratime,barrier=0 -t ext2 $SD_EXT_PART $SD_EXT_DIRECTORY

if [ "$($BB mount | grep $SD_EXT_DIRECTORY)" != "" ]; then
	$LBB chown 1000:1000 $SD_EXT_DIRECTORY
	$LBB chmod 775 $SD_EXT_DIRECTORY
	log -p i -t Switch2SD "Directory $SD_EXT_DIRECTORY successfully mounted on $SD_EXT_PART"
	echo $(date "+%Y-%m-%d %H:%M:%S"): "Directory $SD_EXT_DIRECTORY successfully mounted on $SD_EXT_PART" >> $S2SD_LOG
else
	log -p i -t Switch2SD "$($BB mount)"
	log -p e -t Switch2SD "Unable to mount directory $SD_EXT_DIRECTORY on partition $SD_EXT_PART"
	echo $(date "+%Y-%m-%d %H:%M:%S"): "Unable to mount directory $SD_EXT_DIRECTORY on partition $SD_EXT_PART" >> $S2SD_LOG
	EXIT 1
fi
#                      
#
# Double check the partition has been correctly mounted.
# This is a MUST since from now on we modify all application files.
#
if [ "$($BB mount | grep $SD_EXT_DIRECTORY)" = "" ]; then
	log -p e -t Switch2SD "$SD_EXT_DIRECTORY isn't mounted!!! Exiting..."
	echo $(date "+%Y-%m-%d %H:%M:%S"): "ERROR: $SD_EXT_DIRECTORY isn't mounted. Exiting..." >> $S2SD_LOG
#
# Debug.
#
	log -p d -t Switch2SD "$($BB mount)"
	echo $(date "+%Y-%m-%d %H:%M:%S"): "$($BB mount)" >> $S2SD_LOG
	EXIT 1
fi
#
# First uninstall Link2SD from the device if present!!
#
$LBB rm -f /system/app/Link2SD*.apk
$LBB rm -f /data/app/com.buak.Link2SD*.apk
$LBB rm -rf /data/data/com.buak.Link2SD
#
# Now the scripts and dir
#
$LBB rm -f /etc/install-recovery.sh
$LBB rm -f /etc/init.d/11link2sd
$LBB rmdir  /data/sdext2
#
# Move the applications in the phome memory into the external partition
# Only if they do not exist already...
#
for i in /data/app/*.apk; do
	if [ "$i" == "/data/app/*.apk" ]; then
		log -p i -t Switch2SD "No apps to move to $SD_EXT_DIRECTORY"
		echo $(date "+%Y-%m-%d %H:%M:%S"): No apps to move to $SD_EXT_DIRECTORY >> $S2SD_LOG
		break
	fi
#
# Copy and then remove. Delete if already installed
#
	j=$(basename $i | awk -F- '{print  $1 }')
	if [ "$(ls $SD_EXT_DIRECTORY/$j-*.apk)" = "" ]; then
		log -p i -t Switch2SD "Moving $i to $SD_EXT_DIRECTORY"
		echo $(date "+%Y-%m-%d %H:%M:%S"): Moving $i to $SD_EXT_DIRECTORY >> $S2SD_LOG
		$BB cp -p $i $SD_EXT_DIRECTORY
		$BB rm -f $i
	else
		log -p i -t Switch2SD "$i already installed in $SD_EXT_DIRECTORY. Deleting"
		echo $(date "+%Y-%m-%d %H:%M:%S"): $i already installed in $SD_EXT_DIRECTORY. Deleting >> $S2SD_LOG
		$BB rm -f $i
	fi
done
#
# This will remove any potential occurence of Link2SD in the ext partition
# 
$LBB find $SD_EXT_DIRECTORY -iname 'com.buak.Link2SD*' -exec $LBB rm -f {} \;
#
# Mount the external data above the internal one
#	
$LBB mount $SD_EXT_DIRECTORY /data/app
#
# Make sure the dalvik-cache folder is present and it is a directory
#	
if [ ! -d $SD_EXT_DIRECTORY/dalvik-cache ]; then
	$LBB rm -rf $SD_EXT_DIRECTORY/dalvik-cache
	$LBB mkdir $SD_EXT_DIRECTORY/dalvik-cache
else
#
# Remove any old occurence of Link2SD in the dalvik cache
# It preserves the real dalvik-cache. They may come from S2SD!!!
#
	$LBB find $SD_EXT_DIRECTORY/dalvik-cache -type l -exec $LBB rm -f {} \;
fi
$LBB chmod 775 $SD_EXT_DIRECTORY/dalvik-cache
#
# Clean the dalvik-cache in the phone memory then recreate the folder to be mounted.
# This will free precious internal memory useful for real data (MMS, mail..).
#
# We don't care if rm -rf fails because it doesn't exist, just fail through
# In case this script will fail for any reason, or the SD card isn't mounted
# the internal dalvik-cache will be automatically re-created.
#
$LBB rm -rf /data/dalvik-cache
$LBB mkdir /data/dalvik-cache
$LBB chmod 775 /data/dalvik-cache
#
# Mount the dalvik cache directory in the ext partition
#
$LBB mount $SD_EXT_DIRECTORY/dalvik-cache /data/dalvik-cache
$LBB chmod 775 $SD_EXT_DIRECTORY/dalvik-cache
#
# It seems now there is even /data/cache ...
#
$LBB rm -rf /data/cache $SD_EXT_DIRECTORY/cache
$LBB mkdir /data/cache $SD_EXT_DIRECTORY/cache
$LBB chmod 775 /data/cache $SD_EXT_DIRECTORY/cache
mount $SD_EXT_DIRECTORY/cache /data/cache
#	
# default install location is internal. No need for app2SD or
# similar junk. We have all the space we decided we need
#
# It crashes if called just after boot?!? What a piece of junk!
#pm setInstallLocation 1
#
# Finito!
log -p i -t Switch2SD "Switch2SD ended successfully"
echo $(date "+%Y-%m-%d %H:%M:%S"): Switch2SD ended successfully >> $S2SD_LOG
#
# Enjoy your nearly unlimited internal memory!!
EXIT 0
