Prevent recovering to wrong devices or paths

Before starting a recovery run verify the source and destination have
not changed.  This will prevent issues on some extreme edge cases but
the main goal is for disappearing source drives with heavy damage.

e.g. A very damaged source drive disappears mid-recovery, drops off and
before would need a restart, or unplug/replug, to continue.  Now we can
attempt to re-detect the drive and resume recovery without leaving the
script.  If for some reason the drive order were to change then we'll
avoid using the wrong source or destination device.
This commit is contained in:
2Shirt 2021-04-08 23:09:00 -06:00
parent 43fd30322e
commit 5a2d35d3cc
Signed by: 2Shirt
GPG key ID: 152FAC923B0E132C

View file

@ -1719,6 +1719,8 @@ def is_missing_source_or_destination(state):
'Source': state.source,
'Destination': state.destination,
}
# Check items
for name, item in items.items():
if not item:
continue
@ -1733,9 +1735,38 @@ def is_missing_source_or_destination(state):
else:
LOG.error('Unknown %s type: %s', name, item)
# Update top panes
state.update_top_panes()
# Done
return missing
def source_or_destination_changed(state):
"""Verify the source and destination objects are still valid."""
changed = False
# Compare objects
for obj in (state.source, state.destination):
if not obj:
changed = True
elif hasattr(obj, 'exists'):
# Assuming dest path
changed = changed or not obj.exists()
elif isinstance(obj, hw_obj.Disk):
compare_dev = hw_obj.Disk(obj.path)
for key in ('model', 'serial'):
changed = changed or obj.details[key] != compare_dev.details[key]
# Update top panes
state.update_top_panes()
# Done
if changed:
std.print_error('Source and/or Destination changed')
return changed
def main():
# pylint: disable=too-many-branches
"""Main function for ddrescue TUI."""
@ -1760,7 +1791,6 @@ def main():
# Show menu
while True:
state.update_top_panes()
selection = main_menu.advanced_select()
# Change settings
@ -1781,6 +1811,8 @@ def main():
std.print_standard('Forcing controllers to rescan for devices...')
cmd = 'echo "- - -" | sudo tee /sys/class/scsi_host/host*/scan'
exe.run_program(cmd, check=False, shell=True)
if source_or_destination_changed(state):
std.abort()
# Start recovery
if 'Start' in selection:
@ -2022,10 +2054,12 @@ def run_recovery(state, main_menu, settings_menu, dry_run=True):
# Bail early
if is_missing_source_or_destination(state):
state.update_top_panes()
std.print_standard('')
std.pause('Press Enter to return to main menu...')
return
if source_or_destination_changed(state):
std.print_standard('')
std.abort()
# Get settings
for name, details in main_menu.toggles.items():