#!/bin/busybox sh
#
# Copyright (C) 2013 fakesh. http://sourceforge.jp/users/fakesh/
# MIT/X Consortium License
#

case "$mkBackupLOG" in
*.txt) ;;
*)
  mkBackupLOG="/mnt/onboard/backup$(date +%y%m%d%H%M).log.txt"
  export mkBackupLOG
  exec "$0" "$@" 2>&1 | tee "$mkBackupLOG"
  exit
;;
esac

vol=mmcblk1

if grep -q '^/dev/mmcblk0p2' </proc/mounts >/dev/null 2>&1 ; then
  echo "umount /dev/mmcblk0p2; : first."
  exit 1
fi

date '+---- %H:%M:%S ----'
me="$(readlink -f "$0")"
cd /
case "$me" in
*-oneShot.sh)
  rm -f "$me"
  me="${me%/*}"; rmdir --ignore-fail-on-non-empty "$me"
  me="${me%/*}"; rmdir --ignore-fail-on-non-empty "$me"
  KoboRoot_tgz=/mnt/onboard/.kobo/KoboRoot.tgz
  if [ -f $KoboRoot_tgz ] ; then # fail safe
    empDir=`mktemp -d`
    cd $empDir
    chmod 755 .
    tar cfz - . > $KoboRoot_tgz
  fi
;;
esac >/dev/null 2>&1

sedfdisk='/^$/d;
/^Command/d;
1,/^Disk /{/^Disk/p;d};
/^Disk /d;
/cylinders$/d;
/^Units/{x;p;x;}'

echo 'Current INNER disk geometory:'
printf 'u\np\nu\np\nq\n' | fdisk /dev/mmcblk0 | sed "$sedfdisk"
printf \\n

wnkCyc=$(mktemp /tmp/whinkerCyc_XXXXXX)
ledR=/sys/class/leds/pmic_ledsr/brightness
ledG=/sys/class/leds/pmic_ledsg/brightness
ledB=/sys/class/leds/pmic_ledsb/brightness
[ -f "$ledR" ] || ledR=/dev/null
[ -f "$ledG" ] || ledG=/dev/null
[ -f "$ledB" ] || ledB=/dev/null
while : ; do
  if [ ! -f $wnkCyc ] ; then
    echo 0 > "$ledR"
    echo 0 > "$ledG"
    echo 0 > "$ledB"
    exit 0
  fi
  wwait=250  # msec
  while read mcs r g b dum ; do
    # args check
    [ 0 -lt "$mcs" -a "$mcs" -le 2000 ] || continue
    [ 0 -le "$r" -a "$r" -le 255 ] || continue
    [ 0 -le "$g" -a "$g" -le 255 ] || continue
    [ 0 -le "$b" -a "$b" -le 255 ] || continue
    echo $r > "$ledR"
    echo $g > "$ledG"
    echo $b > "$ledB"
    usleep $((mcs*1000))
    wwait=""
  done < $wnkCyc
  [ -n "$wwait" ] && usleep $((wwait*1000))
done < /dev/null > /dev/null 2>&1 &

pipetrash=`mktemp /tmp/pipe-trash_XXXXXX`  # dont delete on exit
magicMSG="_#the#end#of#messages#$$#_"
pipeCleaner () {
  touch $pipetrash
  while : ; do
    while read -r l ; do
      echo "$(date +%H:%M:%S) $l" >> $pipetrash
      [ "$magicMSG" = "$l" ] || continue
      [ -n "$1" ] && kill -CONT $1
      exit 0
    done < /tmp/nickel-hardware-status
  done &
  return 0
}

nickelCtrl () {
  local pid l
  pid=$(pidof nickel)
  #  pipe=/tmp/nickel-hardware-status
  case "$1" in
  STOP)
    if [ -z "$pid" ] ; then
      pipeCleaner
      return 1
    fi
    if awk '$1!="State:"{next;}
            $2=="T"{exit 0;}
            {exit 1;}' /proc/$pid/status ; then
      echo 'ERROR: nickel is alive and STOPed. WHY?'
      rm -f $wnkCyc
      exit 2
    fi
    kill -STOP $pid
    pipeCleaner $pid
    return 0
  ;;
  CONT)
    printf '\n%s\n' "$magicMSG" > /tmp/nickel-hardware-status
    [ -n "$pid" ]
    return
  ;;
  esac
}

wSec=30
n=0
while [ $n -lt $wSec ] ; do
  if grep -q "$vol\$" /proc/partitions >/dev/null 2>&1 ; then
    if [ $n -eq 0 ] ; then
      rm -f $wnkCyc
      echo "Dont insert mcSD, first. Eject mcSD."
#      rm -f "$mkBackupLOG"
      exit 3
    else
      printf 'Found'
      break
    fi
  elif [ $n -eq 0 ] ; then
    printf '30 99 0 0\n30 99 99 0\n30 0 99 0\n400 0 0 0\n' > $wnkCyc
    echo 'Send signal STOP to nickel, udevd, etc.'
    nickelCtrl STOP || echo 'But nickel is already DEAD... OK'
    for p in $(pidof udevd fickel hindenburg) ; do kill -STOP $p ; done
    echo "Insert mcSD in $wSec sec."
    sleep 1
  else
    sleep 1
  fi
  n=$((n+1))
  printf .
done
printf \\n
sleep 4 # for insert time lag
date '+---- %H:%M:%S ----'
pz="$(awk -v "d=$vol" '
  $4==d{printf "%d", int($3/1024)*2-1}
  ' /proc/partitions)"

wdir=$(mktemp -d /tmp/dev_XXXXXX)
cd "$wdir"

# exitWithMsg msg exitStatus
exitWithMsg () {
  cd /
  rm -rf "$wdir"
  printf '%s\n%s\n' "$1" "$(date '+---- %H:%M:%S ----')"
  yel=99
  [ "$2" -eq 0 ] && yel=0
  printf '10 %d 99 0\n690 0 0 00\n' $yel > $wnkCyc
  if grep -q "$vol\$" /proc/partitions >/dev/null 2>&1 ; then
    printf 'Please eject mcSD media'
    while : ; do
      printf .
      sleep 1
      grep -q "$vol\$" /proc/partitions >/dev/null 2>&1 || break
    done
    printf '\nEjected\n%s\n' "$(date '+---- %H:%M:%S ----')"
  fi
  printf '200 99 99 99\n300 0 0 00\n' > $wnkCyc
  echo 'Send signal CONT to udevd, etc...'
  for p in $(pidof hindenburg fickel udevd) ; do kill -CONT $p ; done
  echo 'Wait another 7 secs for pipe cleaning'
  sleep 7 # udev is insistent
  nickelCtrl CONT && echo 'Sent signal CONT to nickel.'
  usleep 250000  # 250msec
  echo '  -  -  -  droped messages to nickel  -  -  -'
  cat $pipetrash
  rm -f $pipetrash
  printf '\nExit.\n'
  rm -f $wnkCyc
  {
    ## log cleaner
    sedcmd="$(printf 's/........\b\b\b\b\b\b\b\b//g;';
            printf 's/....\b\b\b\b//g;s/..\b\b//g;s/.\b//g')"
    sleep 1
    sed -i "$sedcmd" "$mkBackupLOG"
  } </dev/null >/dev/null 2>&1 &
  exit $2
}

if [ -z "$pz" ] ; then
  # rm -f "$mkBackupLOG"
  exitWithMsg '+++ NO mcSD media.' 0
fi

printf '20 99 0 0\n800 0 0 99\n' > $wnkCyc
# unit = 512KiB
p6=''
if [ $pz -lt 1600 ] ; then
  exitWithMsg '***ERROR too small mcSD media.' 5
elif [ $pz -lt 5000 ] ; then
  # 1GB or 2GB : 240.5M 200M - 100M
  p1=20
  p2=501
  p3=901
  p5=$((pz-200))
  p9=$pz
elif [ $pz -lt 12000 ] ; then
  # 4GB : 390M 300M - 200M
  p1=21
  p2=801
  p3=1401
  p5=$((pz-400))
  p9=$pz
elif [ $pz -lt 24000 ] ; then
  # 8GB : 590M 400M - 400M 200M
  p1=21
  p2=1201
  p3=2001
  p5=$((pz-1200))
  p6=$((pz-400))
  p9=$pz
else
  # > 8GB : 990M 600M - 600M 1200M
  p1=21
  p2=2001
  p3=3201
  p5=$((pz-3600))
  p6=$((pz-2400))
  p9=$pz
fi
ptn=5
pt="$p1 $p2 $p3 $p5 $p6 $p9"

## 
paramfile=/mnt/onboard/easyBackup.param
if [ -f $paramfile ] ; then
  read ptn < $paramfile
  pt="${ptn#*:}"; pt="${pt%[!0-9]}"
  ptn=$((${ptn%%:*}+0))
fi

mkDevices () {
  while read major minor blocks nam ; do
    case "$nam" in $vol*)
      rm -f "$nam"
      mknod -m 600 "$nam" b $major $minor
    ;; esac
  done < /proc/partitions
}
mkDevices

echo 'Partitioning of OUTER disk will be:'
pp=''
n=0
for p in $pt ; do
  if [ -z "$pp" ] ; then
    pp=$p
    [ $p -lt 20 ] && exitWithMsg "Must be 20 <= $p" 6
    continue
  fi
  n=$((n+1))
  [ $p -gt $pz ] && p=$pz
  [ $pp -lt $p ] || exitWithMsg "Must be $pp < $p for $lvl" 7
  case $n in
  1) # 192MiB
    lvl="rootfs"
    [ $((p-pp)) -lt 384 ] && \
      exitWithMsg "Must be $pp + 384 <= $p for $lvl" 8
  ;; 
  2) # 144MiB
    lvl="recoveryfs"
    [ $((p-pp)) -lt 288 ] && \
      exitWithMsg "Must be $pp + 288 <= $p for $lvl" 9
  ;; 
  3) # 256MiB
    lvl="KOBOeReader"
    [ $((p-pp)) -lt 512 ] && \
      exitWithMsg "Must be $pp + 512 <= $p for $lvl" 10
  ;;
  4) # 32MiB
    n=5
    lvl="koboswap"
    [ $((p-pp)) -lt 63 ] && \
      exitWithMsg "Must be $pp + 63 <= $p for $lvl" 11
  ;;
  6) lvl="kobohome" ;;
  *) lvl="" ;;
  esac
  echo $n $pp $p | awk -v "lvl=$lvl" '
    {printf "%d: %7.1fMiB %s\n", $1, ($3 - $2)/2.0, lvl}'
  pp=$p
done
if [ $n -lt 3 ] ; then
  exitWithMsg '***ERROR too few partitions.' 12
fi

fdiskBatch () {
  printf \\n
  pp=''
  n=0
  for p in $pt '' ; do
    if [ -z "$pp" ] ; then
      printf '\no\n'
      pp=$p
      continue
    fi
    if [ -z "$p" ] ; then
      printf 'u\np\nu\np\n%s\n' $1
      break
    fi
    n=$((n+1))
    [ $p -gt $pz ] && p=$pz
    case $n in
    1|2|3)
      printf 'n\np\n%d\n%d\n%d\n' $n $pp $((p-1))
      [ $n -eq 3 ] && printf 't\n3\n%s\n' c # FAT32(LBA)
    ;;
    4)
      printf 'n\ne\n%d\n%d\n' $pp $((pz-1))
      n=5
      printf 'n\n%d\n%d\nt\n5\n82\n' $pp $((p-1))
    ;;
    *)
      printf 'n\n%d\n%d\n' $pp $((p-1))
    ;;
    esac
    pp=$p
  done | fdisk -H 32 -S 32 $vol | sed "$sedfdisk"
}

printf  '\n ==== fdisk SIMULATION ====\n'
fdiskBatch q

if [ YES != "$1" ] ; then
  printf '\nOK? [N/YES(type YES)] '
  read YN
  case $YN in
  YES) echo "$YN" ;;
  *) exitWithMsg 'Canceled.' 0 ;;
  esac
fi

date '+---- %H:%M:%S ----'
printf '20 99 0 0\n530 0 0 99\n' > $wnkCyc
echo "Copy current META data (SN etc.)"
echo "Invoke: dd if=/dev/mmcblk0 of=$vol bs=512K count=20"
dd if=/dev/mmcblk0 of=$vol bs=512K count=20
sync; sync; sync; 

echo "Clear partition table"
echo "Invoke: dd if=/dev/zero of=$vol bs=2 seek=223 count=32"
dd if=/dev/zero of=$vol bs=2 seek=223 count=32
sync; sync; sync; 

echo "Partitioning"
fdiskBatch w >/dev/null
sync; sync; sync; 
{
hdparm -z ./$vol
sync; sync; sync; 
hdparm -z ./$vol
sync; sync; sync; 
} >/dev/null 2>&1
mkDevices

fdisk -l $vol ||
  exitWithMsg "fdisk fails partitioning" 13
echo 'Device files:'
ls -l "$vol"*
n=1
while [ $n -le $ptn ] ; do
  [ -e "${vol}p$n" ] || exitWithMsg "fdisk fails partitioning" 14
  n=$((n+1))
done

mkdir -m 000 src
mount /dev/mmcblk0p2 -t ext4 -o ro,noatime,nodiratime src

exitUnmountWithMsg () {
  for mtpt in */ ; do
    umount ${mtpt%/}
  done >/dev/null 2>&1
  sync; sync; sync
  for mtpt in */ ; do
    umount ${mtpt%/}
  done >/dev/null 2>&1
  sync; sync; sync
  exitWithMsg "$1" "$2"
}

PRODUCT=$(/bin/kobo_config.sh)
[ "$PRODUCT" != trilogy ] && PREFIX="$PRODUCT"-
PLATFORM=freescale
[ $(dd if=/dev/mmcblk0 bs=512 skip=1024 count=1 2>/dev/null |
      grep -c "HW CONFIG") == 1 ] && PLATFORM=ntx508

UBOOT="src/upgrade/$PLATFORM/u-boot.bin"
if [ "$PLATFORM" = ntx508 ] ; then
  PCB=$(ntx_hwconfig -s -p /dev/mmcblk0 PCB)
  RAM=$(ntx_hwconfig -s -p /dev/mmcblk0 RAMType)
  NEW_UBOOT="src/upgrade/$PLATFORM/u-boot_mddr_256-$PCB-$RAM.bin"
  [ -e "$NEW_UBOOT" ] && UBOOT="$NEW_UBOOT"
fi
[ -e "$UBOOT" ] || exitUnmountWithMsg "NO U-Boot: $UBOOT" 15

echo "Install: U-Boot"
echo "Invoke: dd if=$UBOOT of=$vol bs=1K seek=1 skip=1"
dd if=$UBOOT of=$vol bs=1K seek=1 skip=1 ||
  exitUnmountWithMsg "Fail:" 16
sync; sync; sync

KERNEL="src/upgrade/$PLATFORM/uImage"
[ -e "$KERNEL" ] || exitUnmountWithMsg "NO kernel: $KERNEL" 17

echo "Install: kernel"
echo "Invoke: dd if=$KERNEL of=$vol bs=512 seek=2048"
dd if=$KERNEL of=$vol bs=512 seek=2048 ||
  exitUnmountWithMsg "Fail:" 18
sync; sync; sync

date '+---- %H:%M:%S ----'
printf '20 99 0 0\n330 0 0 99\n' > $wnkCyc
echo "Formatting partitions..."
mkfs="./src/sbin/mkfs.ext4"
[ -x "$mkfs" ] || exitUnmountWithMsg "***ERROR NO: $mkfs" 19
echo "Invoke: $mkfs -L rootfs -m 0 ${vol}p1"
$mkfs -L rootfs -m 0 "$vol"p1 ||
  exitUnmountWithMsg "***ERROR $mkfs ${vol}p1" 20
sync; sync; sync
echo "Invoke: $mkfs -L recoveryfs -m 0 ${vol}p2"
$mkfs -L recoveryfs -m 0 "$vol"p2 ||
  exitUnmountWithMsg "***ERROR $mkfs ${vol}p2" 21
sync; sync; sync
echo "Invoke: mkfs.vfat -n KOBOeReader ${vol}p3"
mkfs.vfat -n KOBOeReader "$vol"p3 ||
  exitUnmountWithMsg "***ERROR mkfs.vfat ${vol}p3" 22
sync; sync; sync
if [ -e "$vol"p5 ] ; then
  echo "Invoke: mkswap -L koboswap ${vol}p5"
  mkswap -L koboswap "$vol"p5 ||
    exitUnmountWithMsg "***ERROR mkswap ${vol}p5" 23
  sync; sync; sync
else
  echo "NO PARTITON: ${vol}p5 ???"
fi
if [ -e "$vol"p6 ] ; then
  echo "Invoke: $mkfs -L kobohome -m 0 ${vol}p6"
  $mkfs -L kobohome -m 0 "$vol"p6 ||
    exitUnmountWithMsg "***ERROR $mkfs ${vol}p6" 24
  sync; sync; sync
fi

date '+---- %H:%M:%S ----'
printf '20 99 0 0\n130 0 0 99\n' > $wnkCyc
echo "Clone: recoveryfs"
mkdir -m 000 dst
mtopt="norelatime,noatime,nodiratime"
mount -t ext4 -o $mtopt "$vol"p2 dst ||
   exitUnmountWithMsg "***ERROR mounting ${vol}p2" 25
for d in src/.* src/* ; do
  case "${d#*/}" in
  . | .. | 'lost+found') continue ;;
  esac
  [ -e "$d" ] || continue
  printf '%s ' "${d#*/}"
  cp -a "$d" dst/
  sync; sync; sync
done
printf \\n
umount dst ||
   exitUnmountWithMsg "***ERROR unmounting ${vol}p2" 26
sync; sync; sync

date '+---- %H:%M:%S ----'
printf '20 99 0 0\n60 0 0 99\n' > $wnkCyc
fstgz=src/upgrade/fs.tgz
[ -e $fstgz ] ||
   exitUnmountWithMsg "***ERROR No $fstgz" 27
mount -t ext4 -o $mtopt "$vol"p1 dst ||
   exitUnmountWithMsg "***ERROR mounting ${vol}p1" 28
echo "Expanding factory image rootfs. Take a while..."
tar zxf $fstgz -C dst ||
   exitUnmountWithMsg "***ERROR " 29
sync; sync; sync
umount dst ||
   exitUnmountWithMsg "***ERROR unmounting ${vol}p1" 30
sync; sync; sync

dbtgz=src/upgrade/db.tgz
[ -e $dbtgz ] ||
   exitUnmountWithMsg "***ERROR No $dbtgz" 31
mount "$vol"p3 dst ||
   exitUnmountWithMsg "***ERROR mounting ${vol}p3" 32
echo "Expanding factory image KOBOeReader"
tar zxf $dbtgz -C dst ||
   exitUnmountWithMsg "***ERROR " 33
sync; sync; sync
umount dst ||
   exitUnmountWithMsg "***ERROR unmounting ${vol}p3" 34
sync; sync; sync
rmdir dst ||
   exitUnmountWithMsg "***ERROR nonempty dst" 35

ubmmc="src/etc/u-boot/$PLATFORM/u-boot.mmc"
[ -e $ubmmc ] ||
   exitUnmountWithMsg "***ERROR No $ubmmc" 36
echo "Invoke: dd if=$ubmmc of=$vol bs=128K seek=6 count=1"
dd if=$ubmmc of=$vol bs=128K seek=6 count=1 ||
  exitUnmountWithMsg "Fail:" 37
sync; sync; sync

umount src ||
   exitUnmountWithMsg "***ERROR unmounting /dev/mmcblk0p2" 38
sync; sync; sync
rmdir src ||
   exitUnmountWithMsg "***ERROR nonempty src" 39

sync; sync; sync
sleep 1
sync; sync; sync
sleep 1
sync; sync; sync
sleep 1

exitUnmountWithMsg "|+++ OKOKOK SUCCESSFULLY BACKUPED +++|" 0

exit


