#!/sbin/sh # nandroid v2.1 - an Android backup tool for the G1 by infernix and brainaid # Requirements: # - a modded android in recovery mode (JF 1.3 will work by default) # - adb shell as root in recovery mode if not using a pre-made recovery image # - busybox in recovery mode # - dump_image-arm-uclibc compiled and in path on phone # - mkyaffs2image-arm-uclibc compiled and installed in path on phone # Reference data: # dev: size erasesize name #mtd0: 00040000 00020000 "misc" #mtd1: 00500000 00020000 "recovery" #mtd2: 00280000 00020000 "boot" #mtd3: 04380000 00020000 "system" #mtd4: 04380000 00020000 "cache" #mtd5: 04ac0000 00020000 "userdata" #mtd6 is everything, dump splash1 with: dd if=/dev/mtd/mtd6ro of=/sdcard/splash1.img skip=19072 bs=2048 count=150 # We don't dump misc or cache because they do not contain any useful data that we are aware of at this time. # Logical steps (v2.1): # # 0. test for a target dir and the various tools needed, if not found then exit with error. # 1. check "adb devices" for a device in recovery mode. set DEVICEID variable to the device ID. abort when not found. # 2. mount system and data partitions read-only, set up adb portforward and create destdir # 3. check free space on /cache, exit if less blocks than 20MB free # 4. push required tools to device in /cache # 5 for partitions boot recovery misc: # 5a get md5sum for content of current partition *on the device* (no data transfered) # 5b while MD5sum comparison is incorrect (always is the first time): # 5b1 dump current partition to a netcat session # 5b2 start local netcat to dump image to current dir # 5b3 compare md5sums of dumped data with dump in current dir. if correct, contine, else restart the loop (6b1) # 6 for partitions system data: # 6a get md5sum for tar of content of current partition *on the device* (no data transfered) # 6b while MD5sum comparison is incorrect (always is the first time): # 6b1 tar current partition to a netcat session # 6b2 start local netcat to dump tar to current dir # 6b3 compare md5sums of dumped data with dump in current dir. if correct, contine, else restart the loop (6b1) # 6c if i'm running as root: # 6c1 create a temp dir using either tempdir command or the deviceid in /tmp # 6c2 extract tar to tempdir # 6c3 invoke mkyaffs2image to create the img # 6c4 clean up # 7. remove tools from device /cache # 8. umount system and data on device # 9. print success. DEVICEID=foo RECOVERY=foo echo "nandroid-mobile v2.1" if [ "$1" == "" ]; then echo "Usage: $0 {backup|restore} [/path/to/nandroid/backup/]" echo "- backup will store a full system backup on /sdcard/nandroid/$DEVICEID" echo "- restore path will restore the last made backup for boot, system, recovery and data" exit 0 fi case $1 in backup) mkyaffs2image=`which mkyaffs2image` if [ "$mkyaffs2image" == "" ]; then mkyaffs2image=`which mkyaffs2image-arm-uclibc` if [ "$mkyaffs2image" == "" ]; then echo "error: mkyaffs2image or mkyaffs2image-arm-uclibc not found in path" exit 1 fi fi dump_image=`which dump_image` if [ "$dump_image" == "" ]; then dump_image=`which dump_image-arm-uclibc` if [ "$dump_image" == "" ]; then echo "error: dump_image or dump_image-arm-uclibc not found in path" exit 1 fi fi break ;; restore) flash_image=`which flash_image` if [ "$flash_image" == "" ]; then flash_image=`which flash_image-arm-uclibc` if [ "$flash_image" == "" ]; then echo "error: flash_image or flash_image-arm-uclibc not found in path" exit 1 fi fi break ;; esac # 1 DEVICEID=`cat /proc/cmdline | sed "s/.*serialno=//" | cut -d" " -f1` RECOVERY=`cat /proc/cmdline | grep "androidboot.mode=recovery"` if [ "$RECOVERY" == "foo" ]; then echo "error: not running in recovery mode, aborting" exit 1 fi if [ "$DEVICEID" == "foo" ]; then echo "error: device id not found in /proc/cmdline, aborting" exit 1 fi if [ ! "`id -u 2>/dev/null`" == "0" ]; then if [ "`whoami 2>&1 | grep 'uid 0'`" == "" ]; then echo "error: must run as root, aborting" exit 1 fi fi case $1 in restore) ENERGY=`cat /sys/class/power_supply/battery/capacity` if [ "`cat /sys/class/power_supply/battery/status`" == "Charging" ]; then ENERGY=100 fi if [ ! $ENERGY -ge 30 ]; then echo "Error: not enough battery power" echo "Connect charger or USB power and try again" exit 1 fi RESTOREPATH=$2 if [ ! -f $RESTOREPATH/nandroid.md5 ]; then echo "error: $RESTOREPATH/nandroid.md5 not found, cannot verify backup data" exit 1 fi umount /system 2>/dev/null umount /data 2>/dev/null if [ ! "`mount | grep data`" == "" ]; then echo "error: unable to umount /data, aborting" exit 1 fi if [ ! "`mount | grep system`" == "" ]; then echo "error: unable to umount /system, aborting" exit 1 fi echo "Verifying backup images..." CWD=$PWD cd $RESTOREPATH md5sum -c nandroid.md5 if [ $? -eq 1 ]; then echo "error: md5sum mismatch, aborting" exit 1 fi for image in boot recovery; do echo "Flashing $image..." $flash_image $image $image.img done echo "Flashing system and data not currently supported" echo "Restore done" exit 0 ;; backup) break ;; *) echo "Usage: $0 {backup|restore} [/path/to/nandroid/backup/]" echo "- backup will store a full system backup on /sdcard/nandroid/$DEVICEID" echo "- restore path will restore the last made backup for boot, system, recovery and data" exit 1 ;; esac # 2. echo "mounting system and data read-only, sdcard read-write" umount /system 2>/dev/null umount /data 2>/dev/null umount /sdcard 2>/dev/null mount -o ro /system || FAIL=1 mount -o ro /data || FAIL=2 mount /sdcard || mount /dev/block/mmcblk0 /sdcard || FAIL=3 case $FAIL in 1) echo "Error mounting system read-only"; umount /system /data /sdcard; exit 1;; 2) echo "Error mounting data read-only"; umount /system /data /sdcard; exit 1;; 3) echo "Error mounting sdcard read-write"; umount /system /data /sdcard; exit 1;; esac TIMESTAMP="`date +%Y%m%d-%H%M`" DESTDIR="/sdcard/nandroid/$DEVICEID/$TIMESTAMP" if [ ! -d $DESTDIR ]; then mkdir -p $DESTDIR if [ ! -d $DESTDIR ]; then echo "error: cannot create $DESTDIR" umount /system 2>/dev/null umount /data 2>/dev/null umount /sdcard 2>/dev/null exit 1 fi else touch $DESTDIR/.nandroidwritable if [ ! -e $DESTDIR/.nandroidwritable ]; then echo "error: cannot write to $DESTDIR" umount /system 2>/dev/null umount /data 2>/dev/null umount /sdcard 2>/dev/null exit 1 fi rm $DESTDIR/.nandroidwritable fi # 3. echo "checking free space on sdcard" FREEBLOCKS="`df -k /sdcard| grep sdcard | awk '{ print $4 }'`" # we need about 130MB for the dump if [ $FREEBLOCKS -le 130000 ]; then echo "error: not enough free space available on sdcard (need 130mb), aborting." umount /system 2>/dev/null umount /data 2>/dev/null umount /sdcard 2>/dev/null exit 1 fi if [ -e /dev/mtd/mtd6ro ]; then echo -n "Dumping splash1 from device over tcp to $DESTDIR/splash1.img..." dd if=/dev/mtd/mtd6ro of=$DESTDIR/splash1.img skip=19072 bs=2048 count=150 2>/dev/null echo "done" sleep 1s echo -n "Dumping splash2 from device over tcp to $DESTDIR/splash2.img..." dd if=/dev/mtd/mtd6ro of=$DESTDIR/splash2.img skip=19456 bs=2048 count=150 2>/dev/null echo "done" fi # 5. for image in boot recovery misc; do # 5a DEVICEMD5=`$dump_image $image - | md5sum | awk '{ print $1 }'` sleep 1s MD5RESULT=1 # 5b echo -n "Dumping $image to $DESTDIR/$image.img..." ATTEMPT=0 while [ $MD5RESULT -eq 1 ]; do let ATTEMPT=$ATTEMPT+1 # 5b1 $dump_image $image $DESTDIR/$image.img sync # 5b3 echo "${DEVICEMD5} $DESTDIR/$image.img" | md5sum -c -s - if [ $? -eq 1 ]; then true else MD5RESULT=0 fi if [ "$ATTEMPT" == "5" ]; then echo "fatal error while trying to dump $image, aborting" umount /system umount /data umount /sdcard exit 1 fi done echo "done" done # 6 for image in system data cache; do # 6a echo -n "Dumping $image to $DESTDIR/$image.img..." $mkyaffs2image /$image $DESTDIR/$image.img sync echo "done" done # 7. echo -n "generating md5sum file..." CWD=$PWD cd $DESTDIR md5sum *img > nandroid.md5 cd $CWD echo "done" # 8. echo "unmounting system, data and sdcard" umount /system umount /data umount /sdcard # 9. echo "Backup successful."