Include more details in ddrescue-tui OST posts
This commit is contained in:
parent
593cb405c5
commit
33fe7b3b9e
1 changed files with 61 additions and 2 deletions
|
|
@ -119,6 +119,7 @@ class BlockPair():
|
||||||
self.map_data: dict[str, bool | int] = {}
|
self.map_data: dict[str, bool | int] = {}
|
||||||
self.map_path: pathlib.Path = pathlib.Path()
|
self.map_path: pathlib.Path = pathlib.Path()
|
||||||
self.size: int = source_dev.size
|
self.size: int = source_dev.size
|
||||||
|
self.stats = {}
|
||||||
self.status: dict[str, float | int | str] = {
|
self.status: dict[str, float | int | str] = {
|
||||||
'read-skip': 'Pending',
|
'read-skip': 'Pending',
|
||||||
'read-full': 'Pending',
|
'read-full': 'Pending',
|
||||||
|
|
@ -345,6 +346,7 @@ class State():
|
||||||
self.ost = osticket.osTicket()
|
self.ost = osticket.osTicket()
|
||||||
self.progress_out: pathlib.Path = self.log_dir.joinpath('progress.out')
|
self.progress_out: pathlib.Path = self.log_dir.joinpath('progress.out')
|
||||||
self.mode: str = '?'
|
self.mode: str = '?'
|
||||||
|
self.notes = []
|
||||||
self.source: hw_disk.Disk | None = None
|
self.source: hw_disk.Disk | None = None
|
||||||
self.working_dir: pathlib.Path | None = None
|
self.working_dir: pathlib.Path | None = None
|
||||||
self.ui: tui.TUI = tui.TUI('Source')
|
self.ui: tui.TUI = tui.TUI('Source')
|
||||||
|
|
@ -584,6 +586,13 @@ class State():
|
||||||
def generate_report(self) -> list[str]:
|
def generate_report(self) -> list[str]:
|
||||||
"""Generate report of overall and per block_pair results, returns list."""
|
"""Generate report of overall and per block_pair results, returns list."""
|
||||||
report = []
|
report = []
|
||||||
|
stats_str = (
|
||||||
|
'\tnon-trimmed: {non-trimmed}, '
|
||||||
|
'non-scraped: {non-scraped}, '
|
||||||
|
'bad-sectors: {bad-sector}, '
|
||||||
|
'slow reads: {slow reads}, '
|
||||||
|
'run time: {run time}'
|
||||||
|
)
|
||||||
|
|
||||||
# Header
|
# Header
|
||||||
report.append(f'{self.mode.title()} Results:')
|
report.append(f'{self.mode.title()} Results:')
|
||||||
|
|
@ -604,8 +613,16 @@ class State():
|
||||||
report.append(f'Overall rescued: {percent}, error size: {error_size_str}')
|
report.append(f'Overall rescued: {percent}, error size: {error_size_str}')
|
||||||
|
|
||||||
# Block-Pairs
|
# Block-Pairs
|
||||||
if len(self.block_pairs) > 1:
|
if len(self.block_pairs) == 1:
|
||||||
report.append(' ')
|
stats = self.block_pairs[0].stats
|
||||||
|
if stats:
|
||||||
|
try:
|
||||||
|
report.append(stats_str.format(**stats))
|
||||||
|
except KeyError:
|
||||||
|
# Ignore and omit stats
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
# Two or more block_pairs
|
||||||
for pair in self.block_pairs:
|
for pair in self.block_pairs:
|
||||||
error_size = pair.get_error_size()
|
error_size = pair.get_error_size()
|
||||||
error_size_str = std.bytes_to_string(error_size, decimals=2)
|
error_size_str = std.bytes_to_string(error_size, decimals=2)
|
||||||
|
|
@ -614,11 +631,25 @@ class State():
|
||||||
pair_size = std.bytes_to_string(pair.size, decimals=2)
|
pair_size = std.bytes_to_string(pair.size, decimals=2)
|
||||||
percent = pair.get_percent_recovered()
|
percent = pair.get_percent_recovered()
|
||||||
percent = format_status_string(percent, width=0)
|
percent = format_status_string(percent, width=0)
|
||||||
|
report.append(' ')
|
||||||
report.append(
|
report.append(
|
||||||
f'{pair.source.name} ({pair_size}) '
|
f'{pair.source.name} ({pair_size}) '
|
||||||
f'rescued: {percent}, '
|
f'rescued: {percent}, '
|
||||||
f'error size: {error_size_str}'
|
f'error size: {error_size_str}'
|
||||||
)
|
)
|
||||||
|
stats = pair.stats
|
||||||
|
if not stats:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
report.append(stats_str.format(**stats))
|
||||||
|
except KeyError:
|
||||||
|
# Ignore and omit stats
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Notes
|
||||||
|
if self.notes:
|
||||||
|
report.append(' ')
|
||||||
|
report.extend(self.notes)
|
||||||
|
|
||||||
# Done
|
# Done
|
||||||
return report
|
return report
|
||||||
|
|
@ -1654,6 +1685,24 @@ def get_etoc() -> str:
|
||||||
return etoc
|
return etoc
|
||||||
|
|
||||||
|
|
||||||
|
def get_stats() -> dict[str, Any]:
|
||||||
|
"""Get stats from ddrescue output, returns dict."""
|
||||||
|
output = tmux.capture_pane()
|
||||||
|
stats = {}
|
||||||
|
temp = []
|
||||||
|
for line in output[output.find('ipos:'):].splitlines():
|
||||||
|
temp.extend(line.split(','))
|
||||||
|
for line in temp:
|
||||||
|
line = line.strip()
|
||||||
|
try:
|
||||||
|
key, value = line.split(':')
|
||||||
|
stats[key] = value.strip()
|
||||||
|
except ValueError:
|
||||||
|
# ignore
|
||||||
|
pass
|
||||||
|
return stats
|
||||||
|
|
||||||
|
|
||||||
def finalize_recovery(state: State, dry_run: bool = True) -> None:
|
def finalize_recovery(state: State, dry_run: bool = True) -> None:
|
||||||
"""Show recovery finalization options."""
|
"""Show recovery finalization options."""
|
||||||
zero_fill_destination(state, dry_run=dry_run)
|
zero_fill_destination(state, dry_run=dry_run)
|
||||||
|
|
@ -2096,6 +2145,9 @@ def relocate_backup_gpt(state: State, dry_run: bool = True) -> None:
|
||||||
if proc.returncode:
|
if proc.returncode:
|
||||||
cli.print_error('ERROR: Failed to relocate backup GPT.')
|
cli.print_error('ERROR: Failed to relocate backup GPT.')
|
||||||
LOG.error('sfdisk result: %s, %s', proc.stdout, proc.stderr)
|
LOG.error('sfdisk result: %s, %s', proc.stdout, proc.stderr)
|
||||||
|
state.notes.append('NOTE: Failed to relocated backup GPT')
|
||||||
|
else:
|
||||||
|
state.notes.append('NOTE: Relocated backup GPT to the end of the disk.')
|
||||||
|
|
||||||
|
|
||||||
def run_ddrescue(state, block_pair, pass_name, settings, dry_run=True) -> None:
|
def run_ddrescue(state, block_pair, pass_name, settings, dry_run=True) -> None:
|
||||||
|
|
@ -2183,6 +2235,9 @@ def run_ddrescue(state, block_pair, pass_name, settings, dry_run=True) -> None:
|
||||||
# Update SMART pane
|
# Update SMART pane
|
||||||
_update_smart_panes()
|
_update_smart_panes()
|
||||||
|
|
||||||
|
# Stats
|
||||||
|
block_pair.stats.update(get_stats())
|
||||||
|
|
||||||
# Check destination
|
# Check destination
|
||||||
warning_message = check_destination_health(state.destination)
|
warning_message = check_destination_health(state.destination)
|
||||||
if warning_message:
|
if warning_message:
|
||||||
|
|
@ -2430,9 +2485,13 @@ def zero_fill_destination(state: State, dry_run: bool = True) -> None:
|
||||||
|
|
||||||
# Re-run ddrescue to zero-fill gaps
|
# Re-run ddrescue to zero-fill gaps
|
||||||
proc = exe.run_program(cmd, check=False, pipe=False)
|
proc = exe.run_program(cmd, check=False, pipe=False)
|
||||||
|
LOG.info('Zero-fill result: %s', proc)
|
||||||
if proc.returncode:
|
if proc.returncode:
|
||||||
cli.print_error('ERROR: Failed to zero-fill: {block_pair.destination}')
|
cli.print_error('ERROR: Failed to zero-fill: {block_pair.destination}')
|
||||||
LOG.error('zero-fill error: %s, %s', proc.stdout, proc.stderr)
|
LOG.error('zero-fill error: %s, %s', proc.stdout, proc.stderr)
|
||||||
|
state.notes.append('NOTE: Failed to zero-fill destination')
|
||||||
|
else:
|
||||||
|
state.notes.append('NOTE: Zero-filled gaps and extra space on destination.')
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue