­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ ­ # # Run the disk layout recreation code (diskrestore.sh) # again and again until it succeeds or the user aborts. # # TODO: Provide a skip option (needs thoughtful consideration) # I think such an option is not needed in practice # because the user can add an initial 'exit 0' line to diskrestore.sh # that results in practice the same behaviour. # # TODO: Implement layout/prepare as part of a function ? # # TODO: Add choices as in layout/prepare/default/500_confirm_layout_file.sh # "View disk layout ($LAYOUT_FILE)" # "Edit disk layout ($LAYOUT_FILE)" # and for the latter choice some code like # # If disklayout.conf has changed, generate new diskrestore.sh # if (( $timestamp < $(stat --format="%Y" $LAYOUT_FILE) )); then # LogPrint "Detected changes to $LAYOUT_FILE, rebuild $LAYOUT_CODE on-the-fly." # SourceStage "layout/prepare" 2>>$RUNTIME_LOGFILE # fi # rear_workflow="rear $WORKFLOW" original_disk_space_usage_file="$VAR_DIR/layout/config/df.txt" rear_shell_history="$( echo -e "cd $VAR_DIR/layout/\nvi $LAYOUT_CODE\nless $RUNTIME_LOGFILE" )" wilful_input="" unset choices choices[0]="Rerun disk recreation script ($LAYOUT_CODE)" choices[1]="View '$rear_workflow' log file ($RUNTIME_LOGFILE)" choices[2]="Edit disk recreation script ($LAYOUT_CODE)" choices[3]="View original disk space usage ($original_disk_space_usage_file)" choices[4]="Use Relax-and-Recover shell and return back to here" choices[5]="Abort '$rear_workflow'" prompt="The disk layout recreation script failed" choice="" # When USER_INPUT_LAYOUT_CODE_RUN has any 'true' value be liberal in what you accept and # assume choices[0] 'Rerun disk recreation script' was actually meant: is_true "$USER_INPUT_LAYOUT_CODE_RUN" && USER_INPUT_LAYOUT_CODE_RUN="${choices[0]}" unset confirm_choices confirm_choices[0]="Confirm recreated disk layout and continue '$rear_workflow'" confirm_choices[1]="Go back one step to redo disk layout recreation" confirm_choices[2]="Use Relax-and-Recover shell and return back to here" confirm_choices[3]="Abort '$rear_workflow'" confirm_prompt="Confirm the recreated disk layout or go back one step" confirm_choice="" # When USER_INPUT_LAYOUT_MIGRATED_CONFIRMATION has any 'true' value be liberal in what you accept and # assume confirm_choices[0] 'Confirm recreated disk layout and continue' was actually meant: is_true "$USER_INPUT_LAYOUT_MIGRATED_CONFIRMATION" && USER_INPUT_LAYOUT_MIGRATED_CONFIRMATION="${confirm_choices[0]}" # Run the disk layout recreation code (diskrestore.sh) # again and again until it succeeds or the user aborts: while true ; do # Run LAYOUT_CODE in a sub-shell because it sets 'set -e' # so that it exits the running shell in case of an error # but that exit must not exit this running bash here: ( source $LAYOUT_CODE ) # One must explicitly test whether or not $? is zero in a separated bash command # because with bash 3.x and bash 4.x code like # # ( set -e ; cat qqq ; echo "hello" ) && echo ok || echo failed # cat: qqq: No such file or directory # hello # ok # does not work as one may expect (cf. what "man bash" describes for 'set -e'). # There is a subtle behavioural difference between bash 3.x and bash 4.x # when a script that has 'set -e' set gets sourced: # With bash 3.x the 'set -e' inside the sourced script is effective: # # echo 'set -e ; cat qqq ; echo hello' >script.sh # # ( source script.sh ) && echo ok || echo failed # cat: qqq: No such file or directory # failed # With bash 4.x the 'set -e' inside the sourced script gets noneffective: # # echo 'set -e ; cat qqq ; echo hello' >script.sh # # ( source script.sh ) && echo ok || echo failed # cat: qqq: No such file or directory # hello # ok # With bash 3.x and bash 4.x testing $? in a separated bash command # keeps the 'set -e' inside the sourced script effective: # # echo 'set -e ; cat qqq ; echo hello' >script.sh # # ( source script.sh ) ; (( $? == 0 )) && echo ok || echo failed # cat: qqq: No such file or directory # failed # See also https://github.com/rear/rear/pull/1573#issuecomment-344303590 if (( $? == 0 )) ; then # When LAYOUT_CODE succeeded and when not in migration mode # break the outer while loop and continue the "rear recover" workflow # which means continue with restoring the backup: is_true "$MIGRATION_MODE" || break # When LAYOUT_CODE succeeded in migration mode # let the user explicitly confirm the recreated (and usually migrated) disk layout # before continuing the "rear recover" workflow with restoring the backup. # Run an inner while loop with a user dialog so that the user can inspect the recreated disk layout # and perhaps even manually fix the recreated disk layout if it is not what the user wants # (e.g. by using the Relax-and-Recover shell and returning back to this user dialog): while true ; do confirm_choice="$( UserInput -I LAYOUT_MIGRATED_CONFIRMATION -p "$confirm_prompt" -D "${confirm_choices[0]}" "${confirm_choices[@]}" )" && wilful_input="yes" || wilful_input="no" case "$confirm_choice" in (${confirm_choices[0]}) # Confirm recreated disk layout and continue: is_true "$wilful_input" && LogPrint "User confirmed recreated disk layout" || LogPrint "Continuing with recreated disk layout by default" # Break the outer while loop and continue with restoring the backup: break 2 ;; (${confirm_choices[1]}) # Go back one step to redo disk layout recreation: # Only break the inner while loop (i.e. this user dialog loop) # and continue with the next user dialog below: break ;; (${confirm_choices[2]}) # rear_shell runs 'bash' with the original STDIN STDOUT and STDERR when 'rear' was launched by the user: rear_shell "" "$rear_shell_history" ;; (${confirm_choices[3]}) abort_recreate Error "User did not confirm the recreated disk layout but aborted '$rear_workflow' in ${BASH_SOURCE[0]}" ;; esac done fi # Run an inner while loop with a user dialog so that the user can fix things when LAYOUT_CODE failed. # Such a fix does not necessarily mean the user must change the diskrestore.sh script. # The user might also fix things by only using the Relax-and-Recover shell. while true ; do choice="$( UserInput -I LAYOUT_CODE_RUN -p "$prompt" -D "${choices[0]}" "${choices[@]}" )" && wilful_input="yes" || wilful_input="no" case "$choice" in (${choices[0]}) # Rerun disk recreation script: is_true "$wilful_input" && LogPrint "User reruns disk recreation script" || LogPrint "Rerunning disk recreation script by default" # Only break the inner while loop (i.e. the user dialog loop): break ;; (${choices[1]}) # Run 'less' with the original STDIN STDOUT and STDERR when 'rear' was launched by the user: less $RUNTIME_LOGFILE 0<&6 1>&7 2>&8 ;; (${choices[2]}) # Run 'vi' with the original STDIN STDOUT and STDERR when 'rear' was launched by the user: vi $LAYOUT_CODE 0<&6 1>&7 2>&8 ;; (${choices[3]}) # Run 'less' with the original STDIN STDOUT and STDERR when 'rear' was launched by the user: less $original_disk_space_usage_file 0<&6 1>&7 2>&8 ;; (${choices[4]}) # rear_shell runs 'bash' with the original STDIN STDOUT and STDERR when 'rear' was launched by the user: rear_shell "" "$rear_shell_history" ;; (${choices[5]}) abort_recreate Error "User chose to abort '$rear_workflow' in ${BASH_SOURCE[0]}" ;; esac done done