Updated run_ddrescue() to use new objects
This commit is contained in:
parent
53a899f967
commit
bb270715c1
1 changed files with 36 additions and 43 deletions
|
|
@ -65,6 +65,7 @@ class BlockPair():
|
||||||
def __init__(self, mode, source, dest):
|
def __init__(self, mode, source, dest):
|
||||||
self.mode = mode
|
self.mode = mode
|
||||||
self.source = source
|
self.source = source
|
||||||
|
self.source_path = source.path
|
||||||
self.dest = dest
|
self.dest = dest
|
||||||
self.pass_done = [False, False, False]
|
self.pass_done = [False, False, False]
|
||||||
self.resumed = False
|
self.resumed = False
|
||||||
|
|
@ -97,6 +98,7 @@ class BlockPair():
|
||||||
|
|
||||||
def finish_pass(self, pass_num):
|
def finish_pass(self, pass_num):
|
||||||
"""Mark pass as done and check if 100% recovered."""
|
"""Mark pass as done and check if 100% recovered."""
|
||||||
|
map_data = read_map_file(self.map_path)
|
||||||
if map_data['full recovery']:
|
if map_data['full recovery']:
|
||||||
self.pass_done = [True, True, True]
|
self.pass_done = [True, True, True]
|
||||||
self.rescued = self.size
|
self.rescued = self.size
|
||||||
|
|
@ -111,10 +113,6 @@ class BlockPair():
|
||||||
else:
|
else:
|
||||||
self.pass_done[pass_num] = True
|
self.pass_done[pass_num] = True
|
||||||
|
|
||||||
def get_pass_done(self, pass_num):
|
|
||||||
"""Return pass number's done state."""
|
|
||||||
return self.pass_done[pass_num]
|
|
||||||
|
|
||||||
def load_map_data(self):
|
def load_map_data(self):
|
||||||
"""Load data from map file and set progress."""
|
"""Load data from map file and set progress."""
|
||||||
map_data = read_map_file(self.map_path)
|
map_data = read_map_file(self.map_path)
|
||||||
|
|
@ -128,8 +126,8 @@ class BlockPair():
|
||||||
# Initial pass incomplete
|
# Initial pass incomplete
|
||||||
pass
|
pass
|
||||||
elif map_data['non-trimmed'] > 0:
|
elif map_data['non-trimmed'] > 0:
|
||||||
self.pass_done[0] = True
|
self.pass_done = [True, False, False]
|
||||||
self.status[0] = 'Skipped'
|
self.status = ['Skipped', 'Pending', 'Pending']
|
||||||
elif map_data['non-scraped'] > 0:
|
elif map_data['non-scraped'] > 0:
|
||||||
self.pass_done = [True, True, False]
|
self.pass_done = [True, True, False]
|
||||||
self.status = ['Skipped', 'Skipped', 'Pending']
|
self.status = ['Skipped', 'Skipped', 'Pending']
|
||||||
|
|
@ -259,6 +257,7 @@ class RecoveryState():
|
||||||
def __init__(self, mode, source, dest):
|
def __init__(self, mode, source, dest):
|
||||||
self.mode = mode.lower()
|
self.mode = mode.lower()
|
||||||
self.source = source
|
self.source = source
|
||||||
|
self.source_path = source.path
|
||||||
self.dest = dest
|
self.dest = dest
|
||||||
self.block_pairs = []
|
self.block_pairs = []
|
||||||
self.current_pass = 0
|
self.current_pass = 0
|
||||||
|
|
@ -320,7 +319,7 @@ class RecoveryState():
|
||||||
"""Checks if pass is done for all block-pairs, returns bool."""
|
"""Checks if pass is done for all block-pairs, returns bool."""
|
||||||
done = True
|
done = True
|
||||||
for bp in self.block_pairs:
|
for bp in self.block_pairs:
|
||||||
done &= bp.get_pass_done(self.current_pass)
|
done &= bp.pass_done[self.current_pass]
|
||||||
return done
|
return done
|
||||||
|
|
||||||
def current_pass_min(self):
|
def current_pass_min(self):
|
||||||
|
|
@ -345,7 +344,7 @@ class RecoveryState():
|
||||||
# Iterate backwards through passes
|
# Iterate backwards through passes
|
||||||
pass_done = True
|
pass_done = True
|
||||||
for bp in self.block_pairs:
|
for bp in self.block_pairs:
|
||||||
pass_done &= bp.get_pass_done(pass_num)
|
pass_done &= bp.pass_done[pass_num]
|
||||||
if pass_done:
|
if pass_done:
|
||||||
# All block-pairs reported being done
|
# All block-pairs reported being done
|
||||||
# Set to next pass, unless we're on the last pass (2)
|
# Set to next pass, unless we're on the last pass (2)
|
||||||
|
|
@ -806,7 +805,11 @@ def menu_settings(source):
|
||||||
def read_map_file(map_path):
|
def read_map_file(map_path):
|
||||||
"""Read map file with ddrescuelog and return data as dict."""
|
"""Read map file with ddrescuelog and return data as dict."""
|
||||||
map_data = {}
|
map_data = {}
|
||||||
result = run_program(['ddrescuelog', '-t', map_path])
|
try:
|
||||||
|
result = run_program(['ddrescuelog', '-t', map_path])
|
||||||
|
except CalledProcessError:
|
||||||
|
# (Grossly) assuming map_data hasn't been saved yet, return empty dict
|
||||||
|
return map_data
|
||||||
|
|
||||||
# Parse output
|
# Parse output
|
||||||
for line in result.stdout.decode().splitlines():
|
for line in result.stdout.decode().splitlines():
|
||||||
|
|
@ -824,7 +827,7 @@ def read_map_file(map_path):
|
||||||
# Check if 100% done
|
# Check if 100% done
|
||||||
try:
|
try:
|
||||||
run_program(['ddrescuelog', '-D', map_path])
|
run_program(['ddrescuelog', '-D', map_path])
|
||||||
except subprocess.CalledProcessError:
|
except CalledProcessError:
|
||||||
map_data['full recovery'] = False
|
map_data['full recovery'] = False
|
||||||
else:
|
else:
|
||||||
map_data['full recovery'] = True
|
map_data['full recovery'] = True
|
||||||
|
|
@ -832,25 +835,16 @@ def read_map_file(map_path):
|
||||||
return map_data
|
return map_data
|
||||||
|
|
||||||
|
|
||||||
def run_ddrescue(source, dest, settings):
|
def run_ddrescue(state):
|
||||||
"""Run ddrescue pass."""
|
"""Run ddrescue pass."""
|
||||||
current_pass = source['Current Pass']
|
|
||||||
return_code = None
|
return_code = None
|
||||||
|
|
||||||
if current_pass == 'Done':
|
if state.finished:
|
||||||
clear_screen()
|
clear_screen()
|
||||||
print_warning('Recovery already completed?')
|
print_warning('Recovery already completed?')
|
||||||
pause('Press Enter to return to main menu...')
|
pause('Press Enter to return to main menu...')
|
||||||
return
|
return
|
||||||
|
|
||||||
# Set device(s) to clone/image
|
|
||||||
source[current_pass]['Status'] = 'Working'
|
|
||||||
source['Started Recovery'] = True
|
|
||||||
source_devs = [source]
|
|
||||||
if source['Children']:
|
|
||||||
# Use only selected child devices
|
|
||||||
source_devs = source['Children']
|
|
||||||
|
|
||||||
# Set heights
|
# Set heights
|
||||||
# NOTE: 12/33 is based on min heights for SMART/ddrescue panes (12+22+1sep)
|
# NOTE: 12/33 is based on min heights for SMART/ddrescue panes (12+22+1sep)
|
||||||
result = run_program(['tput', 'lines'])
|
result = run_program(['tput', 'lines'])
|
||||||
|
|
@ -863,39 +857,35 @@ def run_ddrescue(source, dest, settings):
|
||||||
'-bdvl', str(height_smart),
|
'-bdvl', str(height_smart),
|
||||||
'-PF', '#D',
|
'-PF', '#D',
|
||||||
'watch', '--color', '--no-title', '--interval', '300',
|
'watch', '--color', '--no-title', '--interval', '300',
|
||||||
'ddrescue-tui-smart-display', source['Dev Path'])
|
'ddrescue-tui-smart-display', state.source_path)
|
||||||
|
|
||||||
# Start pass for each selected device
|
# Run pass for each block-pair
|
||||||
for s_dev in source_devs:
|
for bp in state.block_pairs:
|
||||||
if s_dev[current_pass]['Done']:
|
if bp.pass_done[state.current_pass]:
|
||||||
# Move to next device
|
# Skip to next block-pair
|
||||||
continue
|
continue
|
||||||
source['Current Device'] = s_dev['Dev Path']
|
bp.status[state.current_pass] = 'Working'
|
||||||
s_dev[current_pass]['Status'] = 'Working'
|
update_progress(state)
|
||||||
update_progress(source)
|
|
||||||
|
|
||||||
# Set ddrescue cmd
|
# Set ddrescue cmd
|
||||||
if source['Type'] == 'clone':
|
cmd = [
|
||||||
cmd = [
|
'ddrescue', *settings,
|
||||||
'ddrescue', *settings, '--force', s_dev['Dev Path'],
|
bp.source_path, bp.dest_path, bp.map_path]
|
||||||
dest['Dev Path'], s_dev['Dest Paths']['Map']]
|
if state.mode == 'clone':
|
||||||
else:
|
cmd.append('--force')
|
||||||
cmd = [
|
if current_pass == 0:
|
||||||
'ddrescue', *settings, s_dev['Dev Path'],
|
|
||||||
s_dev['Dest Paths']['image'], s_dev['Dest Paths']['Map']]
|
|
||||||
if current_pass == 'Pass 1':
|
|
||||||
cmd.extend(['--no-trim', '--no-scrape'])
|
cmd.extend(['--no-trim', '--no-scrape'])
|
||||||
elif current_pass == 'Pass 2':
|
elif current_pass == 1:
|
||||||
# Allow trimming
|
# Allow trimming
|
||||||
cmd.append('--no-scrape')
|
cmd.append('--no-scrape')
|
||||||
elif current_pass == 'Pass 3':
|
elif current_pass == 2:
|
||||||
# Allow trimming and scraping
|
# Allow trimming and scraping
|
||||||
pass
|
pass
|
||||||
|
|
||||||
# Start ddrescue
|
# Start ddrescue
|
||||||
try:
|
try:
|
||||||
clear_screen()
|
clear_screen()
|
||||||
print_info('Current dev: {}'.format(s_dev['Dev Path']))
|
print_info('Current dev: {}'.format(bp.source_path))
|
||||||
ddrescue_proc = popen_program(['./__choose_exit', *cmd])
|
ddrescue_proc = popen_program(['./__choose_exit', *cmd])
|
||||||
# ddrescue_proc = popen_program(['./__exit_ok', *cmd])
|
# ddrescue_proc = popen_program(['./__exit_ok', *cmd])
|
||||||
# ddrescue_proc = popen_program(cmd)
|
# ddrescue_proc = popen_program(cmd)
|
||||||
|
|
@ -903,10 +893,10 @@ def run_ddrescue(source, dest, settings):
|
||||||
try:
|
try:
|
||||||
ddrescue_proc.wait(timeout=10)
|
ddrescue_proc.wait(timeout=10)
|
||||||
sleep(2)
|
sleep(2)
|
||||||
update_progress(source)
|
update_progress(state)
|
||||||
break
|
break
|
||||||
except subprocess.TimeoutExpired:
|
except subprocess.TimeoutExpired:
|
||||||
update_progress(source)
|
update_progress(state)
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
# Catch user abort
|
# Catch user abort
|
||||||
pass
|
pass
|
||||||
|
|
@ -921,6 +911,9 @@ def run_ddrescue(source, dest, settings):
|
||||||
# i.e. not None and not 0
|
# i.e. not None and not 0
|
||||||
print_error('Error(s) encountered, see message above.')
|
print_error('Error(s) encountered, see message above.')
|
||||||
break
|
break
|
||||||
|
else:
|
||||||
|
# Mark pass finished
|
||||||
|
bp.finish_pass(state.current_pass)
|
||||||
|
|
||||||
# Done
|
# Done
|
||||||
if str(return_code) != '0':
|
if str(return_code) != '0':
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue