dwipe 2.0.1__py3-none-any.whl → 3.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dwipe/DeviceChangeMonitor.py +244 -0
- dwipe/DeviceInfo.py +703 -177
- dwipe/DeviceWorker.py +566 -0
- dwipe/DiskWipe.py +953 -214
- dwipe/DrivePreChecker.py +203 -0
- dwipe/FirmwareWipeTask.py +865 -0
- dwipe/NvmeTool.py +225 -0
- dwipe/PersistentState.py +45 -16
- dwipe/Prereqs.py +84 -0
- dwipe/SataTool.py +499 -0
- dwipe/StructuredLogger.py +644 -0
- dwipe/Tunables.py +62 -0
- dwipe/Utils.py +298 -3
- dwipe/VerifyTask.py +412 -0
- dwipe/WipeJob.py +631 -171
- dwipe/WipeTask.py +150 -0
- dwipe/WriteTask.py +402 -0
- dwipe/main.py +34 -9
- dwipe-3.0.0.dist-info/METADATA +566 -0
- dwipe-3.0.0.dist-info/RECORD +24 -0
- dwipe/ToolManager.py +0 -637
- dwipe/WipeJobFuture.py +0 -245
- dwipe-2.0.1.dist-info/METADATA +0 -410
- dwipe-2.0.1.dist-info/RECORD +0 -14
- {dwipe-2.0.1.dist-info → dwipe-3.0.0.dist-info}/WHEEL +0 -0
- {dwipe-2.0.1.dist-info → dwipe-3.0.0.dist-info}/entry_points.txt +0 -0
- {dwipe-2.0.1.dist-info → dwipe-3.0.0.dist-info}/licenses/LICENSE +0 -0
dwipe/WipeJobFuture.py
DELETED
|
@@ -1,245 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Docstring for dwipe.WipeJobFuture. Probably, only winners here are:
|
|
3
|
-
- Detailed Status Dict - Returns structured status.
|
|
4
|
-
Low risk but not urgent since current status works fine.
|
|
5
|
-
- Custom Pattern Sequences - Adds 0xFF pattern support.
|
|
6
|
-
Low risk but adds complexity.
|
|
7
|
-
"""
|
|
8
|
-
|
|
9
|
-
class MaybeSomeDay:
|
|
10
|
-
def __init__(self, device_path, total_size, opts=None, resume_from=0, resume_mode=None):
|
|
11
|
-
""" Performance Throttling """
|
|
12
|
-
# ... existing initialization ...
|
|
13
|
-
|
|
14
|
-
# Performance throttling
|
|
15
|
-
self.max_speed_mbps = getattr(opts, 'max_speed_mbps', 0) # 0 = unlimited
|
|
16
|
-
self.min_speed_mbps = getattr(opts, 'min_speed_mbps', 0) # Minimum speed to trigger stall detection
|
|
17
|
-
|
|
18
|
-
# Stall detection and recovery
|
|
19
|
-
self.stall_timeout = getattr(opts, 'stall_timeout', 300) # Seconds before stall recovery (5 min)
|
|
20
|
-
self.last_progress_time = time.monotonic()
|
|
21
|
-
self.last_progress_bytes = resume_from
|
|
22
|
-
|
|
23
|
-
# Adaptive block sizing
|
|
24
|
-
self.adaptive_block_size = getattr(opts, 'adaptive_block_size', False)
|
|
25
|
-
self.current_write_size = WipeJob.WRITE_SIZE
|
|
26
|
-
|
|
27
|
-
# Temperature monitoring (for SSDs)
|
|
28
|
-
self.check_temperature = getattr(opts, 'check_temperature', False)
|
|
29
|
-
self.last_temp_check = 0
|
|
30
|
-
self.temp_check_interval = 60 # seconds
|
|
31
|
-
|
|
32
|
-
# Energy-efficient mode
|
|
33
|
-
self.energy_saver = getattr(opts, 'energy_saver', False)
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def _throttle_write_speed(self, bytes_written, start_time):
|
|
39
|
-
"""Throttle write speed to specified maximum"""
|
|
40
|
-
if self.max_speed_mbps <= 0:
|
|
41
|
-
return
|
|
42
|
-
|
|
43
|
-
elapsed = time.monotonic() - start_time
|
|
44
|
-
if elapsed <= 0:
|
|
45
|
-
return
|
|
46
|
-
|
|
47
|
-
actual_speed_mbps = (bytes_written / (1024 * 1024)) / elapsed
|
|
48
|
-
if actual_speed_mbps > self.max_speed_mbps:
|
|
49
|
-
# Calculate how long to sleep to hit target speed
|
|
50
|
-
target_time = (bytes_written / (1024 * 1024)) / self.max_speed_mbps
|
|
51
|
-
sleep_time = target_time - elapsed
|
|
52
|
-
if sleep_time > 0:
|
|
53
|
-
time.sleep(sleep_time)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def _check_ssd_temperature(self):
|
|
58
|
-
"""Check SSD temperature and throttle if too hot"""
|
|
59
|
-
if not self.check_temperature:
|
|
60
|
-
return
|
|
61
|
-
|
|
62
|
-
now = time.monotonic()
|
|
63
|
-
if now - self.last_temp_check < self.temp_check_interval:
|
|
64
|
-
return
|
|
65
|
-
|
|
66
|
-
self.last_temp_check = now
|
|
67
|
-
|
|
68
|
-
try:
|
|
69
|
-
# Try to read temperature from SMART or sysfs
|
|
70
|
-
device_name = os.path.basename(self.device_path)
|
|
71
|
-
|
|
72
|
-
# Check sysfs for temperature
|
|
73
|
-
temp_paths = [
|
|
74
|
-
f"/sys/block/{device_name}/device/hwmon/hwmon*/temp1_input",
|
|
75
|
-
f"/sys/block/{device_name}/device/temperature",
|
|
76
|
-
]
|
|
77
|
-
|
|
78
|
-
for temp_path in temp_paths:
|
|
79
|
-
for path in glob.glob(temp_path):
|
|
80
|
-
try:
|
|
81
|
-
with open(path, 'r') as f:
|
|
82
|
-
temp_millic = int(f.read().strip())
|
|
83
|
-
temp_c = temp_millic // 1000
|
|
84
|
-
|
|
85
|
-
if temp_c > 70: # Throttle if >70°C
|
|
86
|
-
# Reduce speed by 50%
|
|
87
|
-
old_max = self.max_speed_mbps
|
|
88
|
-
self.max_speed_mbps = max(10, old_max // 2)
|
|
89
|
-
if old_max != self.max_speed_mbps:
|
|
90
|
-
print(f"Temperature {temp_c}°C: Throttling to {self.max_speed_mbps} MB/s")
|
|
91
|
-
elif temp_c < 60 and self.max_speed_mbps != getattr(self.opts, 'max_speed_mbps', 0):
|
|
92
|
-
# Restore speed if cooled down
|
|
93
|
-
self.max_speed_mbps = getattr(self.opts, 'max_speed_mbps', 0)
|
|
94
|
-
|
|
95
|
-
except (OSError, ValueError):
|
|
96
|
-
continue
|
|
97
|
-
|
|
98
|
-
except Exception:
|
|
99
|
-
pass
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
def _energy_saver_write(self, fd, chunk, is_random_pass):
|
|
107
|
-
"""Write with energy saving considerations"""
|
|
108
|
-
if not self.energy_saver:
|
|
109
|
-
return os.write(fd, chunk)
|
|
110
|
-
|
|
111
|
-
# For energy saving:
|
|
112
|
-
# 1. Group writes
|
|
113
|
-
# 2. Add small delays between writes
|
|
114
|
-
# 3. Use larger blocks when possible
|
|
115
|
-
|
|
116
|
-
bytes_written = 0
|
|
117
|
-
chunk_size = len(chunk)
|
|
118
|
-
|
|
119
|
-
while bytes_written < chunk_size:
|
|
120
|
-
write_size = min(self.current_write_size, chunk_size - bytes_written)
|
|
121
|
-
sub_chunk = chunk[bytes_written:bytes_written + write_size]
|
|
122
|
-
|
|
123
|
-
# Write the chunk
|
|
124
|
-
written = os.write(fd, sub_chunk)
|
|
125
|
-
bytes_written += written
|
|
126
|
-
|
|
127
|
-
# Small delay for energy saving
|
|
128
|
-
if bytes_written < chunk_size:
|
|
129
|
-
time.sleep(0.001) # 1ms delay
|
|
130
|
-
|
|
131
|
-
# Update progress
|
|
132
|
-
self.total_written += written
|
|
133
|
-
|
|
134
|
-
return bytes_written
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
def _adjust_block_size(self, write_success, write_time):
|
|
143
|
-
"""Dynamically adjust block size based on performance"""
|
|
144
|
-
if not self.adaptive_block_size:
|
|
145
|
-
return
|
|
146
|
-
|
|
147
|
-
if write_success:
|
|
148
|
-
# Successful write - consider increasing block size
|
|
149
|
-
speed_mbps = (self.current_write_size / (1024 * 1024)) / write_time if write_time > 0 else 0
|
|
150
|
-
|
|
151
|
-
if speed_mbps > 100: # Good speed, try larger blocks
|
|
152
|
-
new_size = min(WipeJob.WRITE_SIZE * 4, self.current_write_size * 2)
|
|
153
|
-
if new_size != self.current_write_size:
|
|
154
|
-
self.current_write_size = new_size
|
|
155
|
-
print(f"Increased block size to {new_size // 1024}KB")
|
|
156
|
-
else:
|
|
157
|
-
# Write failed or slow - reduce block size
|
|
158
|
-
new_size = max(WipeJob.BLOCK_SIZE, self.current_write_size // 2)
|
|
159
|
-
if new_size != self.current_write_size:
|
|
160
|
-
self.current_write_size = new_size
|
|
161
|
-
print(f"Reduced block size to {new_size // 1024}KB")
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
def get_detailed_status(self):
|
|
170
|
-
"""Get detailed status including speed, ETA, and health metrics"""
|
|
171
|
-
elapsed, pct_str, rate_str, eta_str = self.get_status()
|
|
172
|
-
|
|
173
|
-
status = {
|
|
174
|
-
'elapsed': elapsed,
|
|
175
|
-
'percentage': pct_str,
|
|
176
|
-
'rate': rate_str,
|
|
177
|
-
'eta': eta_str,
|
|
178
|
-
'bytes_written': self.total_written,
|
|
179
|
-
'total_bytes': self.total_size * self.passes,
|
|
180
|
-
'current_pass': self.current_pass + 1 if not self.verify_phase else 'Verifying',
|
|
181
|
-
'total_passes': self.passes,
|
|
182
|
-
'verify_phase': self.verify_phase,
|
|
183
|
-
'verify_result': self.verify_result if hasattr(self, 'verify_result') else None,
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
# Add adaptive block size info if enabled
|
|
187
|
-
if self.adaptive_block_size:
|
|
188
|
-
status['block_size_kb'] = self.current_write_size // 1024
|
|
189
|
-
|
|
190
|
-
# Add throttle info if enabled
|
|
191
|
-
if self.max_speed_mbps > 0:
|
|
192
|
-
status['max_speed_mbps'] = self.max_speed_mbps
|
|
193
|
-
|
|
194
|
-
return status
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
def get_custom_pattern(self, pass_number):
|
|
200
|
-
"""Get custom write pattern if specified"""
|
|
201
|
-
custom_patterns = getattr(self.opts, 'custom_patterns', None)
|
|
202
|
-
if custom_patterns and pass_number < len(custom_patterns):
|
|
203
|
-
pattern = custom_patterns[pass_number]
|
|
204
|
-
if pattern == 'random':
|
|
205
|
-
return True
|
|
206
|
-
elif pattern == 'zeros':
|
|
207
|
-
return False
|
|
208
|
-
elif pattern == 'ones':
|
|
209
|
-
# Special pattern: all ones (0xFF)
|
|
210
|
-
return 'ones'
|
|
211
|
-
|
|
212
|
-
# Fall back to standard pattern
|
|
213
|
-
mode_to_use = self.resume_mode if self.resume_mode else self.opts.wipe_mode.replace('+V', '')
|
|
214
|
-
return self.get_pass_pattern(pass_number, mode_to_use)
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
def run_benchmark(self, duration_seconds=30):
|
|
220
|
-
"""Run a benchmark to determine optimal settings"""
|
|
221
|
-
print(f"Running benchmark for {duration_seconds} seconds...")
|
|
222
|
-
|
|
223
|
-
benchmark_results = []
|
|
224
|
-
test_sizes = [4*1024, 64*1024, 512*1024, 1024*1024, 4*1024*1024] # 4KB to 4MB
|
|
225
|
-
|
|
226
|
-
for test_size in test_sizes:
|
|
227
|
-
self.current_write_size = test_size
|
|
228
|
-
start_time = time.monotonic()
|
|
229
|
-
bytes_written = 0
|
|
230
|
-
|
|
231
|
-
# Test write for duration_seconds
|
|
232
|
-
while time.monotonic() - start_time < duration_seconds:
|
|
233
|
-
# Perform test write
|
|
234
|
-
# ... benchmark logic ...
|
|
235
|
-
pass
|
|
236
|
-
|
|
237
|
-
speed_mbps = bytes_written / (1024 * 1024) / duration_seconds
|
|
238
|
-
benchmark_results.append((test_size, speed_mbps))
|
|
239
|
-
print(f" Block size {test_size//1024}KB: {speed_mbps:.2f} MB/s")
|
|
240
|
-
|
|
241
|
-
# Find optimal block size
|
|
242
|
-
optimal_size = max(benchmark_results, key=lambda x: x[1])[0]
|
|
243
|
-
print(f"Optimal block size: {optimal_size//1024}KB")
|
|
244
|
-
|
|
245
|
-
return optimal_size
|
dwipe-2.0.1.dist-info/METADATA
DELETED
|
@@ -1,410 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: dwipe
|
|
3
|
-
Version: 2.0.1
|
|
4
|
-
Summary: A tool to wipe disks and partitions for Linux
|
|
5
|
-
Keywords: disk,partition,wipe,clean,scrub
|
|
6
|
-
Author-email: Joe Defen <joedef@google.com>
|
|
7
|
-
Requires-Python: >=3.8
|
|
8
|
-
Description-Content-Type: text/markdown
|
|
9
|
-
Classifier: Programming Language :: Python :: 3
|
|
10
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
-
Classifier: Operating System :: POSIX :: Linux
|
|
12
|
-
License-File: LICENSE
|
|
13
|
-
Requires-Dist: console-window == 1.3.2
|
|
14
|
-
Project-URL: Bug Tracker, https://github.com/joedefen/dwipe/issues
|
|
15
|
-
Project-URL: Homepage, https://github.com/joedefen/dwipe
|
|
16
|
-
|
|
17
|
-
# dwipe
|
|
18
|
-
`dwipe` is a tool to wipe disks and partitions for Linux to help secure your data. `dwipe` aims to reduce mistakes by providing ample information about your devices during selection.
|
|
19
|
-
|
|
20
|
-

|
|
21
|
-
### Quick Comparison
|
|
22
|
-
|
|
23
|
-
| Feature | dwipe | nwipe | shred | dd |
|
|
24
|
-
|---------|-------|-------|-------|-----|
|
|
25
|
-
| Interactive TUI | ✓ | ✓ | ✗ | ✗ |
|
|
26
|
-
| Multiple simultaneous wipes | ✓ | ✗ | ✗ | ✗ |
|
|
27
|
-
| Hot-swap detection | ✓ | ✗ | ✗ | ✗ |
|
|
28
|
-
| Device/partition locking | ✓ | ✗ | ✗ | ✗ |
|
|
29
|
-
| Persistent wipe state | ✓ | ✗ | ✗ | ✗ |
|
|
30
|
-
| Resume interrupted wipes | ✓ | ✗ | ✗ | ✗ |
|
|
31
|
-
| Wipe operation logging | ✓ | ✗ | ✗ | ✗ |
|
|
32
|
-
| Mount detection/prevention | ✓ | ✓ | ✗ | ✗ |
|
|
33
|
-
| Fast Statistical sampling verification | ✓ | ✗ | ✗ | ✗ |
|
|
34
|
-
| Multi-pass wipe standards | ✗ | ✓ | ✓ | ✗ |
|
|
35
|
-
| Full sequential verification | ✗ | ✓ | ✓ | ✓ |
|
|
36
|
-
| Certificate generation | ✗ | ✓ | ✗ | ✗ |
|
|
37
|
-
|
|
38
|
-
> * **Modern drives are reliably wiped with one pass of zeros**; just zero once in almost all cases for best, fastest results.
|
|
39
|
-
> * `dwipe` offers Multi-pass and Rand modes as "checkbox" features, but those provide no additional security on drives manufactured after 2001 (NIST SP 800-88).
|
|
40
|
-
|
|
41
|
-
## **V2 Features**
|
|
42
|
-
|
|
43
|
-
* **Statistical verification** - Automatic or on-demand verification with intelligent pattern detection:
|
|
44
|
-
- Fast-fail for zeros (fails on first non-zero byte)
|
|
45
|
-
- Statistical analysis for random data to check for evidence of randomness
|
|
46
|
-
- Smart sampling: divides disk into 100 sections, randomly samples each section to sample entire disk
|
|
47
|
-
- Unmarked disk detection: can verify disks without filesystems and auto-detect if zeros/random
|
|
48
|
-
* **Configurable verification percentage** - Choose thoroughness: 0% (skip), 2%, 5%, 10%, 25%, 50%, or 100% (cycle with **V** key, persistent preference)
|
|
49
|
-
* **Multi-pass wipe support** - Choose 1, 2, or 4 wipe passes with alternating patterns for improved data destruction (cycle with **P** key, persistent preference)
|
|
50
|
-
* **Inline wipe confirmation** - Confirmation prompts appear below the selected device (no popup), keeping full context visible
|
|
51
|
-
* **Configurable confirmation modes** - Choose your safety level: single keypress (Y/y), typed confirmation (YES/yes), or device name (cycle with **c** key)
|
|
52
|
-
* **Enhanced wipe history** - Detailed log viewer (**h** key) shows wipe history with UUIDs, filesystems, labels, and percentages for stopped wipes
|
|
53
|
-
* **Active wipe highlighting** - In-progress wipes displayed in bright cyan/blue with elapsed time, remaining time, and transfer speed (0-100% write, 101-200% verify)
|
|
54
|
-
* **Persistent user preferences** - Theme, wipe mode (Rand/Zero/Rand+V/Zero+V), confirmation mode, verification %, and locked devices persist across sessions (saved to `~/.config/dwipe/state.json`)
|
|
55
|
-
* **Individual partition locking** - Lock individual partitions to prevent accidental wiping (previously only whole disks could be locked)
|
|
56
|
-
* **Full terminal color themes** - Complete themed color schemes with backgrounds, not just highlights (cycle with **t** key)
|
|
57
|
-
* **Visual feedback improvements** - Mounted and locked devices appear dimmed; active wipes are bright and prominent
|
|
58
|
-
* **Smart device identification** - Uses UUID/PARTUUID/serial numbers for stable device tracking across reconnections
|
|
59
|
-
* **Screen-based navigation** - Modern screen stack architecture with help screen (**?**) and history screen (**h**)
|
|
60
|
-
* **Direct I/O to Disk** - Wiping is done with direct I/O which is fast and avoid polluting your page cache. Writer threads are given lower than normal I/O priority to play nice with other apps. This makes stopping jobs fast and certain.
|
|
61
|
-
* **Improved Handling of Bad Disks.** Now detects (sometimes corrects) write failures, slowdowns, excessive no progress, and reports/aborts hopeless or hopelessly slow wipes.
|
|
62
|
-
|
|
63
|
-
## **V2.x Features**
|
|
64
|
-
Features added since V2 deployed (may not be in latest demo):
|
|
65
|
-
* **Port and Serial number**. Press `p` to toggle whether port and serial number is show; it adds another line per disk and you may want to use it selectively.
|
|
66
|
-
## Requirements
|
|
67
|
-
- **Linux operating system** (uses `/dev/`, `/sys/`, `/proc/` interfaces)
|
|
68
|
-
- **Python 3.8 or higher**
|
|
69
|
-
- **Root/sudo privileges** (automatically requested when you run the tool)
|
|
70
|
-
- **lsblk utility** (usually pre-installed on most Linux distributions)
|
|
71
|
-
|
|
72
|
-
## Installation
|
|
73
|
-
|
|
74
|
-
* **Recommended (using pipx):** `pipx install dwipe`
|
|
75
|
-
* **Verify installation:** `dwipe --help`
|
|
76
|
-
* **Uninstall:** `pipx uninstall dwipe`
|
|
77
|
-
|
|
78
|
-
## Quick Start
|
|
79
|
-
1. Install `dwipe`
|
|
80
|
-
2. Run `dwipe` from a terminal (`sudo` will be requested automatically)
|
|
81
|
-
3. Observe the context-sensitive help on the first line
|
|
82
|
-
4. Navigate with arrow keys or vi-like keys (j/k)
|
|
83
|
-
5. Press **?** for full help screen
|
|
84
|
-
|
|
85
|
-
## Features
|
|
86
|
-
|
|
87
|
-
`dwipe` provides comprehensive disk wiping capabilities with safety features:
|
|
88
|
-
|
|
89
|
-
* **Smart device display** - Shows disks and partitions with labels, sizes, types, and vendor/model information to help identify devices correctly
|
|
90
|
-
* **Safety protections** - Prevents wiping mounted devices, detects overlapping wipes, supports manual disk locking
|
|
91
|
-
* **Hot-swap detection** - Updates the device list when storage changes; newly added devices are marked with **^** to make them easy to spot
|
|
92
|
-
* **Multiple simultaneous wipes** - Start wipes on multiple devices at once, with individual progress tracking and completion states
|
|
93
|
-
* **Flexible wipe modes** - Choose between Rand, Zero, Rand+V (with auto-verify), or Zero+V (with auto-verify). Multi-pass modes alternate patterns for improved data destruction
|
|
94
|
-
* **Persistent state tracking** - Wipe status survives reboots; partially wiped (**s**) and completed (**W**) states are stored on the device
|
|
95
|
-
* **Device filtering** - Filter devices by name/pattern using regex in case of too many for one screen
|
|
96
|
-
* **Stop capability** - Stop individual wipes or all wipes in progress
|
|
97
|
-
* **Disk locking** - Manually lock disks to prevent accidental wipes (locks hide all partitions)
|
|
98
|
-
* **Dry-run mode** - Practice using the interface without risk using `--dry-run`
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
> **Note:** `dwipe` shows file system labels, and if not available, the partition label. It is best practice to label partitions and file systems well to make selection easier.
|
|
102
|
-
|
|
103
|
-
## Usage
|
|
104
|
-
|
|
105
|
-
Simply run `dwipe` from the command line without arguments: `dwipe`
|
|
106
|
-
|
|
107
|
-
### Color Legend
|
|
108
|
-
|
|
109
|
-
`dwipe` uses color coding to provide instant visual feedback about device and operation status:
|
|
110
|
-
|
|
111
|
-
- **Dimmed (gray)** - Mounted or locked devices (cannot be wiped)
|
|
112
|
-
- **Default (white)** - Ready to wipe, idle state, or previously wiped (before this session)
|
|
113
|
-
- **Bright cyan/blue + bold** - Active wipe or verification in progress (0-100% write, v0-v100% verify)
|
|
114
|
-
- **Bold yellow** - Stopped or partially completed wipe
|
|
115
|
-
- **Bold green** - ✅ Successfully completed wipe in THIS session (ready to swap out!)
|
|
116
|
-
- **Dimmer green** - ✅ Successfully completed wipe in previous session .
|
|
117
|
-
- **Bold orange** - Newly inserted (hot-swapped) device
|
|
118
|
-
- **Bold red** - Destructive operation prompts (wipe confirmation)
|
|
119
|
-
|
|
120
|
-
### Color Themes
|
|
121
|
-
|
|
122
|
-
`dwipe` supports multiple color themes for improved visibility and aesthetics.
|
|
123
|
-
|
|
124
|
-
**Available themes:**
|
|
125
|
-
- `default` - Terminal Default (basic ANSI colors)
|
|
126
|
-
- `dark-mono` - Dark Mono (almost-white on almost-black with bright colors)
|
|
127
|
-
- `light-mono` - Light Mono (almost-black on almost-white with bright colors)
|
|
128
|
-
- `solarized-dark` - Solarized Dark palette
|
|
129
|
-
- `solarized-light` - Solarized Light palette (for light terminal backgrounds)
|
|
130
|
-
- `gruvbox` - Gruvbox Dark palette
|
|
131
|
-
- `nord` - Nord palette
|
|
132
|
-
|
|
133
|
-
**Changing themes:**
|
|
134
|
-
- Press **t** from the main screen to open the theme preview screen
|
|
135
|
-
- The theme screen shows color examples for each color purpose (DANGER, SUCCESS, WARNING, etc.)
|
|
136
|
-
- Press **t** while on the theme screen to cycle through available themes and preview them live
|
|
137
|
-
- Press **ESC** or **ENTER** to return to the main screen
|
|
138
|
-
- Selected theme is saved and persists across sessions
|
|
139
|
-
|
|
140
|
-
**Theme features:**
|
|
141
|
-
- Yellow/warning color for stopped wipes (state **s**) - highly visible even when not selected
|
|
142
|
-
- Red/danger color for wipe confirmation prompts
|
|
143
|
-
- Coordinated color palettes designed for terminal readability
|
|
144
|
-
|
|
145
|
-
### Device State Values
|
|
146
|
-
|
|
147
|
-
The **STATE** column shows the current status of each device:
|
|
148
|
-
|
|
149
|
-
| State | Meaning |
|
|
150
|
-
|-------|---------|
|
|
151
|
-
| **-** | Device is ready for wiping |
|
|
152
|
-
| **^** | Device is ready for wiping AND was added after `dwipe` started (hot-swapped) |
|
|
153
|
-
| **Mnt** | Partition is mounted or disk has mounted partitions - cannot be wiped |
|
|
154
|
-
| **N%** | Wipe is in progress (shows percentage complete, 0-100%) |
|
|
155
|
-
| **vN%** | Verification is in progress (shows percentage complete, v0-v100%) |
|
|
156
|
-
| **STOP** | Wipe or verification is being stopped |
|
|
157
|
-
| **s** | Wipe was stopped - device is partially wiped (can restart or verify) |
|
|
158
|
-
| **W** | Wipe was completed successfully (can wipe again or verify) |
|
|
159
|
-
| **Lock** | Disk is manually locked - partitions are hidden and cannot be wiped |
|
|
160
|
-
| **Unlk** | Disk was just unlocked (transitory state) |
|
|
161
|
-
|
|
162
|
-
### Available Actions
|
|
163
|
-
|
|
164
|
-
The top line shows available actions. Some are context-sensitive (only available for certain devices):
|
|
165
|
-
|
|
166
|
-
| Key | Action | Description |
|
|
167
|
-
|-----|--------|-------------|
|
|
168
|
-
| **w** | wipe | Wipe the selected device (requires confirmation) |
|
|
169
|
-
| **v** | verify | Verify a wiped device or detect pattern on unmarked disk (context-sensitive) |
|
|
170
|
-
| **s** | stop | Stop the selected wipe in progress (context-sensitive) |
|
|
171
|
-
| **S** | Stop All | Stop all wipes in progress |
|
|
172
|
-
| **l** | lock/unlock | Lock or unlock a disk to prevent accidental wiping |
|
|
173
|
-
| **q** or **x** | quit | Quit the application (stops all wipes first) |
|
|
174
|
-
| **?** | help | Show help screen with all actions and navigation keys |
|
|
175
|
-
| **h** | history | Show wipe history log |
|
|
176
|
-
| **/** | filter | Filter devices by regex pattern (shows matching devices + all active wipes) |
|
|
177
|
-
| **ESC** | clear filter | Clear the filter and jump to top of list |
|
|
178
|
-
| **m** | mode | Cycle wipe mode: Rand, Zero, Rand+V, Zero+V (saved as preference) |
|
|
179
|
-
| **P** | passes | Cycle wipe passes: 1, 2, or 4 (saved as preference) |
|
|
180
|
-
| **V** | verify % | Cycle verification percentage: 0%, 2%, 5%, 10%, 25%, 50%, 100% (saved as preference) |
|
|
181
|
-
| **c** | confirmation | Cycle confirmation mode: Y, y, YES, yes, device name (saved as preference) |
|
|
182
|
-
| **d** | dirty limit | Cycle dirty page limit: 0, 500, 1000, 2000, 4000 MB (saved as preference) |
|
|
183
|
-
| **D** | dense | Toggle dense/spaced view (saved as preference) |
|
|
184
|
-
| **t** | themes | Open theme preview screen to view and change color themes |
|
|
185
|
-
|
|
186
|
-
### Wipe Modes
|
|
187
|
-
|
|
188
|
-
`dwipe` supports four wipe modes (cycle with **m** key):
|
|
189
|
-
|
|
190
|
-
- **Zero** - Fills the device with zeros (multi-pass alternates random/zero patterns, ending on zeros)
|
|
191
|
-
- **Zero+V** - Same as Zero, but automatically verifies after wipe completes (if verify % > 0)
|
|
192
|
-
- **Rand** - Fills the device with random data (multi-pass alternates zero/random patterns, ending on random)
|
|
193
|
-
- **Rand+V** - Same as Rand, but automatically verifies after wipe completes (if verify % > 0)
|
|
194
|
-
|
|
195
|
-
The `+V` suffix indicates automatic verification after wipe completion. Without `+V`, you can still manually verify by pressing **v** on a wiped device.
|
|
196
|
-
|
|
197
|
-
> **Note:** Multi-pass wipes (2 or 4 passes) alternate between zero and random patterns to ensure different bit patterns physically overwrite the disk, ending on your selected mode.
|
|
198
|
-
|
|
199
|
-
### Resuming Stopped Wipes
|
|
200
|
-
|
|
201
|
-
Stopped wipes (state **s**) can be resumed by pressing **w** on the device:
|
|
202
|
-
|
|
203
|
-
**How Resume Works:**
|
|
204
|
-
- Preserves the original wipe mode (Rand or Zero) from when the wipe was started
|
|
205
|
-
- Uses the **current** passes setting to determine how much more to write
|
|
206
|
-
- Continues from the exact byte offset where it stopped (rounded to buffer boundary)
|
|
207
|
-
- Smart validation ensures interrupted wipes resume with correct pattern integrity
|
|
208
|
-
|
|
209
|
-
**Resume Examples:**
|
|
210
|
-
|
|
211
|
-
| Stopped At | Current Passes | What Happens |
|
|
212
|
-
|------------|----------------|--------------|
|
|
213
|
-
| 50% | 1 pass | Resumes: writes remaining 50% |
|
|
214
|
-
| 150% (1.5 of 4 passes) | 1 pass | Already complete (150% > 100%) |
|
|
215
|
-
| 150% (1.5 of 4 passes) | 4 passes | Resumes: writes 2.5 more passes (150% → 400%) |
|
|
216
|
-
| 100% (1 pass complete) | 2 passes | Resumes: writes pass 2 (100% → 200%) |
|
|
217
|
-
|
|
218
|
-
**Benefits:**
|
|
219
|
-
- Change passes setting before resuming to finish faster (reduce) or add more passes (increase)
|
|
220
|
-
- No need to restart from beginning
|
|
221
|
-
- Progress marker updated every 30 seconds, so resume works even after crashes or power loss
|
|
222
|
-
- Automatic validation prevents corrupted final patterns
|
|
223
|
-
|
|
224
|
-
### Verification Strategy
|
|
225
|
-
|
|
226
|
-
`dwipe` uses intelligent verification with statistical analysis and fast-fail optimizations:
|
|
227
|
-
|
|
228
|
-
**Smart Sampling:**
|
|
229
|
-
- Divides disk into 100 equal sections
|
|
230
|
-
- Randomly samples configurable percentage (0%, 2%, 5%, 10%, 25%, 50%, 100%) from EACH section
|
|
231
|
-
- Ensures complete disk coverage even with 2% verification
|
|
232
|
-
- Change verification percentage with **V** key (saved as preference)
|
|
233
|
-
|
|
234
|
-
**Pattern Detection:**
|
|
235
|
-
- **Zero verification**: Fails immediately on first non-zero byte (fast!)
|
|
236
|
-
- **Random verification**: Statistical analysis of byte distribution
|
|
237
|
-
- Tests if byte distribution is uniform (all byte values 0-255 appear fairly equally)
|
|
238
|
-
- Fast-fails periodically if non-random pattern detected
|
|
239
|
-
- Checks for evidence of randomness to distinguish from structured data
|
|
240
|
-
|
|
241
|
-
**Verification Modes:**
|
|
242
|
-
1. **Automatic verification** (after wipe): Use a mode with `+V` suffix (Rand+V or Zero+V) and set verify % > 0
|
|
243
|
-
2. **Manual verification** (press **v**): Verify previously wiped devices or detect pattern on unmarked disks (requires verify % > 0)
|
|
244
|
-
3. **Unmarked disk detection**: Can verify disks with no filesystem to detect if all zeros or random
|
|
245
|
-
- If passes, writes marker as if disk had been wiped
|
|
246
|
-
- Useful for detecting pre-wiped drives or verifying manufacturer erasure
|
|
247
|
-
|
|
248
|
-
**Verification States:**
|
|
249
|
-
- ✓ (green checkmark) - Verification passed
|
|
250
|
-
- ✗ (red X) - Verification failed
|
|
251
|
-
- No symbol - Not verified
|
|
252
|
-
- During verify: **vN%** shows progress (v0% to v100%)
|
|
253
|
-
|
|
254
|
-
**Why statistical sampling is better than sequential:**
|
|
255
|
-
- 2% verification with 100 sections provides better coverage than 2% sequential read
|
|
256
|
-
- Detects problems faster (could hit bad sector in early sections)
|
|
257
|
-
- Statistical analysis actually validates randomness (sequential can't do this)
|
|
258
|
-
- Much faster than 100% sequential verification
|
|
259
|
-
|
|
260
|
-
### Progress Information
|
|
261
|
-
|
|
262
|
-
When wiping a device, `dwipe` displays:
|
|
263
|
-
- **Elapsed time** - Time since wipe started (e.g., 1m18s)
|
|
264
|
-
- **Remaining time** - Estimated time to completion (e.g., -3m6s)
|
|
265
|
-
- **Write rate** - Current throughput (e.g., "45.2MB/s")
|
|
266
|
-
- **MaxSlowDown** - Ratio of Fastest/Slowest write speed (e.g, ÷2). If over threshold, the write job stops.
|
|
267
|
-
- **MaxWriteDelay** - Largest write delay detected (e.g., 𝚫122ms). If over threshold, the write job stops.
|
|
268
|
-
|
|
269
|
-
### Persistent State
|
|
270
|
-
|
|
271
|
-
The **W** (wiped) and **s** (partially wiped) states are persistent across reboots. This is achieved by writing metadata to the first 16KB of the device:
|
|
272
|
-
- First 15KB: zeros
|
|
273
|
-
- Next 1KB: JSON metadata (timestamp, bytes written, total size, mode, verification status)
|
|
274
|
-
|
|
275
|
-
When a device with persistent state is displayed, additional information shows:
|
|
276
|
-
- When it was wiped and the completion percentage
|
|
277
|
-
- Verification status: ✓ (passed), ✗ (failed), or no symbol (not verified)
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
### The Help Screen
|
|
281
|
-
When **?** is typed, you can see the available keys and some obscure settings no seen elsewhere.
|
|
282
|
-
|
|
283
|
-
### Navigation
|
|
284
|
-
|
|
285
|
-
You can navigate the device list using:
|
|
286
|
-
- **Arrow keys** - Up/Down to move through the list
|
|
287
|
-
- **Vi-like keys** - j (down), k (up), g (top), G (bottom)
|
|
288
|
-
- **Page Up/Down** - Quick navigation through long lists
|
|
289
|
-
|
|
290
|
-
## Device Filtering
|
|
291
|
-
|
|
292
|
-
The **/** key activates incremental search filtering with vim-style behavior:
|
|
293
|
-
|
|
294
|
-
**How it works:**
|
|
295
|
-
- Press **/** to start filtering
|
|
296
|
-
- Type your regex pattern - the device list updates **as you type** (real-time filtering)
|
|
297
|
-
- Your cursor position is shown with **|** in the header
|
|
298
|
-
- **Arrow keys**, **Home**/**End**, and **Backspace** work for editing
|
|
299
|
-
- **ENTER** to accept the filter
|
|
300
|
-
- **ESC** to cancel and restore the previous filter
|
|
301
|
-
|
|
302
|
-
**Filter Examples:**
|
|
303
|
-
|
|
304
|
-
The filter supports regex patterns. Here are some useful examples:
|
|
305
|
-
|
|
306
|
-
```
|
|
307
|
-
/sda # Show only sda and its partitions
|
|
308
|
-
/sd[ab] # Show sda, sdb and their partitions
|
|
309
|
-
/nvme # Show all NVMe devices
|
|
310
|
-
/nvme0n1p[12] # Show only partitions 1 and 2 of nvme0n1
|
|
311
|
-
/usb # Show devices with "usb" in their labels
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
Press **ESC** from the main screen to clear the filter and return to showing all devices.
|
|
315
|
-
|
|
316
|
-
**Note:** Invalid regex patterns are ignored - the filter stays at the last valid pattern while you type.
|
|
317
|
-
|
|
318
|
-
## Security Considerations
|
|
319
|
-
|
|
320
|
-
**Important limitations:**
|
|
321
|
-
|
|
322
|
-
- `dwipe` supports multi-pass wiping with alternating patterns, but does not implement specific DoD 5220.22-M or Gutmann certified pattern sequences
|
|
323
|
-
- More than adequate for **personal and business data** that doesn't require (antiquated) certified destruction
|
|
324
|
-
- **NOT suitable for** classified, top-secret, or highly sensitive data requiring certified pattern-specific wiping with compliance certificates
|
|
325
|
-
- **SSD considerations**:
|
|
326
|
-
- Modern SSDs use wear-leveling and may retain data in unmapped blocks
|
|
327
|
-
- TRIM/DISCARD may prevent complete data erasure
|
|
328
|
-
- For SSDs, consider manufacturer's secure erase utilities for maximum security
|
|
329
|
-
- Random mode may not provide additional security over zeros on SSDs
|
|
330
|
-
|
|
331
|
-
**Best practices:**
|
|
332
|
-
- Verify device labels and sizes carefully before wiping
|
|
333
|
-
- Use the **Lock** feature to protect critical disks
|
|
334
|
-
- Test with `--dry-run` first if unsure
|
|
335
|
-
- Consider encryption for sensitive data as the primary security measure
|
|
336
|
-
|
|
337
|
-
---
|
|
338
|
-
---
|
|
339
|
-
|
|
340
|
-
## Troubleshooting
|
|
341
|
-
|
|
342
|
-
### dwipe won't start
|
|
343
|
-
- **Error: "cannot find lsblk on $PATH"** - Install `util-linux` package
|
|
344
|
-
- **Permission denied** - `dwipe` automatically requests sudo; ensure you can use sudo
|
|
345
|
-
|
|
346
|
-
### Terminal display issues
|
|
347
|
-
- **Corrupted display after crash** - Run `reset` or `stty sane` command
|
|
348
|
-
- **Colors don't work** - Ensure your terminal supports colors (most modern terminals do)
|
|
349
|
-
|
|
350
|
-
### Wipe issues
|
|
351
|
-
- **Can't wipe a device** - Check the STATE column:
|
|
352
|
-
- **Mnt** - Unmount the partition first: `sudo umount /dev/sdXN`
|
|
353
|
-
- **Lock** - Press **l** to unlock
|
|
354
|
-
- **Busy** - Another partition on the disk is being wiped
|
|
355
|
-
- **Wipe is very slow** - Normal for large drives; check write rate to verify progress
|
|
356
|
-
- **Wipe seems stuck** - Most likely due to bad disks; Direct I/O makes progress almost constant on good disks.
|
|
357
|
-
|
|
358
|
-
---
|
|
359
|
-
### Dealing with Bad or Failing Disks
|
|
360
|
-
|
|
361
|
-
dwipe includes built-in protections for problematic storage devices:
|
|
362
|
-
|
|
363
|
-
**Automatic Error Handling.** When encountering disk errors during wiping:
|
|
364
|
-
* Consecutive write errors: Wipe aborts after 3 consecutive failed writes
|
|
365
|
-
* Total error threshold: Wipe aborts after 100 total write errors
|
|
366
|
-
* Automatic retry: On write failure, device is automatically closed and reopened (transient error recovery)
|
|
367
|
-
* File descriptor recovery: Bad FD states are detected and handles are refreshed
|
|
368
|
-
|
|
369
|
-
**Stall and Slowdown Detection.** dwipe monitors write performance and can abort problematic operations:
|
|
370
|
-
* Stall detection: Aborts if no progress for 5 minutes (configurable)
|
|
371
|
-
* Slowdown detection: Measures baseline speed during first 5 seconds, aborts if speed drops below threshold (e.g., 1/4 of baseline)
|
|
372
|
-
* Progress tracking: Continuous monitoring ensures writes are actually reaching the device
|
|
373
|
-
|
|
374
|
-
**If a Wipe Gets Stuck...** If a wipe appears frozen or unresponsive:
|
|
375
|
-
* First attempt: Press s to gracefully stop the selected wipe
|
|
376
|
-
* Wait patiently: Some disk operations can take minutes to timeout at the kernel level
|
|
377
|
-
* If still stuck: Press S (Shift+s) to stop ALL wipes
|
|
378
|
-
* Last resort: If the interface is completely frozen:
|
|
379
|
-
* Press Ctrl-Z to suspend `dwipe`
|
|
380
|
-
* In the terminal, run: `sudo pkill -f "python.*dwipe" (targets only dwipe processes)`
|
|
381
|
-
* Run reset to restore terminal if display is corrupted
|
|
382
|
-
|
|
383
|
-
**Preventing Issues with Problematic Media.** For known bad disks or questionable hardware:
|
|
384
|
-
* Start with verification: Press v first to test readability
|
|
385
|
-
* Use lower speeds: Enable dirty page throttling (d key) to reduce I/O pressure
|
|
386
|
-
* Monitor system logs: Check dmesg -w in another terminal for disk errors
|
|
387
|
-
* Consider hardware issues: USB enclosures, cables, and controllers often cause issues
|
|
388
|
-
|
|
389
|
-
**Common Disk Error Patterns**
|
|
390
|
-
* USB connection drops: dwipe will detect and attempt recovery
|
|
391
|
-
* Bad sectors: Errors will be counted; job aborts if excessive
|
|
392
|
-
* Controller timeouts: Kernel may hang; stall detection should trigger
|
|
393
|
-
* Full disk: Write past end-of-device errors are handled gracefully
|
|
394
|
-
|
|
395
|
-
**Recovery After Abort.** If a wipe aborts due to disk errors:
|
|
396
|
-
* Device state shows s (stopped/partial)
|
|
397
|
-
* You can attempt to resume (w) - may succeed if error was transient
|
|
398
|
-
* Or verify (v) to see what was actually written
|
|
399
|
-
* Consider replacing the disk if errors persist
|
|
400
|
-
|
|
401
|
-
Note: Some disks are fundamentally broken and cannot be reliably wiped. dwipe will protect itself and your system, but cannot fix hardware failures.
|
|
402
|
-
|
|
403
|
-
---
|
|
404
|
-
|
|
405
|
-
### Contributing
|
|
406
|
-
Issues and pull requests welcome at [github.com/joedefen/dwipe](https://github.com/joedefen/dwipe)
|
|
407
|
-
|
|
408
|
-
## License
|
|
409
|
-
|
|
410
|
-
MIT License - see [LICENSE](LICENSE) file for details.
|
dwipe-2.0.1.dist-info/RECORD
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
dwipe/DeviceInfo.py,sha256=7ZgtLDT1z5QwMWVwEb9Q3-wonvuPyAWgl7Xl5o14XbY,25777
|
|
2
|
-
dwipe/DiskWipe.py,sha256=SVfcGDMZccGBocpS5U8JXI-Y2UzRix3jAzzaYPVRCDc,40161
|
|
3
|
-
dwipe/PersistentState.py,sha256=FZydQs_-VYiq-Gw0hvcWPeuWOU5VFgI-FvrUsbT92RQ,6339
|
|
4
|
-
dwipe/ToolManager.py,sha256=EpG_588Q76IzFfjrTM5LSnhTUC1CoBeCUdqtR0duliY,23371
|
|
5
|
-
dwipe/Utils.py,sha256=Cuq8Usamrq1DWUk8EtjTuD6lSLXYGY0x-pDcoLJBR8M,7714
|
|
6
|
-
dwipe/WipeJob.py,sha256=bjv_hVuH5DBDgY5-y3Mv11URhsBu1t1iu8lx76dmAhE,54486
|
|
7
|
-
dwipe/WipeJobFuture.py,sha256=urkrASHtqELsKQ5c7OMc_LxpgIiYAIOeb1ZixQYmp74,8746
|
|
8
|
-
dwipe/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
9
|
-
dwipe/main.py,sha256=Zyw9LFBGqWYxga1H9qTdQGHLyCsxZUg3tm_Ylj20FG4,1841
|
|
10
|
-
dwipe-2.0.1.dist-info/entry_points.txt,sha256=SZHFezmse2c-jxG-BJ0TXy_TZ8vVFf0lPJWs0cdxz6Y,41
|
|
11
|
-
dwipe-2.0.1.dist-info/licenses/LICENSE,sha256=qB9OdnyyF6WYHiEIXVm0rOSdcf8e2ctorrtWs6CC5lU,1062
|
|
12
|
-
dwipe-2.0.1.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82
|
|
13
|
-
dwipe-2.0.1.dist-info/METADATA,sha256=kcykkG3kr9kyZ0T6nUN_dGCxbC3E2fh26HovbCnqGD4,21957
|
|
14
|
-
dwipe-2.0.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|