#!/bin/bash
EDM="xcrun -sdk iphoneos.internal embedded_device_map"
MOBDEV=`xcrun -sdk iphoneos.internal -f mobdev`
PERSONALIZE_IMG4="xcrun -sdk iphoneos.internal personalize_img4"
TCPRELAY="xcrun -sdk iphoneos.internal tcprelay"
FSREMOUNT="`dirname $0`/fsremount"
CLEAN_TMP=
TCPRELAY_OUTPUT=
TCPRELAY_PID=
kBoardIDKey="BoardId"
kChipIDKey="ChipID"
kECIDKey="UniqueChipID"
VERBOSELEVEL=0
ROOTPASS="alpine"
KCACHEDST=/System/Library/Caches/com.apple.kernelcaches/kernelcache
SEPOSDST=/usr/standalone/firmware/sep-firmware.img4
PTYPE=" -X"
BOARDID=
CHIPID=
ECID=
LOCATIONID=
UDID=
function usage() {
echo "Usage: `basename $0` [-l location|-d udid] [options] [-S path|-C path] [-k kernelcache|-s sepos|-c file]"
echo
echo "Device selection:"
echo " -l Location ID"
echo " -u UDID"
echo
echo "Options:"
echo " -F Force local signing"
echo " -h Print this help"
echo " -k Kernelcache to install"
echo " -s SEP/OS to install"
echo " -c arbitrary file to install"
echo " -S override SEP/OS install location"
echo " -C override SEP/OS install location"
echo " -p Root password (default: alpine)"
echo " -X Enable user authlisting (default)"
echo " -v Enable verbosity (may specify more than once)"
}
function cleanup() {
if [[ $TCPRELAY_PID ]]; then
kill $TCPRELAY_PID
wait $TCPRELAY_PID 2>/dev/null
fi
if [ $CLEAN_TMP ]; then
rm -rf $TMPDIR
fi
}
trap cleanup EXIT
exec 9>/dev/null
args=$(getopt Fhk:l:p:s:S:c:C:u:vX $*)
if [ $? != 0 ]; then
usage; exit 1
fi
set -- $args
while [ $ case $1 in
-F)
PTYPE=" -F";;
-h)
usage; exit 0;;
-k)
KCACHE=$2; shift;;
-s)
SEPOS=$2; shift;;
-S)
SEPOSDST=$2; shift;;
-c)
COPYFILE=$2; shift;;
-C)
COPYDST=$2; shift;;
-l)
if [[ $UDID ]]; then
echo "Error: -l may not be specified with -u"
echo
usage; exit 1;
fi;
LOCATIONID=$2;
shift;;
-p)
ROOTPASS=$2;
shift;;
-u)
if [[ $LOCATIONID ]]; then
echo "Error: -u may not be specified with -l"
echo
usage; exit 1;
fi;
UDID=$2;
shift;;
-v)
case $VERBOSELEVEL in
0)
exec 9>&1
VERBOSELEVEL=1;;
1)
set -x
VERBOSELEVEL=2;;
*)
;;
esac;;
-X)
PTYPE=" -X";;
--)
if [ $ echo "Unrecognized options: $*"
usage; exit 1
fi
;;
*)
echo "Unrecognized option: $1"
usage; exit 1;;
esac
shift
done
if [[ ( -z $KCACHE && -z $SEPOS && -z $COPYFILE ) ]]; then
echo "Error: at least one of -k, -s or -c must be specified."
echo
usage; exit 1;
fi
if [[ $LOCATIONID ]]; then
mobdev list 2>&1 | grep $LOCATIONID > /dev/null
if [ $? -ne 0 ]; then
echo "Cannot find device at location $LOCATIONID"
exit $?
fi
MBDEVICE=" -l $LOCATIONID"
TRDEVICE=" --locationid $LOCATIONID"
elif [[ $UDID ]]; then
mobdev list 2>&1 | grep $UDID > /dev/null
if [ $? -ne 0 ]; then
echo "Cannot find device with UDID $UDID"
exit $?
fi
MBDEVICE=" -u $UDID"
TRDEVICE=" --serialnumber $UDID"
fi
TMPDIR=`mktemp -d -t \`basename $0\``
if [[ -z $TMPDIR ]]; then
echo "Could not create temporary directory"
exit 1;
fi
CLEAN_TMP=1
CHIPID=`$MOBDEV $MBDEVICE get NULL $kChipIDKey 2>&1 | awk '/CFNumber/ {print $5}' | sed 's/[+|,]//g'`
if [[ -z $CHIPID ]]; then
echo "Failed to read ChipID from device"
exit 1;
fi
IMAGEFORMAT=`$EDM -query SELECT DISTINCT ImageFormat FROM Targets WHERE ChipID==$CHIPID`
if [[ $IMAGEFORMAT == 'im4p' ]]; then
BOARDID=`$MOBDEV $MBDEVICE get NULL $kBoardIDKey 2>&1 | awk '/CFNumber/ {print $5}' | sed 's/[+|,]//g'`
if [[ -z $BOARDID ]]; then
echo "Failed to read BoardID from device"
exit 1;
fi
ECID=`$MOBDEV $MBDEVICE get NULL $kECIDKey 2>&1 | awk '/ECID in hex/ { print $4}'`
if [[ -z $ECID ]]; then
echo "Failed to read ECID from device"
exit 1;
fi
if [[ -n $KCACHE ]]; then
echo "Personalizing kernelcache for device with BoardID=`printf %d $BOARDID` ChipID=`printf 0x%x $CHIPID` ECID=`printf 0x%x $ECID`"
$PERSONALIZE_IMG4 -a -b $BOARDID -c $CHIPID -d 1 -e $ECID -n 0 -s 0 -i KernelCache=$KCACHE -i RestoreKernelCache=$KCACHE -o $TMPDIR $PTYPE >&9
if [ $? -ne 0 ]; then
echo "Personalization failed."
exit 1
fi
KCACHE=$TMPDIR/"`basename ${KCACHE}`.img4"
fi
if [[ -n $SEPOS ]]; then
echo "Personalizing SEP/OS for device with BoardID=`printf %d $BOARDID` ChipID=`printf 0x%x $CHIPID` ECID=`printf 0x%x $ECID`"
$PERSONALIZE_IMG4 -a -b $BOARDID -c $CHIPID -d 1 -e $ECID -n 0 -s 0 -i SEP=$SEPOS -i RestoreSEP=$SEPOS -l -o $TMPDIR $PTYPE >&9
if [ $? -ne 0 ]; then
echo "Personalization failed."
exit 1
fi
SEPOS=$TMPDIR/"`basename ${SEPOS%.*}`.img4"
fi
fi
TCPRELAY_OUTPUT=`mktemp -t tcprelay`
if [[ -z $TCPRELAY_OUTPUT ]]; then
echo "Could not create tcprelay output"
exit 1;
fi
$TCPRELAY $TRDEVICE --dynamicports --autoexit telnet rsync > $TCPRELAY_OUTPUT 2>&1 &
TCPRELAY_PID=$!
while [[ `stat -f "%z" $TCPRELAY_OUTPUT` -eq 0 ]]; do
sleep 1
done
TELNET_PORT=`awk '/127\.0\.0\.1.*telnet/ {print $9}' $TCPRELAY_OUTPUT | awk -F : '{print $2}'`
RSYNC_PORT=`awk '/127\.0\.0\.1.*rsync/ {print $9}' $TCPRELAY_OUTPUT | awk -F : '{print $2}'`
$FSREMOUNT localhost $TELNET_PORT $ROOTPASS rw >&9
case $? in
128)
SKIP_MOUNT_RO=1;;
0)
;;
*)
echo "Failed to mount root filesystem rw"
exit 1;;
esac
if [[ -n $KCACHE ]]; then
RSYNC_PASSWORD=$ROOTPASS rsync -v $KCACHE rsync://root@localhost:$RSYNC_PORT/root/$KCACHEDST >&9
if [ $? -ne 0 ]; then
echo "Failed to install kernelcache"
exit 1
else
echo "Kernelcache installed successfully."
fi
fi
if [[ -n $SEPOS ]]; then
RSYNC_PASSWORD=$ROOTPASS rsync -v $SEPOS rsync://root@localhost:$RSYNC_PORT/root/$SEPOSDST >&9
if [ $? -ne 0 ]; then
echo "Failed to install SEP/OS"
exit 1
else
echo "SEP/OS installed successfully."
fi
fi
if [[ -n $COPYFILE ]]; then
RSYNC_PASSWORD=$ROOTPASS rsync -v $COPYFILE rsync://root@localhost:$RSYNC_PORT/root/$COPYDST >&9
if [ $? -ne 0 ]; then
echo "Failed to install $COPYDST"
exit 1
else
echo "$COPYDST installed successfully."
fi
fi
if [ ! $SKIP_MOUNT_RO ]; then
$FSREMOUNT localhost $TELNET_PORT $ROOTPASS ro >&9
if [ $? -ne 0 ]; then
echo "Failed to mount root filesystem ro"
exit 1
fi
fi