#!/bin/bash # ================================================================================ # # RESTORE - interactive restore # # Restore duplicity backup data to a local directory. # Please notice: duplicity does not overwrite any dir or file. So the restore # path is different to the path of the backed up data. # # SYNTAX: # restore.sh [path-to-restore] # # path-to-restore - optional # default: none ... you get an interactive selection of backup sets # # -------------------------------------------------------------------------------- # ah - Axel Hahn <axel.hahn@iml.unibe.ch> # ds - Daniel Schueler <daniel.schueler@iml.unibe.ch> # # 2016-11-17 ah,ds v1.0 # 2017-10-11 ah,ds v1.1 added support for duplicity param --ssh-backend # 2018-08-27 ah,ds v1.2 fix restore target with a given selection; handle '*' placeholder # 2019-06-05 ah,ds v1.3 add custom cache dir # 2021-05-19 ah,ds, v2.0 plugin driven # 2022-10-21 ah v2.1 init vars; shell fixes # 2024-02-01 ah v2.2 update restore menu # ================================================================================ # -------------------------------------------------------------------------------- # CONFIG # -------------------------------------------------------------------------------- # . `dirname $0`/inc_config.sh . $(dirname $0)/includes/jobhelper.sh || exit 1 . $(dirname $0)/includes/inc_bash.sh || exit 1 # --- load a transfer plugin STORAGE_BIN=$(_j_getvar ${STORAGEFILE} "bin") if [ -z "$STORAGE_BIN" ]; then if ! id -u | grep '^0$' then cecho error "ERROR: Maybe you need root permissions to start $0" else cecho error "ERROR: missing config bin = ... for file transfer." fi exit 1 fi CFGPREFIX=${STORAGE_BIN}_ . $(dirname $0)/plugins/transfer/$STORAGE_BIN.sh || exit 1 # --- get backend url of backup data STORAGE_BASEDIR=$(_j_getvar ${STORAGEFILE} "storage") if [ -z $STORAGE_BASEDIR ]; then echo "ERROR: missing config for backup target." echo "There must be an entry storage in ${STORAGEFILE}" exit 1 fi # target directory of directory specific repository STORAGE_TARGETPATH= PASSPHRASE=$(_j_getvar "${STORAGEFILE}" "passphrase") # timestamp or snapshot id RESTORE_ITEM= # include filter to restore a part of the backup set RESTORE_FILTER= # full path of restore data RESTORE_BASEDIR=$(_j_getvar "${STORAGEFILE}" "restore-path") RESTORE_TARGETPATH= # set vars for transfer plugin t_setVars || exit 1 # ----- Create default command line parameters export ARGS_DEFAULT ARGS_DEFAULT="$( t_getParamDefault $1 $2 )" sFileSshPrivkey=$(_j_getvar "${STORAGEFILE}" "ssh-privatekey") if [ -n "$sFileSshPrivkey" ]; then ARGS_DEFAULT="${ARGS_DEFAULT} $( t_getParamSshKey $sFileSshPrivkey )" fi # task#3046 - add custom cache dir sCacheDir=$(_j_getvar "${STORAGEFILE}" "cachedir") ARGS_DEFAULT="${ARGS_DEFAULT} $( t_getParamCacheDir $sCacheDir )" # ----- what to restore ... BACKUP_DIR= # -------------------------------------------------------------------------------- # FUNCTIONS # -------------------------------------------------------------------------------- # ---------------------------------------------------------------------- # enter name of directory to restore; menu item # ---------------------------------------------------------------------- function enterBackupDir(){ h2 "select a directory to be restored" echo "This is a list of the directories from the backup configuration." echo "Enter the full path" echo echo "Enter the full path; marked entries with (*) do not exist on this machine" echo local sDirs="$(j_getDirs2Backup)" for mydir in $sDirs do if [ ! -d "$mydir" ]; then color error echo "$mydir (*)" color reset else echo "$mydir" fi done color input echo -n "[$BACKUP_DIR] >" color reset read -r myinput setBackupDir "${myinput}" } # ---------------------------------------------------------------------- # set backup dir .. called when using cli parameter or enterBackupDir # param string full path of a directory to retore # ---------------------------------------------------------------------- function setBackupDir(){ if [ ! -z $1 ]; then sDirs2Backup="$(j_getDirs2Backup)" bFound=0 for mydir in ${sDirs2Backup} do if [ "${mydir}" = "${1}" ]; then bFound=1 fi done if [ $bFound -eq 0 ]; then color error echo echo "WARNING: seems to be wrong ... " echo "At the moment I restore only known targets." color reset # TODO: if we want to retore other backup sets of other servers # we cannot be as strict else BACKUP_DIR=$1 setVars fi fi } # ---------------------------------------------------------------------- # internal: set variables for target path and backup set # ---------------------------------------------------------------------- # set backup url and local restore path (based on given backup directory) function setVars(){ local sSafeName=$(j_getSafename "$BACKUP_DIR") RESTORE_TARGETPATH="${RESTORE_BASEDIR}/${sSafeName}" STORAGE_TARGETPATH="$( t_backupDirGetTarget $BACKUP_DIR )" } # actions for restore function doRestore(){ local restorecmd=$( t_restoreDoRestore ) if [ -z "$restorecmd" ]; then color error echo "ERROR: There is no restore command ... " echo "A developer must check t_restoreDoRestore in plugins/transfer/$STORAGE_BIN.sh" color reset exit 1 fi mkdir -p "${RESTORE_TARGETPATH}" echo "$restorecmd" color cmd $restorecmd fetchrc color reset t_rcCheckRestore $myrc echo echo echo Restore is finished. echo Have look to the output above. echo "The restore path has $(find ${RESTORE_TARGETPATH} | wc -l) items ($(du -hs ${RESTORE_TARGETPATH} | awk '{ print $1 }'))" echo echo " find ${RESTORE_TARGETPATH}" echo exit } # -------------------------------------------------------------------------------- # MAIN # -------------------------------------------------------------------------------- # ----- set a directory to restore to have a useful initial point t_checkRequirements setBackupDir $1 if [ -z "$BACKUP_DIR" ]; then enterBackupDir fi # ----- menu and loop while true do h1 "Restore :: Menu" echo " D - directory to restore: $( color cmd ; echo -n $BACKUP_DIR; color reset)" echo echo "---------- Restore method 1:" echo echo " M - mount backup with fuse" echo echo "---------- Restore method 2:" echo echo -n " W - time or snapshot ID : $( color cmd ; echo -n $RESTORE_ITEM; color reset)" test -z "$RESTORE_ITEM" && echo -n " ... set one first" test -z "$RESTORE_ITEMINFO" || echo -n " ($RESTORE_ITEMINFO)" echo echo -n " F - what to restore : $( color cmd ; echo -n $RESTORE_FILTER; color reset)" test -z "$RESTORE_FILTER" && echo -n "(no filter = restore all files)" echo echo # echo " C - show file changes" # echo " V - verify" # echo echo " R - start restore with $STORAGE_BIN" echo echo " restore from : $STORAGE_TARGETPATH" | sed 's#:[^:]*@#:**********@#' echo " restore to : $( color cmd ; echo -n $RESTORE_TARGETPATH; color reset)" echo -n " " if [ -n "$RESTORE_TARGETPATH" ]; then ls -d "$RESTORE_TARGETPATH" >/dev/null 2>&1 if [ $? -eq 0 ]; then color error echo "WARNING: directory already exists! Backup will fail." color reset else echo "OK, it does not exist yet" fi else echo "(not set)" fi echo echo "---------- Other options:" echo echo " S - search files" echo " B - Bash (Shell)" echo " X - exit" echo showPrompt "Select (not case sensitive) --> " read -r action echo case $action in d|D) enterBackupDir ;; w|W) h2 "Set a time / select a snapshot" t_restoreDoSelect ;; c|C) showFilechanges ;; m|M) h2 "Mount backup data" t_restoreDoMountBackupdata ;; s|S) h2 "Search a file" filefilter=".*" showPrompt "Regex for filefilter; ${filefilter} for all >" read -r filefilter test -z "${filefilter}" || t_restoreDoSearchFile "${filefilter}" ;; # v|V) # t_backupDoVerify # ;; b|B) h2 "Shell" echo "HINT: type exit in the subshell to return to the menu." echo export PS1="RESTIC [$(basename $0) \u@\h \w]\$ " bash --noprofile ;; f|F) h2 "Filter restore items" echo "By default all files will be restored." echo "You can limit it by setting include rules." t_restoreDoSetIncludeFilter ;; r|R) h2 "Start restore" doRestore ;; x|X) exit 0 ;; *) echo "Try again" esac done # --------------------------------------------------------------------------------