#!/bin/sh
#(c) Copyright Barry Kauler 22 Dec 2013, bkhome.org
#Licence: GPL3 (/usr/share/doc/legal)
#for Quirky 6.x, take a snapshot of the entire system, with exclusions.
#131221 first version. 131224 implemented recovery.
#131225 run in text-mode, recovery only.
#131225 /sbin/init (in ramdisk) can call this script with passed-param of required rollback date.
#131225 need to prefix target path when run snapshot-manager from ramdisk. another passed-param.
#131226 test if /lost+found exists before excluding.
#131226 gui recovery, this script may change, so run a copy. fix snapshot-mark-delete.
#131226 include /boot in snapshot. restore vmlinuz in 1st partition.
#131226 exclude sockets/pipes/fifos from snapshot.
#131227 use cmptree to delete files after recovery.
#131229 cmptree: can't just compare with ${PRE}/ as that will delete /dev, /tmp etc.
#140103 fix for "p" in mmcklb0p1.
#140103 if there is only one snapshot, that have just recovered from, do not delete it.
#140104 fix copy symlink/file/dir clashes.
#140105 run urxvt instead of rxvt, as latter not work if 'misc' dir missing.
#140105 some error logging.
#140106 $FIRSTSNAP is actually the older date, use that in the popup msg.
#140106 when cp-fix-code relocates a folder, cmptree then deletes it. fixed.
#140112 140106 cp-fix-code needed another test.
#140112 140103 was not completely implemented.
#140121 want a comment for each snapshot. new file /audit/snapshot-comments
#140124 /archive no longer exists.
#140125 fixed recovery failure.
#140201 exclude /file from snapshots. 140202
#140206 after recovery: /audit/deposed/<pkg>DEPOSED.sfs, pkg not in /root/.packages/user-installed-packages, then delete.
#140212 want to call from /usr/sbin/delayedrun, take a snapshot at 1st bootup. passed-param = take ['comment']   140213
#151007 clarify in help window that /file not saved.
#151117 guess_fstype broken, reported 'unknown' for 'vfat' partition. (see also 5create-service-packs)
#151206 exclude /initrd from snapshot.
#151210 fix for frugal installation.

mkdir -p /tmp/audit
#131226 run copy of script...
if [ ! $1 ];then #there will be $1 if run from ramdisk.
 if [ "$(echo "$0" | grep '/tmp/audit')" = "" ];then
  cp -a -f /usr/sbin/snapshot-manager /tmp/audit/snapshot-manager
  exec /tmp/audit/snapshot-manager
 fi
fi

CHOSENDATE=""; PRE=""; TAKE=0; DEFAULTCOMMENT=""
if [ $1 ];then
 if [ "$1" = "take" ];then #140212
  TAKE=1
  [ $2 ] && DEFAULTCOMMENT="$2"
 else
  [ $1 ] && PRE="$1"
  [ $2 ] && CHOSENDATE="$2"
 fi
fi

export TEXTDOMAIN=snapshot-manager
export OUTPUT_CHARSET=UTF-8

. ${PRE}/etc/rc.d/PUPSTATE #want PDEV1
mkdir -p ${PRE}/audit/snapshots
touch ${PRE}/audit/snapshot-comments #140121
touch ${PRE}/audit/audit-specs
. ${PRE}/audit/audit-specs
[ ! "$SNAPSHOT_LIMIT" ] && SNAPSHOT_LIMIT=5
[ ! "$SNAPSHOT_ARCHTYPE" ] && SNAPSHOT_ARCHTYPE='sfs'

case $SNAPSHOT_ARCHTYPE in
 cpio)  EXT='cpio' ;;
 usfs)  EXT='usfs' ; COMPR='-noI -noD -noF -noX' ;; #no compression.
 sfs)   EXT='sfs' ; COMPR='' ;;
esac

CR='
'

#151210 detect frugal install...
if [ "$(cat /proc/mounts | grep '^layerfs / ')" != "" ];then
 if [ -d /initrd/q_rw ];then
  INSTALL_MODE='frugal'
  #cop out for now...
  msg1="$(gettext 'Snapshot Manager: abort')"
  msg2="$(gettext 'The Snapshot Manager is designed for a <b>Full</b> installation. You are currently running in a <b>Frugal</b> installation.')"
  msg3="$(gettext 'Note: It is easy to take snapshots in a Frugal installation, by making backup copies of the <b>s.sfs</b> file (the saved session).')"
  popup "background=#FF8080 terminate=ok level=top process=wait|<big><b>${msg1}</b></big>${CR}${CR}${msg2}${CR}${CR}${msg3}"
  exit
 fi
fi

cd ${PRE}/audit/snapshots

limitsnaps_func() {
DELTASNAPS="$(find ./ -mindepth 1 -maxdepth 1 -type f -name '[0-9]*.xdelta' | sed -e 's%./%%' -e 's%.xdelta$%%' | sort -n -r)" #sort in reverse, need to go back in time down list.
xSNAPSHOT_LIMIT=`expr $SNAPSHOT_LIMIT - 1`
NUMDELTAS=`echo "$DELTASNAPS" | wc -l`
if [ $NUMDELTAS -gt $xSNAPSHOT_LIMIT ];then
 NUMTAIL=`expr $NUMDELTAS - $xSNAPSHOT_LIMIT`
 rm -f $(echo "$DELTASNAPS" | tail -n ${NUMTAIL} | sed -e 's%$%.xdelta%' | tr '\n' ' ')
fi
}

###131225 text-mode, recovery only###
if [ ! $DISPLAY ];then
 [ $TAKE -eq 1 ] && exit 8 #140212 precaution.
 echo -en "\\033[1;35m" #140109 purple. 34=blue, 33=yellow, 32=green, 31=red, 35=purple, 36=aquablue, 38=black.
 echo "$(gettext 'Quirky Snapshot Manager: console recovery mode')"
 echo -en "\\033[0;39m"
 DATELIST=""
 FIRSTSNAP="$(find ./ -mindepth 1 -maxdepth 1 -type f -name "[0-9]*.${EXT}" | sed -e 's%./%%' -e "s%.${EXT}$%%" | sort -n | head -n 1)" #there should only be one of these.
 DELTASNAPS="$(find ./ -mindepth 1 -maxdepth 1 -type f -name '[0-9]*.xdelta' | sed -e 's%./%%' -e 's%.xdelta$%%' | sort -n -r)" #sort in reverse, need to go back in time down list.
 if [ "$FIRSTSNAP" ];then
  DATELIST="$FIRSTSNAP"
  if [ "$DELTASNAPS" ];then
   DATELIST="${DATELIST}
$(echo "$DELTASNAPS" | cut -f 2 -d '_')" #2nd field has the older date.
  fi
  xDATELIST="$(echo "$DATELIST" | sed -r -e 's%([0-9][0-9][0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])%\1-\2-\3 \4:\5%')" #reformat 201312221645 to 2013-12-22 16:45
 else
  echo "$(gettext 'There are no snapshots. Aborting.')"
  exit 1
 fi
 #131225 /sbin/init can call this script with passed-param of required rollback date...
 if [ "$CHOSENDATE" ];then
  OLDESTDATE="$CHOSENDATE"
 else
  echo "$(gettext 'These are snapshots of the system partition, enabling rollback')"
  echo "$(gettext 'of your entire Quirky installation to an earlier date:')"
  echo
  CNT=1
  for ADATE in `echo -n "$DATELIST" | tr '\n' ' '`
  do
   xADATE="$(echo "$ADATE" | sed -r -e 's%([0-9][0-9][0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])%\1-\2-\3 \4:\5%')" #reformat 201312221645 to 2013-12-22 16:45
   echo "${CNT} ${xADATE}"
   CNT=`expr $CNT + 1`
  done
  echo "${CNT} $(gettext 'Abort recovery')"
  echo -n "$(gettext 'Type a number from left column (then press ENTER key):') "
  read numof
  [ "$numof" = "$CNT" ] && exit 0 #abort.
  OLDESTDATE="$(echo "$DATELIST" | head -n ${numof} | tail -n 1)" #ex: 201312240052
 fi
 
 #now recover...
 MARKDONE=0
 echo "${FIRSTSNAP}.${EXT}" > /tmp/audit/snapshot-mark-delete #as going to roll back, mark later snapshots for deletion.
 [ ! "$DELTASNAPS" ] && AOLD="$FIRSTSNAP"
 if [ "$OLDESTDATE" != "$FIRSTSNAP" ];then
  for ADELTA in $DELTASNAPS
  do
   echo "${ADELTA}.xdelta" >> /tmp/audit/snapshot-mark-delete
   AOLD="$(echo -n "$ADELTA" | cut -f 2 -d '_')"
   ANEW="$(echo -n "$ADELTA" | cut -f 1 -d '_')"
   [ "$AOLD" = "$OLDESTDATE" ] && MARKDONE=1
   xAOLD="$(echo -n "$AOLD" | sed -r -e 's%([0-9][0-9][0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])%\1-\2-\3 \4:\5%')"
   echo "$(gettext 'Reconstituting snapshot:') ${xAOLD}. $(gettext 'Please wait...')"
   #format: xdelta3 -d -s "$SOURCEFILE_OLD" "$SOURCEFILE_DELTA" "$SOURCEFILE_NEW"
   echo "xdelta3 -d -s ${ANEW}.${EXT} ${ADELTA}.xdelta ${AOLD}.${EXT}" >> /tmp/audit/recover-xdelta-operations
   xdelta3 -d -s ${ANEW}.${EXT} ${ADELTA}.xdelta ${AOLD}.${EXT}
   sync
   [ "$ANEW" != "$FIRSTSNAP" ] && rm -f ${ANEW}.${EXT}
   [ $MARKDONE -eq 1 ] && break
  done
 else
  #140125 want to recover the last snapshot.
  if [ "$DELTASNAPS" ];then
   AOLD="$FIRSTSNAP"
   #need to reconstitute a sfs for previous snapshot...
   PREVDATE="`echo "$DELTASNAPS" | head -n 1 | cut -f 2 -d '_'`"
   echo "xdelta3 -d -s ${FIRSTSNAP}.${EXT} ${FIRSTSNAP}_${PREVDATE}.xdelta ${PREVDATE}.${EXT}" >> /tmp/audit/recover-xdelta-operations
   xdelta3 -d -s ${FIRSTSNAP}.${EXT} ${FIRSTSNAP}_${PREVDATE}.xdelta ${PREVDATE}.${EXT}
   sync
   echo "${FIRSTSNAP}_${PREVDATE}.xdelta" >> /tmp/audit/snapshot-mark-delete
  fi
 fi
 
 #140105 bug report...
 if [ ! -f ${AOLD}.${EXT} ];then
  echo "Error: Have not created \$AOLD.\$EXT=${AOLD}.${EXT}" > recover-bug-report
  echo "FIRSTSNAP=${FIRSTSNAP} OLDESTDATE=${OLDESTDATE}
DELTASNAPS=${DELTASNAPS}
DATELIST=${DATELIST}

Files in /audit/snapshots:"  >> recover-bug-report
  ls -1 >> recover-bug-report
  echo "
Contents of /tmp/audit/snapshot-mark-delete:" >> recover-bug-report 
  cat /tmp/audit/snapshot-mark-delete >> recover-bug-report
  echo "
Contents of /tmp/audit/recover-xdelta-operations:" >> recover-bug-report
  cat /tmp/audit/recover-xdelta-operations >> recover-bug-report
  echo -n -e "\\033[1;31m" #red.
  echo -n "ERROR: logged to /audit/snapshots/recover-bug-report. Aborting recovery."
  echo -e "\\033[0;39m"
  sync
  sleep 10
  exit 1
 fi
 
 #got code out of /usr/local/petget/installpkg.sh...
 #the 'cp' utility needs fixes for dir symlinks...
 #mount ${AOLD}.${EXT}, copy contents, then umount...
 echo "$(gettext 'Restoring system from snapshot, please wait...')"
 mkdir -p /tmp/audit/snapshot-mntpt
 busybox mount -t squashfs -o loop,ro ${AOLD}.${EXT} /tmp/audit/snapshot-mntpt
 DIRECTSAVEPATH='/tmp/audit/snapshot-mntpt'
 cp -a -f --remove-destination ${DIRECTSAVEPATH}/* ${PRE}/  2> /tmp/audit/install-cp-errlog
 sync
 #can have a problem if want to replace a folder with a symlink. for example, got this error:
 # cp: cannot overwrite directory '/usr/share/mplayer/skins' with non-directory
 #3builddistro has this fix... which is a vice-versa situation...
 #firstly, the vice-versa, source is a directory, target is a symlink...
 CNT=0
 #140104 fixes...
 echo -n '' > /tmp/audit/install-cp-relocations #140106
 while [ -s /tmp/audit/install-cp-errlog ];do
  echo -n '' > /tmp/audit/install-cp-errlog2
  echo -n '' > /tmp/audit/install-cp-errlog3
  cat /tmp/audit/install-cp-errlog | grep 'cannot overwrite non-directory' | grep 'with directory' | tr '[`‘’]' "'" | cut -f 2 -d "'" |
  while read ONEDIRSYMLINK #ex: /usr/share/mplayer/skins
  do
   if [ -h "${ONEDIRSYMLINK}" ];then #source is a directory, target is a symlink...
    zALINK="$(realpath "${ONEDIRSYMLINK}" 2>/dev/null)" #140112. note, got "/old_root/run: no such file or directory", suppress error, then test $zALINK has content...
    [ "$zALINK" ] && echo "$zALINK" >> /tmp/audit/install-cp-relocations #140112
    #adding that extra trailing / does the trick...
    cp -a -f --remove-destination ${DIRECTSAVEPATH}"${ONEDIRSYMLINK}"/* "${ONEDIRSYMLINK}"/ 2>> /tmp/audit/install-cp-errlog2
   else #source is a directory, target is a file...
    rm -f "${ONEDIRSYMLINK}" #delete the file!
    DIRPATH="$(dirname "${ONEDIRSYMLINK}")"
    cp -a -f ${DIRECTSAVEPATH}"${ONEDIRSYMLINK}" "${DIRPATH}"/ 2>> /tmp/audit/install-cp-errlog2 #copy directory (and contents).
   fi
  done
  #secondly, which is our mplayer example, source is a symlink, target is a folder...
  cat /tmp/audit/install-cp-errlog | grep 'cannot overwrite directory' | grep 'with non-directory' | tr '[`‘’]' "'" | cut -f 2 -d "'" |
  while read ONEDIRSYMLINK #ex: /usr/share/mplayer/skins
  do
   #difficult situation, whether to impose the symlink of package, or not. if not...
   #cp -a -f --remove-destination ${DIRECTSAVEPATH}"${ONEDIRSYMLINK}"/* "${ONEDIRSYMLINK}"/ 2> /tmp/audit/install-cp-errlog3
   #or, if we have chosen to follow link...
   DIRPATH="$(dirname "${ONEDIRSYMLINK}")"
   if [ -h ${DIRECTSAVEPATH}"${ONEDIRSYMLINK}" ];then #source is a symlink, trying to overwrite a directory...
    ALINK="$(readlink ${DIRECTSAVEPATH}"${ONEDIRSYMLINK}")"
    if [ "${ALINK:0:1}" = "/" ];then #test 1st char
     xALINK="$ALINK" #absolute
    else
     xALINK="${DIRPATH}/${ALINK}"
    fi
    if [ -d "$xALINK" ];then
     zALINK="$(realpath "$xALINK")" #140106
     echo "$zALINK" >> /tmp/audit/install-cp-relocations #140106
     cp -a -f --remove-destination "${ONEDIRSYMLINK}"/* "$zALINK"/ 2>> /tmp/audit/install-cp-errlog3 #relocates target files.
     rm -rf "${ONEDIRSYMLINK}"
     cp -a -f ${DIRECTSAVEPATH}"${ONEDIRSYMLINK}" "${DIRPATH}"/ #creates symlink only.
    fi
   else #source is a file, trying to overwrite a directory...
    rm -rf "${ONEDIRSYMLINK}" #deleting directory!!!
    cp -a -f ${DIRECTSAVEPATH}"${ONEDIRSYMLINK}" "${DIRPATH}"/ #creates file only.
   fi
  done
  cat /tmp/audit/install-cp-errlog2 >> /tmp/audit/install-cp-errlog3
  cat /tmp/audit/install-cp-errlog3 > /tmp/audit/install-cp-errlog
  sync
  CNT=`expr $CNT + 1`
  [ $CNT -gt 10 ] && break #something wrong, get out.
 done
 
 #131227 find files to be deleted...
 echo "$(gettext 'Finding files/dirs that need to be deleted in system partition...')"
 #131229 can't just compare with ${PRE}/ as that will delete /dev, /tmp etc...
 cmptree /tmp/audit/snapshot-mntpt/bin ${PRE}/bin > /tmp/audit/cmptree-recover
 cmptree /tmp/audit/snapshot-mntpt/sbin ${PRE}/sbin >> /tmp/audit/cmptree-recover
 cmptree /tmp/audit/snapshot-mntpt/lib ${PRE}/lib >> /tmp/audit/cmptree-recover
 [ -d /tmp/audit/snapshot-mntpt/opt ] && cmptree /tmp/audit/snapshot-mntpt/opt ${PRE}/opt >> /tmp/audit/cmptree-recover
 cmptree /tmp/audit/snapshot-mntpt/etc ${PRE}/etc >> /tmp/audit/cmptree-recover
 cmptree /tmp/audit/snapshot-mntpt/usr ${PRE}/usr >> /tmp/audit/cmptree-recover
 cmptree /tmp/audit/snapshot-mntpt/boot ${PRE}/boot >> /tmp/audit/cmptree-recover
 cmptree /tmp/audit/snapshot-mntpt/root ${PRE}/root >> /tmp/audit/cmptree-recover
 sync
 #files to be deleted... (see code in create-service-packs)
 echo " now deleting..."
 grep '^/tmp/audit/snapshot-mntpt/.*does not exist.$' /tmp/audit/cmptree-recover > /tmp/audit/cmptree-recover-removed0
 grep -f /tmp/audit/install-cp-relocations -v /tmp/audit/cmptree-recover-removed0 > /tmp/audit/cmptree-recover-removed #140106
 sed -e 's%^/tmp/audit/snapshot-mntpt%%' /tmp/audit/cmptree-recover-removed | cut -f 1 -d ' ' |
 while read ADEL
 do
  [ ! ${PRE}"$ADEL" ] && continue
  #echo "  deleting ${ADEL}"
  if [ -d ${PRE}"$ADEL" ];then
   rm -rf ${PRE}"$ADEL"
  else
   rm -f ${PRE}"$ADEL"
  fi
 done
 sync
 
 busybox umount /tmp/audit/snapshot-mntpt
 
 #cleanup files that may have been grabbed in the snapshots... 131226 pipes/sockets/fifos now excluded from snapshot.
 #rm -f ${PRE}/var/log/X*
 #rm -f ${PRE}/var/lock/LCK*
 #rm -rf ${PRE}/root/tmp 2>/dev/null
 #rm -rf ${PRE}/root/.thumbnails/* 2>/dev/null
 #rm -f $(find ${PRE}/var -type s -o -type p | tr '\n' ' ') 2>/dev/null #find pipes and sockets.
 #rm -f $(find ${PRE}/root -type s -o -type p | tr '\n' ' ') 2>/dev/null #find pipes and sockets.
 
 #140112 forgot this (see same code when recover without reboot)...
 #delete forward-time, leave ${AOLD}.${EXT} and any older delta-files...
 #140103 if there is only one snapshot, that have just recovered from, do not delete it...
 CNTDELTA=`find ${PRE}/audit/snapshots -mindepth 1 -maxdepth 1 -type f -name '*.xdelta' | wc -l`
 CNTSNAP=`find ${PRE}/audit/snapshots -mindepth 1 -maxdepth 1 -type f -name "*.${EXT}" 2>/dev/null | wc -l`
 if [ $CNTSNAP -eq 1 -a $CNTDELTA -eq 0 ];then
  echo "Have recovered from snapshot, but not deleting it."
 else
  for ADEL in `cat /tmp/audit/snapshot-mark-delete | tr '\n' ' '`
  do
   rm -f ${ADEL} #note, current-dir is ${PRE}/audit/snapshots, so only specify filename.
  done
 fi
 sync
 
 #140206 remove prior installed pkgs that have been wiped out by recovery...
 if [ -s ${PRE}/root/.packages/user-installed-packages ];then
  cut -f 1 -d '|' ${PRE}/root/.packages/user-installed-packages > /tmp/snapshot-recover-user-pkgs
  for ADEPSFS in `find ${PRE}/audit/deposed -maxdepth 1 -type f -name '*DEPOSED.sfs' | tr '\n' ' '`
  do
   ADEPBASE="`basename ${ADEPSFS} DEPOSED.sfs`"
   [ "$(grep -x "${ADEPBASE}" /tmp/snapshot-recover-user-pkgs)" = "" ] && rm -f ${ADEPSFS}
  done
 fi
 
 #131226 update vmlinuz and logo.16 in 1st partition, if full-drive installation... (see also create-service-packs)
 #140103 fix for "p"...
 FLAGP1=0
 PPARTNUM="$(echo -n "$PDEV1" | grep -o -E '[a-z][0-9]$|[a-z][0-9][0-9]$' | cut -c 2-)" #ex: 2
 PDRIVE="$(echo -n "$PDEV1" | sed -e "s%${PPARTNUM}$%%" -e 's%p$%%')" #ex: sdb
 P=''
 [ "$(echo -n "$PDEV1" | grep '[0-9]p[0-9]')" != "" ] && P='p' #ex: mmcblk0p1
 if [ "$PPARTNUM" = "2" ];then
  #PART1FS="$(guess_fstype /dev/${PDRIVE}${P}1)"
  PART1FS="$(busybox blkid /dev/${PDRIVE}${P}1 | grep -o ' TYPE=.*' | cut -f 2 -d '"')" #151117
  if [ "$PART1FS" = "vfat" ];then
   P1MNTPT="$(busybox mount | grep "^/dev/${PDRIVE}${P}1 " | tr -s ' ' | cut -f 3 -d ' ')"
   if [ ! "$P1MNTPT" ];then
    mkdir -p /mnt/${PDRIVE}${P}1
    busybox mount -t ${PART1FS} /dev/${PDRIVE}${P}1 /mnt/${PDRIVE}${P}1
    if [ $? -eq 0 ];then
     P1MNTPT="/mnt/${PDRIVE}${P}1"
     FLAGP1=1
    fi
   fi
   if [ "$P1MNTPT" ];then
    if [ -f ${P1MNTPT}/logo.16 ];then
     echo "Copying logo.16 and vmlinuz into first partition..."
     cp -a -f ${PRE}/boot/syslinux/logo.16 ${P1MNTPT}/
     cp -a -f ${PRE}/boot/vmlinuz ${P1MNTPT}/
     sync
    fi
    [ $FLAGP1 -eq 1 ] && busybox umount ${P1MNTPT}
   fi
  fi
 fi

 xAOLD="$(echo -n "$AOLD" | sed -r -e 's%([0-9][0-9][0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])%\1-\2-\3 \4:\5%')"
 echo "$(gettext 'Finished! Your installation of Quirky has been rolled back to:') ${xAOLD}"

 exit 0
fi ###END text mode, recovery only###

echo -e '1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n15\n20' > /tmp/audit/snapshot-combo2-items

#maybe need to reduce max allowed number of snapshots...
SIZEM=`du -m /audit/snapshots | cut -f 1` #space used by snapshots.
#reduce number-snapshots-limit... 151210 fix for frugal...
TOTALM=`df -m / | grep -E '^/dev|^layerfs' | tr -s ' ' | cut -f 2 -d ' '`
USEDM=`df -m / | grep -E '^/dev|^layerfs' | tr -s ' ' | cut -f 3 -d ' '`
xUSEDM=`expr $USEDM - $SIZEM`
xUSEDP=`expr $xUSEDM \* 100 \/ $TOTALM` #percent-free without snapshots
if [ $xUSEDP -gt 75 ];then
 #do not allow any snapshots.
 rm -f ./*.xdelta ./*.${EXT} 2>/dev/null
 echo -e '0' > /tmp/audit/snapshot-combo2-items
 SNAPSHOT_LIMIT=0
elif [ $xUSEDP -gt 70 ];then
 #only allow one snapshot...
 rm -f *.xdelta 2>/dev/null
 echo -e '1\n2' > /tmp/audit/snapshot-combo2-items
 SNAPSHOT_LIMIT=1
elif [ $xUSEDP -gt 60 ];then
 #allow max two snapshots...
 rm -f $(find ./ -mindepth 1 -maxdepth 1 -type f -name '[0-9]*.xdelta' 2>/dev/null | sort -n -r | tail -n +3 | tr '\n' ' ') 2>/dev/null
 echo -e '1\n2' > /tmp/audit/snapshot-combo2-items
 [ $SNAPSHOT_LIMIT -gt 2 -o $SNAPSHOT_LIMIT -eq 0 ] && SNAPSHOT_LIMIT=2
elif [ $xUSEDP -gt 55 ];then
 #allow max three snapshots...
 rm -f $(find ./ -mindepth 1 -maxdepth 1 -type f -name '[0-9]*.xdelta' 2>/dev/null | sort -n -r | tail -n +4 | tr '\n' ' ') 2>/dev/null
 echo -e '1\n2\n3' > /tmp/audit/snapshot-combo2-items
 [ $SNAPSHOT_LIMIT -gt 3 -o $SNAPSHOT_LIMIT -eq 0 ] && SNAPSHOT_LIMIT=3
fi
sed -i -e '/SNAPSHOT_LIMIT/d' /audit/audit-specs
echo "SNAPSHOT_LIMIT=${SNAPSHOT_LIMIT}" >> /audit/audit-specs

USEDP=`df -m / | grep -E '^/dev/|^layerfs' | tr -s ' ' | cut -f 5 -d ' ' | cut -f 1 -d '%'` #used percentage. 151210 fix frugal.
FREEP=`expr 100 - $USEDP`

HOMEPART="$(rdev | cut -f 1 -d ' ' | cut -f 3 -d '/')"
FIRSTSNAP="$(find ./ -mindepth 1 -maxdepth 1 -type f -name "[0-9]*.${EXT}" | sed -e 's%./%%' -e "s%.${EXT}$%%" | sort -n | head -n 1)" #there should only be one of these.
DELTASNAPS="$(find ./ -mindepth 1 -maxdepth 1 -type f -name '[0-9]*.xdelta' | sed -e 's%./%%' -e 's%.xdelta$%%' | sort -n -r)" #sort in reverse, need to go back in time down list.

if [ "$FIRSTSNAP" ];then
 DATELIST="$FIRSTSNAP"
 if [ "$DELTASNAPS" ];then
  DATELIST="${DATELIST}
$(echo "$DELTASNAPS" | cut -f 2 -d '_')" #2nd field has the older date.
 fi
 #140121 insert comments...
 echo -n "" > /tmp/audit/snapshot-manager-datelist
 echo -n "" > /tmp/audit/snapshot-comments2
 for ADATE in $DATELIST
 do
  ACOMMENT="`grep "^${ADATE}" /audit/snapshot-comments | cut -f 2- -d ' '`"
  xDATE="$(echo "$ADATE" | sed -r -e 's%([0-9][0-9][0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])%\1-\2-\3 \4:\5%')" #reformat 201312221645 to 2013-12-22 16:45
  echo "${xDATE} ${ACOMMENT}" >> /tmp/audit/snapshot-manager-datelist
  echo "${ADATE} ${ACOMMENT}" >> /tmp/audit/snapshot-comments2
 done
 mv -f /tmp/audit/snapshot-comments2 /audit/snapshot-comments #precaution, removed any invalid comments.
 #xDATELIST="$(echo "$DATELIST" | sed -r -e 's%([0-9][0-9][0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])%\1-\2-\3 \4:\5%')" #reformat 201312221645 to 2013-12-22 16:45
 #echo "$xDATELIST" > /tmp/audit/snapshot-manager-datelist
 RECOVERXML="   <text><label>$(gettext 'This is a list of previous snapshots. Choose one, and click the Recover button. Note that this is a one-way operation, and you will not be able to "go forward" afterward. Everything that has changed after the chosen snapshot will be lost.')</label></text>
   <hbox>
    <comboboxtext>
     <variable>COMBO1</variable>
     <input file>/tmp/audit/snapshot-manager-datelist</input>
    </comboboxtext>
    <button><label>$(gettext 'Recover')</label><action function=\"exit\">RECOVER</action></button>
   </hbox>"
else
 RECOVERXML="<text use-markup=\"true\"><label>\"<b>$(gettext 'No snapshots taken yet!')</b>\"</label></text>"
fi

if [ $SNAPSHOT_LIMIT -gt 0 ];then
 TAKEXML="   <text><label>$(gettext 'Click the button to take a snapshot of the system. Please be aware that this may take awhile, as it is going to record almost everything in partition') ${HOMEPART}</label></text>
   <hbox>
    <button><label>$(gettext 'Take snapshot')</label><action function=\"exit\">TAKESNAPSHOT</action></button>
   </hbox>"
else
 TAKEXML="<text use-markup=\"true\"><label>\"<b>$(gettext 'Insufficient free space in partition to take a snapshot!')</b>\"</label></text>"
fi

M_close="$(gettext 'Close')"
M_help1="<b><big>$(gettext 'Partition:') ${HOMEPART}</big></b>

$(gettext 'This partition is where Quirky is installed. A snapshot makes a copy of most of the directories, including:')
<i>/bin, /boot, /lib, /root, /run, /sbin, /usr, /var</i>
$(gettext 'Excluding:') <i>/audit, /dev, /file, /mnt, /proc, /sys, /tmp</i>

$(gettext '<b>Recovery</b> is the key word here: the Snapshot Manager is an emergency tool, enabling you to go back to a hopefully working system, in case the current system has gone wrong.')
$(gettext 'Software developers might find the Snapshot Manager to be a useful tool, as it is a way of getting rid of a lot of compiled and installed source packages -- take a snapshot before, then recover afterward.')

$(gettext '<b>Important:</b> Please be sure that the partition is no more than half-full, to allow sufficient working-space for creating the snapshots. As usage grows over 50%, the maximum allowed number of snapshots is automatically reduced.')

$(gettext '<b>Note 1:</b> The time taken to make a snapshot may be from several minutes upward, depending on the size of all the files in the partition. Recovery of older snapshots takes longer, as they are only kept as delta (difference) files, that need to be reconstituted in sequence.')
$(gettext '<b>Note 2:</b> The main window shows the storage-space of the snapshots, in directory /audit/snapshots. The latest snapshot is very large, whereas older snapshots are delta-files and smaller, so reducing the number-of-snapshots-limit does not proportionally reduce archive storage-usage')
$(gettext '<b>Note 3:</b> Directory /file is <i>not</i> saved, as this has personal files.')"
M_help2=""
export DLG_HELP1="<window resizable=\"false\" title=\"$(gettext 'Help: Snapshot Manager')\" icon-name=\"gtk-index\" window_position=\"1\"><vbox><text use-markup=\"true\"><label>\"${M_help1}\"</label><variable>DLG_HELP1</variable></text><hbox><button><label>${M_close}</label><action type=\"closewindow\">DLG_HELP1</action></button></hbox></vbox></window>"

M_w1="<span fgcolor='"'red'"'><b>$(gettext "Please close all other applications now")</b></span>" #need some funny stuff.

export SNAP1_DIALOG="<window title=\"$(gettext 'Quirky Snapshot Manager')\" icon-name=\"gtk-about\" window_position=\"1\">
 <vbox>
  <text><label>$(gettext 'The Quirky Snapshot Manager takes a snapshot of the entire system. Previous snapshots are retained, enabling recovery back to any earlier snapshot.')</label></text>
  <text use-markup=\"true\"><label>\"${M_w1}\"</label></text>
  <frame $(gettext 'Take Snapshot')>
   ${TAKEXML}
  </frame>
  <frame $(gettext 'Recover')>
   ${RECOVERXML}
  </frame>
  <frame $(gettext 'Manage')>
   <text use-markup=\"true\"><label>\"$(gettext 'Archival storage-space used:') <b>${SIZEM}MB</b>\"</label></text>
   <text><label>$(gettext 'Free space left in partition:') ${FREEP}%</label></text>
   <text><label>$(gettext 'To constrain processing time and storage-space, the maximum allowed number of snapshots is automatically limited. Set limit:')</label></text>
   <hbox>
   <comboboxtext>
    <variable>COMBO2</variable>
    <default>${SNAPSHOT_LIMIT}</default>
    <input file>/tmp/audit/snapshot-combo2-items</input>
   </comboboxtext>
   <button>
    <label>$(gettext 'Apply')</label>
    <action>sed -i -e '/SNAPSHOT_LIMIT/d' /audit/audit-specs</action>
    <action>echo SNAPSHOT_LIMIT=\$COMBO2 >> /audit/audit-specs</action>
    <action>pupmessage -bg yellow -fg black -title \"$(gettext 'Snapshot limit changed to:') \$COMBO2\" '$(gettext 'This sets the maximum number of snapshots that can be taken. The new setting has now taken effect. Note, the Snapshot Manager will automatically override this setting and reduce it, as used space in the system partition grows above 50%.')'</action>
   </button>
   </hbox>
  </frame>
  <hbox>
   <hbox><button cancel></button></hbox>
   <button><input file>/usr/local/lib/X11/mini-icons/mini-question.xpm</input><action type=\"launch\">DLG_HELP1</action></button>
  </hbox>
 </vbox>
 </window>"

if [ $TAKE -eq 1 ];then #140212
 EXIT="TAKESNAPSHOT"
 [ $SNAPSHOT_LIMIT -eq 0 ] && exit 9
 [ $SNAPSHOT_LIMIT -eq 1 ] && exit 9
else
 RETVARS="$(gtkdialog --program=SNAP1_DIALOG)"
 #ex: COMBO1="2013-12-22 20:39"
 #EXIT="RECOVER"
 echo "$RETVARS"
 eval "$RETVARS"
 sed -i -e '/SNAPSHOT_LIMIT/d' /audit/audit-specs
 echo "SNAPSHOT_LIMIT=${COMBO2}" >> /audit/audit-specs
 SNAPSHOT_LIMIT=${COMBO2}
fi

cd /audit/snapshots #have to do it again?

###take snapshot###
if [ "$EXIT" = "TAKESNAPSHOT" ];then
 DATE="$(date +%Y%m%d%H%M)"
 rm -f ${DATE}.${EXT} 2>/dev/null
 xDATE="$(echo -n "$DATE" | sed -r -e 's%([0-9][0-9][0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])%\1-\2-\3 \4:\5%')" #reformat 201312221645 to 2013-12-22 16:45

 #140121...
 if [ "$DEFAULTCOMMENT" = "" ];then #140212
  export SNAP9_DLG="<window title=\"$(gettext 'Quirky Snapshot Manager')\" icon-name=\"gtk-about\" window_position=\"1\">
 <vbox>
  <text use-markup=\"true\"><label>\"<b><big>$(gettext 'Snapshot date:') ${xDATE}</big></b>\"</label></text>
  <text><label>$(gettext 'You have chosen to take a snapshot of the entire Quirky installation.')</label></text>
  <frame $(gettext 'Optional comment')>
   <text><label>Enter a short comment for this snapshot:</label></text>
   <entry width_chars=\"32\" max-length=\"32\"><variable>SNAPCOMMENT</variable></entry>
  </frame>
  <hbox>
   <hbox><button cancel></button></hbox>
   <button><label>$(gettext 'Take snapshot')</label><action type=\"exit\">SNAPNOW</action></button>
  </hbox>
 </vbox>
 </window>"
  RETVARS2="$(gtkdialog --program=SNAP9_DLG)"
  eval "$RETVARS2"
  [ "$EXIT" != "SNAPNOW" ] && exit 7 #140212
 fi
 
 sed -i -e "/${DATE}/d" ${PRE}/audit/snapshot-comments
 echo "${DATE} ${SNAPCOMMENT}" > /tmp/audit/snapshot-comments3
 cat ${PRE}/audit/snapshot-comments >> /tmp/audit/snapshot-comments3
 mv -f /tmp/audit/snapshot-comments3 ${PRE}/audit/snapshot-comments

 yaf-splash -bg '#FB9003' -fg black -close never -fontsize large -text "$(gettext 'Taking a snapshot, please wait...')" &
 YAFPID1=$!
 if [ "$SNAPSHOT_ARCHTYPE" = "cpio" ];then
  find /bin /lib /root /run /sbin /tmp/var /tmp/run /usr -mindepth 1 -mount | grep -v '/tmp/var/local' | cpio -o -H newc > ${DATE}.cpio  # | gzip -2 > ${DATE}.cpio.gz
 else
  echo -e '/audit\n/dev\n/mnt\n/proc\n/root\n/run\n/sys\n/tmp\n/var\n/fsckme.flg' > /tmp/audit/rootfs-snapshot-exclusions1
  [ -d "/archive" ] && echo '/archive' >> /tmp/audit/rootfs-snapshot-exclusions1 #140124
  [ -d "/lost+found" ] && echo '/lost+found' >> /tmp/audit/rootfs-snapshot-exclusions1 #131226
  [ -d "/home" ] && echo '/home' >> /tmp/audit/rootfs-snapshot-exclusions1 #140201
  [ -d "/file" ] && echo '/file' >> /tmp/audit/rootfs-snapshot-exclusions1 #140201
  [ -d "/media" ] && echo '/media' >> /tmp/audit/rootfs-snapshot-exclusions1 #140202
  [ -d "/initrd" ] && echo '/initrd' >> /tmp/audit/rootfs-snapshot-exclusions1 #151206
  #mksquashfs / ${DATE}.usfs -ef /tmp/audit/rootfs-snapshot-exclusions1 -no-exports -noI -noD -noF -noX
  T_1="$(gettext 'Creating:')"
  urxvt -geometry 96x3+0+0 -bg orange -fg black -title "${T_1} /audit/snapshots/${DATE}.${EXT}" -e mksquashfs / ${DATE}.${EXT} -ef /tmp/audit/rootfs-snapshot-exclusions1 -no-exports ${COMPR} #-noI -noD -noF -noX
  sync
  #131226 exclude sockets/pipes/fifos from snapshot...
  echo '/root/.XLOADED' > /tmp/audit/rootfs-snapshot-exclusions4 #see /usr/bin/xwin.
  ROOTSPECIAL="$(find /root -type s -o -type p)" #find pipes and sockets.
  [ "$ROOTSPECIAL" ] && echo "$ROOTSPECIAL" >> /tmp/audit/rootfs-snapshot-exclusions4
  mksquashfs /root ${DATE}.${EXT} -ef /tmp/audit/rootfs-snapshot-exclusions4 -keep-as-directory -no-exports ${COMPR} #-noI -noD -noF -noX
  sync
  #/run and /var are symlinks into /tmp...
  echo '/tmp/var/local' > /tmp/audit/rootfs-snapshot-exclusions2
  VARSPECIAL="$(find /tmp/var -type s -o -type p)" #find pipes and sockets.
  [ "$VARSPECIAL" ] && echo "$VARSPECIAL" >> /tmp/audit/rootfs-snapshot-exclusions2
  mksquashfs /tmp/var ${DATE}.${EXT} -ef /tmp/audit/rootfs-snapshot-exclusions2 -keep-as-directory -no-exports ${COMPR} #-noI -noD -noF -noX
  sync
  echo '/tmp/run/zzzzzz' > /tmp/audit/rootfs-snapshot-exclusions3
  RUNSPECIAL="$(find /tmp/run -type s -o -type p)" #find pipes and sockets.
  [ "$RUNSPECIAL" ] && echo "$RUNSPECIAL" >> /tmp/audit/rootfs-snapshot-exclusions3
  mksquashfs /tmp/run ${DATE}.${EXT} -ef /tmp/audit/rootfs-snapshot-exclusions3 -keep-as-directory -no-exports ${COMPR} #-noI -noD -noF -noX
 fi
 sync
 pupkill $YAFPID1

 #131224 if there is a prior snapshot, create a delta-file and delete prior snapshot...
 if [ "$FIRSTSNAP" ];then
  #140106 $FIRSTSNAP is actually the older date, use that in the popup msg...
  xFIRSTSNAP="$(echo -n "$FIRSTSNAP" | sed -r -e 's%([0-9][0-9][0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])%\1-\2-\3 \4:\5%')" #reformat 201312221645 to 2013-12-22 16:45
  yaf-splash -bg '#FBF303' -fg black -close never -fontsize large -text "$(gettext 'Creating delta-file:') ${xFIRSTSNAP}. $(gettext 'Please wait...')" &
  YAFPID1=$!
  #xdelta3 -e -s "$SOURCEFILE_OLD" "$SOURCEFILE_NEW" "$SOURCEFILE_DELTA"
  echo "xdelta3 -e -s ${DATE}.${EXT} ${FIRSTSNAP}.${EXT} ${DATE}_${FIRSTSNAP}.xdelta" #see what is happening.
  xdelta3 -e -s ${DATE}.${EXT} ${FIRSTSNAP}.${EXT} ${DATE}_${FIRSTSNAP}.xdelta #going back in time!
  sync
  rm ${FIRSTSNAP}.${EXT}
  pupkill $YAFPID1
 fi
 
 [ "$DEFAULTCOMMENT" = "" ] && pupmessage -bg '#AAFB03' -fg black -title "$(gettext 'Snapshot:') ${xDATE}" "$(gettext "That's it, the snapshot has been taken!")" #' 140213
fi
###END take snapshot###

###Recover###
if [ "$EXIT" = "RECOVER" ];then
 MARKDONE=0
 echo "${FIRSTSNAP}.${EXT}" > /tmp/audit/snapshot-mark-delete #as going to roll back, mark later snapshots for deletion.
 [ ! "$DELTASNAPS" ] && AOLD="$FIRSTSNAP"
 GRN=160 #hex: a0
 #140121 comment added...
 #COMBO1 has the selected date, 2nd field of a .xdelta file, older date. ex: COMBO1="2013-12-24 00:52 <comment>"
 rDATE="$(echo -n "$COMBO1" | cut -f 1,2 -d ' ')"
 rCOMMENT="$(echo -n "$COMBO1" | cut -f 3- -d ' ')"
 OLDESTDATE="$(echo -n "$rDATE" | tr -d '[\- :]')" #ex: 201312240052
 COMMENTXML=""
 if [ "$rCOMMENT" ];then
  COMMENTXML="<text><label>$(gettext 'There was a comment lodged with this snapshot:')</label></text>
  <text use-markup=\"true\"><label>\"<b>${rCOMMENT}</b>\"</label></text>"
 fi
 
 #offer to reboot to do recovery...
 export SNAP2_DLG="<window title=\"$(gettext 'Quirky Snapshot Manager')\" icon-name=\"gtk-about\" window_position=\"1\">
 <vbox>
  <text use-markup=\"true\"><label>\"<b><big>$(gettext 'Recovery date:') ${rDATE}</big></b>\"</label></text>
  <text><label>$(gettext 'You have chosen to roll the installation of Quirky back to the snapshot taken on this date.')</label></text>
  ${COMMENTXML}
  <text><label>\" \"</label></text>
  <text><label>$(gettext 'You now have a choice, either to restore right now, or to reboot and restore before Quirky has started up. The latter is recommended if the restore operation will cause major changes to the current installation. If you want to "play safe", choose the Reboot option.')</label></text>
  <hbox>
   <hbox><button cancel></button></hbox>
   <button><label>$(gettext 'Reboot then restore')</label><action type=\"exit\">REBOOT</action></button>
   <button><label>$(gettext 'Restore now')</label><action type=\"exit\">RESTORE</action></button>
  </hbox>
 </vbox>
 </window>"
 RETVARS2="$(gtkdialog --program=SNAP2_DLG)"
 eval "$RETVARS2"
 if [ "$EXIT" = "REBOOT" ];then ###reboot system, see /sbin/init###
  echo -n "$OLDESTDATE" > /recover.flg
  exec wmreboot
 fi
 if [ "$EXIT" != "RESTORE" ];then
  limitsnaps_func
  exit
 fi
 
 if [ "$OLDESTDATE" != "$FIRSTSNAP" ];then
  for ADELTA in $DELTASNAPS
  do
   echo "${ADELTA}.xdelta" >> /tmp/audit/snapshot-mark-delete
   AOLD="$(echo -n "$ADELTA" | cut -f 2 -d '_')"
   ANEW="$(echo -n "$ADELTA" | cut -f 1 -d '_')"
   [ "$AOLD" = "$OLDESTDATE" ] && MARKDONE=1
   xAOLD="$(echo -n "$AOLD" | sed -r -e 's%([0-9][0-9][0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])%\1-\2-\3 \4:\5%')"
   COLR="#FB$(busybox printf %0x $GRN)03"
   yaf-splash -bg "$COLR" -fg black -close never -fontsize large -text "$(gettext 'Reconstituting snapshot:') ${xAOLD}. $(gettext 'Please wait...')" &
   YAFPID1=$!
   #format: xdelta3 -d -s "$SOURCEFILE_OLD" "$SOURCEFILE_DELTA" "$SOURCEFILE_NEW"
   xdelta3 -d -s ${ANEW}.${EXT} ${ADELTA}.xdelta ${AOLD}.${EXT}
   sync
   pupkill $YAFPID1
   [ "$ANEW" != "$FIRSTSNAP" ] && rm -f ${ANEW}.${EXT}
   [ $MARKDONE -eq 1 ] && break
   GRN=`expr $GRN + 10`
   [ $GRN -gt 255 ] && GRN=160
  done
 else
  #140125 want to recover the last snapshot.
  if [ "$DELTASNAPS" ];then
   AOLD="$FIRSTSNAP"
   #need to reconstitute a sfs for previous snapshot...
   PREVDATE="`echo "$DELTASNAPS" | head -n 1 | cut -f 2 -d '_'`"
   echo "xdelta3 -d -s ${FIRSTSNAP}.${EXT} ${FIRSTSNAP}_${PREVDATE}.xdelta ${PREVDATE}.${EXT}"
   xdelta3 -d -s ${FIRSTSNAP}.${EXT} ${FIRSTSNAP}_${PREVDATE}.xdelta ${PREVDATE}.${EXT}
   sync
   echo "${FIRSTSNAP}_${PREVDATE}.xdelta" >> /tmp/audit/snapshot-mark-delete
  fi
 fi
 GRN=`expr $GRN + 10`
 [ $GRN -gt 255 ] && GRN=160
 COLR="#FB$(busybox printf %0x $GRN)03"
 
 #got code out of /usr/local/petget/installpkg.sh...
 #the 'cp' utility needs fixes for dir symlinks...
 #mount ${AOLD}.${EXT}, copy contents, then umount...
 yaf-splash -bg "$COLR" -fg black -close never -fontsize large -text "$(gettext 'Restoring system from snapshot, please wait...')" &
 YAFPID1=$!
 mkdir -p /tmp/audit/snapshot-mntpt
 busybox mount -t squashfs -o loop,ro ${AOLD}.${EXT} /tmp/audit/snapshot-mntpt
 DIRECTSAVEPATH='/tmp/audit/snapshot-mntpt'
 cp -a -f --remove-destination ${DIRECTSAVEPATH}/* /  2> /tmp/audit/install-cp-errlog
 sync
 #can have a problem if want to replace a folder with a symlink. for example, got this error:
 # cp: cannot overwrite directory '/usr/share/mplayer/skins' with non-directory
 #3builddistro has this fix... which is a vice-versa situation...
 #firstly, the vice-versa, source is a directory, target is a symlink...
 CNT=0
 #140104 fixes...
 echo -n '' > /tmp/audit/install-cp-relocations #140106
 while [ -s /tmp/audit/install-cp-errlog ];do
  echo -n '' > /tmp/audit/install-cp-errlog2
  echo -n '' > /tmp/audit/install-cp-errlog3
  cat /tmp/audit/install-cp-errlog | grep 'cannot overwrite non-directory' | grep 'with directory' | tr '[`‘’]' "'" | cut -f 2 -d "'" |
  while read ONEDIRSYMLINK #ex: /usr/share/mplayer/skins
  do
   if [ -h "${ONEDIRSYMLINK}" ];then #source is a directory, target is a symlink...
    zALINK="$(realpath "${ONEDIRSYMLINK}" 2>/dev/null)" #140112
    [ "$zALINK" ] && echo "$zALINK" >> /tmp/audit/install-cp-relocations #140112
    #adding that extra trailing / does the trick...
    cp -a -f --remove-destination ${DIRECTSAVEPATH}"${ONEDIRSYMLINK}"/* "${ONEDIRSYMLINK}"/ 2>> /tmp/audit/install-cp-errlog2
   else #source is a directory, target is a file...
    rm -f "${ONEDIRSYMLINK}" #delete the file!
    DIRPATH="$(dirname "${ONEDIRSYMLINK}")"
    cp -a -f ${DIRECTSAVEPATH}"${ONEDIRSYMLINK}" "${DIRPATH}"/ 2>> /tmp/audit/install-cp-errlog2 #copy directory (and contents).
   fi
  done
  #secondly, which is our mplayer example, source is a symlink, target is a folder...
  cat /tmp/audit/install-cp-errlog | grep 'cannot overwrite directory' | grep 'with non-directory' | tr '[`‘’]' "'" | cut -f 2 -d "'" |
  while read ONEDIRSYMLINK #ex: /usr/share/mplayer/skins
  do
   #difficult situation, whether to impose the symlink of package, or not. if not...
   #cp -a -f --remove-destination ${DIRECTSAVEPATH}"${ONEDIRSYMLINK}"/* "${ONEDIRSYMLINK}"/ 2> /tmp/audit/install-cp-errlog3
   #or, if we have chosen to follow link...
   DIRPATH="$(dirname "${ONEDIRSYMLINK}")"
   if [ -h ${DIRECTSAVEPATH}"${ONEDIRSYMLINK}" ];then #source is a symlink, trying to overwrite a directory...
    ALINK="$(readlink ${DIRECTSAVEPATH}"${ONEDIRSYMLINK}")"
    if [ "${ALINK:0:1}" = "/" ];then #test 1st char
     xALINK="$ALINK" #absolute
    else
     xALINK="${DIRPATH}/${ALINK}"
    fi
    if [ -d "$xALINK" ];then
     zALINK="$(realpath "$xALINK")" #140106
     echo "$zALINK" >> /tmp/audit/install-cp-relocations #140106
     cp -a -f --remove-destination "${ONEDIRSYMLINK}"/* "$zALINK"/ 2>> /tmp/audit/install-cp-errlog3 #relocates target files.
     rm -rf "${ONEDIRSYMLINK}"
     cp -a -f ${DIRECTSAVEPATH}"${ONEDIRSYMLINK}" "${DIRPATH}"/ #creates symlink only.
    fi
   else #source is a file, trying to overwrite a directory...
    rm -rf "${ONEDIRSYMLINK}" #deleting directory!!!
    cp -a -f ${DIRECTSAVEPATH}"${ONEDIRSYMLINK}" "${DIRPATH}"/ #creates file only.
   fi
  done
  cat /tmp/audit/install-cp-errlog2 >> /tmp/audit/install-cp-errlog3
  cat /tmp/audit/install-cp-errlog3 > /tmp/audit/install-cp-errlog
  sync
  CNT=`expr $CNT + 1`
  [ $CNT -gt 10 ] && break #something wrong, get out.
 done
 
 #131227 find files to be deleted...
 #131229 can't just compare with ${PRE}/ as that will delete /dev, /tmp etc...
 cmptree /tmp/audit/snapshot-mntpt/bin /bin > /tmp/audit/cmptree-recover
 cmptree /tmp/audit/snapshot-mntpt/sbin /sbin >> /tmp/audit/cmptree-recover
 cmptree /tmp/audit/snapshot-mntpt/lib /lib >> /tmp/audit/cmptree-recover
 [ -d /tmp/audit/snapshot-mntpt/opt ] && cmptree /tmp/audit/snapshot-mntpt/opt /opt >> /tmp/audit/cmptree-recover
 cmptree /tmp/audit/snapshot-mntpt/etc /etc >> /tmp/audit/cmptree-recover
 cmptree /tmp/audit/snapshot-mntpt/usr /usr >> /tmp/audit/cmptree-recover
 cmptree /tmp/audit/snapshot-mntpt/boot /boot >> /tmp/audit/cmptree-recover
 cmptree /tmp/audit/snapshot-mntpt/root /root >> /tmp/audit/cmptree-recover
 sync
 #files to be deleted... (see code in create-service-packs)
 grep '^/tmp/audit/snapshot-mntpt/.*does not exist.$' /tmp/audit/cmptree-recover > /tmp/audit/cmptree-recover-removed0
 grep -f /tmp/audit/install-cp-relocations -v /tmp/audit/cmptree-recover-removed0 > /tmp/audit/cmptree-recover-removed #140106
 sed -e 's%^/tmp/audit/snapshot-mntpt%%' /tmp/audit/cmptree-recover-removed | cut -f 1 -d ' ' |
 while read ADEL
 do
  [ ! "$ADEL" ] && continue
  if [ -d "$ADEL" ];then
   rm -rf "$ADEL"
  else
   rm -f "$ADEL"
  fi
 done
 sync
 
 busybox umount /tmp/audit/snapshot-mntpt
 
 #delete forward-time, leave ${AOLD}.${EXT} and any older delta-files...
 #140103 if there is only one snapshot, that have just recovered from, do not delete it...
 CNTDELTA=`find /audit/snapshots -mindepth 1 -maxdepth 1 -type f -name '*.xdelta' | wc -l`
 CNTSNAP=`find /audit/snapshots -mindepth 1 -maxdepth 1 -type f -name "*.${EXT}" 2>/dev/null | wc -l`
 if [ $CNTSNAP -eq 1 -a $CNTDELTA -eq 0 ];then
  echo "Have recovered from snapshot, but not deleting it."
 else
  for ADEL in `cat /tmp/audit/snapshot-mark-delete | tr '\n' ' '`
  do
   rm -f ${ADEL}
  done
 fi
 
 #140206 remove prior installed pkgs that have been wiped out by recovery...
 if [ -s /root/.packages/user-installed-packages ];then
  cut -f 1 -d '|' /root/.packages/user-installed-packages > /tmp/snapshot-recover-user-pkgs
  for ADEPSFS in `find /audit/deposed -maxdepth 1 -type f -name '*DEPOSED.sfs' | tr '\n' ' '`
  do
   ADEPBASE="`basename ${ADEPSFS} DEPOSED.sfs`"
   [ "$(grep -x "${ADEPBASE}" /tmp/snapshot-recover-user-pkgs)" = "" ] && rm -f ${ADEPSFS}
  done
 fi
 
 pupkill $YAFPID1
 
 #131226 update vmlinuz and logo.16 in 1st partition, if full-drive installation...
 #140103 fix for "p"...
 FLAGP1=0
 PPARTNUM="$(echo -n "$PDEV1" | grep -o -E '[a-z][0-9]$|[a-z][0-9][0-9]$' | cut -c 2-)" #ex: 2
 PDRIVE="$(echo -n "$PDEV1" | sed -e "s%${PPARTNUM}$%%" -e 's%p$%%')" #ex: sdb
 P=''
 [ "$(echo -n "$PDEV1" | grep '[0-9]p[0-9]')" != "" ] && P='p' #ex: mmcblk0p1
 if [ "$PPARTNUM" = "2" ];then
  #PART1FS="$(guess_fstype /dev/${PDRIVE}${P}1)"
  PART1FS="$(busybox blkid /dev/${PDRIVE}${P}1 | grep -o ' TYPE=.*' | cut -f 2 -d '"')" #151117
  if [ "$PART1FS" = "vfat" ];then
   P1MNTPT="$(busybox mount | grep "^/dev/${PDRIVE}${P}1 " | tr -s ' ' | cut -f 3 -d ' ')"
   if [ ! "$P1MNTPT" ];then
    mkdir -p /mnt/${PDRIVE}${P}1
    busybox mount -t ${PART1FS} /dev/${PDRIVE}${P}1 /mnt/${PDRIVE}${P}1
    if [ $? -eq 0 ];then
     P1MNTPT="/mnt/${PDRIVE}${P}1"
     FLAGP1=1
    fi
   fi
   if [ "$P1MNTPT" ];then
    if [ -f ${P1MNTPT}/logo.16 ];then
     echo "Copying logo.16 and vmlinuz into first partition..."
     cp -a -f /boot/syslinux/logo.16 ${P1MNTPT}/
     cp -a -f /boot/vmlinuz ${P1MNTPT}/
     sync
    fi
    [ $FLAGP1 -eq 1 ] && busybox umount ${P1MNTPT}
   fi
  fi
 fi

 xAOLD="$(echo -n "$AOLD" | sed -r -e 's%([0-9][0-9][0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])([0-9][0-9])%\1-\2-\3 \4:\5%')"
 pupmessage -bg '#AAFB03' -fg black -title "$(gettext 'Snapshot:') ${xAOLD}" "$(gettext "That's it, system has been restored from snapshot!")" #'
fi
###END Recover###

#131224 limit number of snapshots...
limitsnaps_func

exit 0
###END###
