Added resume function and checkpoints for broken
setups
This commit is contained in:
Regular → Executable
+272
-34
@@ -25,6 +25,20 @@ KALI_ISO = ""
|
|||||||
TAILS_ISO = ""
|
TAILS_ISO = ""
|
||||||
CUSTOM_ISO = ""
|
CUSTOM_ISO = ""
|
||||||
DRIVE = ""
|
DRIVE = ""
|
||||||
|
STATE_FILE = "/tmp/covert_sd_state.json"
|
||||||
|
|
||||||
|
# Checkpoint states
|
||||||
|
CHECKPOINTS = {
|
||||||
|
"VERACRYPT_DOWNLOADED": False,
|
||||||
|
"DRIVE_SELECTED": False,
|
||||||
|
"DRIVE_WIPED": False,
|
||||||
|
"ISO_WRITTEN": False,
|
||||||
|
"PARTITIONS_CREATED": False,
|
||||||
|
"PERSISTENCE_SETUP": False,
|
||||||
|
"DOCS_ENCRYPTED": False,
|
||||||
|
"TOOLS_SETUP": False,
|
||||||
|
"COMPLETE": False
|
||||||
|
}
|
||||||
|
|
||||||
def log(message):
|
def log(message):
|
||||||
"""Logs a message to both the log file and the terminal."""
|
"""Logs a message to both the log file and the terminal."""
|
||||||
@@ -32,6 +46,75 @@ def log(message):
|
|||||||
log_file.write(message + "\n")
|
log_file.write(message + "\n")
|
||||||
print(message)
|
print(message)
|
||||||
|
|
||||||
|
def save_state(checkpoint_name, data=None):
|
||||||
|
"""Save current progress to state file."""
|
||||||
|
global CHECKPOINTS
|
||||||
|
CHECKPOINTS[checkpoint_name] = True
|
||||||
|
|
||||||
|
state = {
|
||||||
|
"checkpoints": CHECKPOINTS,
|
||||||
|
"drive": DRIVE,
|
||||||
|
"timestamp": TIMESTAMP,
|
||||||
|
"log_file": LOG_FILE,
|
||||||
|
"create_kali": CREATE_KALI,
|
||||||
|
"create_docs": CREATE_DOCS,
|
||||||
|
"create_tails": CREATE_TAILS,
|
||||||
|
"create_custom": CREATE_CUSTOM,
|
||||||
|
"kali_iso": KALI_ISO,
|
||||||
|
"tails_iso": TAILS_ISO,
|
||||||
|
"custom_iso": CUSTOM_ISO,
|
||||||
|
"fast_mode": FAST_MODE,
|
||||||
|
"paranoid_mode": PARANOID_MODE
|
||||||
|
}
|
||||||
|
|
||||||
|
if data:
|
||||||
|
state.update(data)
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(STATE_FILE, 'w') as f:
|
||||||
|
json.dump(state, f, indent=2)
|
||||||
|
log(f"✓ Checkpoint saved: {checkpoint_name}")
|
||||||
|
except Exception as e:
|
||||||
|
log(f"⚠ Warning: Could not save checkpoint: {e}")
|
||||||
|
|
||||||
|
def load_state():
|
||||||
|
"""Load previous progress from state file."""
|
||||||
|
global CHECKPOINTS, DRIVE, TIMESTAMP, LOG_FILE
|
||||||
|
global CREATE_KALI, CREATE_DOCS, CREATE_TAILS, CREATE_CUSTOM
|
||||||
|
global KALI_ISO, TAILS_ISO, CUSTOM_ISO, FAST_MODE, PARANOID_MODE
|
||||||
|
|
||||||
|
if not os.path.exists(STATE_FILE):
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(STATE_FILE, 'r') as f:
|
||||||
|
state = json.load(f)
|
||||||
|
|
||||||
|
CHECKPOINTS = state.get("checkpoints", CHECKPOINTS)
|
||||||
|
DRIVE = state.get("drive", "")
|
||||||
|
TIMESTAMP = state.get("timestamp", TIMESTAMP)
|
||||||
|
LOG_FILE = state.get("log_file", LOG_FILE)
|
||||||
|
CREATE_KALI = state.get("create_kali", False)
|
||||||
|
CREATE_DOCS = state.get("create_docs", False)
|
||||||
|
CREATE_TAILS = state.get("create_tails", False)
|
||||||
|
CREATE_CUSTOM = state.get("create_custom", False)
|
||||||
|
KALI_ISO = state.get("kali_iso", "")
|
||||||
|
TAILS_ISO = state.get("tails_iso", "")
|
||||||
|
CUSTOM_ISO = state.get("custom_iso", "")
|
||||||
|
FAST_MODE = state.get("fast_mode", False)
|
||||||
|
PARANOID_MODE = state.get("paranoid_mode", False)
|
||||||
|
|
||||||
|
return state
|
||||||
|
except Exception as e:
|
||||||
|
log(f"⚠ Warning: Could not load state: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def clear_state():
|
||||||
|
"""Remove state file when setup is complete."""
|
||||||
|
if os.path.exists(STATE_FILE):
|
||||||
|
os.remove(STATE_FILE)
|
||||||
|
log("✓ State file cleared")
|
||||||
|
|
||||||
def run_command(command, shell=False, interactive=False, ignore_enospc=False):
|
def run_command(command, shell=False, interactive=False, ignore_enospc=False):
|
||||||
"""
|
"""
|
||||||
Runs a system command.
|
Runs a system command.
|
||||||
@@ -135,9 +218,51 @@ def download_portable_veracrypt():
|
|||||||
log("This is a one-time download that will be stored on your device.")
|
log("This is a one-time download that will be stored on your device.")
|
||||||
log("")
|
log("")
|
||||||
|
|
||||||
|
# Use consistent temp directory for caching across runs
|
||||||
|
temp_dir = "/tmp/veracrypt_download"
|
||||||
|
|
||||||
|
# Check if we already have cached downloads
|
||||||
|
if os.path.exists(temp_dir):
|
||||||
|
log(f"✓ Found existing VeraCrypt cache at: {temp_dir}")
|
||||||
|
log("Checking if all required files are present...")
|
||||||
|
|
||||||
|
# Check if all files exist and are recent enough
|
||||||
|
cache_valid = True
|
||||||
|
cached_files = []
|
||||||
|
|
||||||
|
for platform, info in {
|
||||||
|
"Windows": "VeraCrypt-Portable-Windows.exe",
|
||||||
|
"Linux AppImage": "VeraCrypt-Portable-Linux.AppImage",
|
||||||
|
"Linux DEB": "veracrypt-Ubuntu-22.04-amd64.deb",
|
||||||
|
"macOS": "VeraCrypt-MacOS.dmg"
|
||||||
|
}.items():
|
||||||
|
file_path = os.path.join(temp_dir, info)
|
||||||
|
if os.path.exists(file_path):
|
||||||
|
size_mb = os.path.getsize(file_path) / (1024 * 1024)
|
||||||
|
cached_files.append(f" ✓ {platform}: {size_mb:.1f} MB")
|
||||||
|
else:
|
||||||
|
cache_valid = False
|
||||||
|
break
|
||||||
|
|
||||||
|
if cache_valid:
|
||||||
|
log("✓ All VeraCrypt files found in cache!")
|
||||||
|
for cf in cached_files:
|
||||||
|
log(cf)
|
||||||
|
log("")
|
||||||
|
use_cache = input("Use cached files? (y/n) [Default: y]: ") or "y"
|
||||||
|
if use_cache.lower() == "y":
|
||||||
|
log("✓ Using cached VeraCrypt downloads")
|
||||||
|
return temp_dir
|
||||||
|
else:
|
||||||
|
log("Removing old cache and downloading fresh copies...")
|
||||||
|
shutil.rmtree(temp_dir)
|
||||||
|
else:
|
||||||
|
log("⚠ Cache incomplete, will re-download")
|
||||||
|
shutil.rmtree(temp_dir)
|
||||||
|
|
||||||
# Create temp directory for downloads
|
# Create temp directory for downloads
|
||||||
temp_dir = tempfile.mkdtemp(prefix="veracrypt_download_")
|
os.makedirs(temp_dir, exist_ok=True)
|
||||||
log(f"Using temporary directory: {temp_dir}")
|
log(f"Downloading to: {temp_dir}")
|
||||||
log("")
|
log("")
|
||||||
|
|
||||||
# Get latest VeraCrypt version from GitHub
|
# Get latest VeraCrypt version from GitHub
|
||||||
@@ -322,26 +447,69 @@ def setup_usb():
|
|||||||
|
|
||||||
# Download portable VeraCrypt first (so it's ready to copy later)
|
# Download portable VeraCrypt first (so it's ready to copy later)
|
||||||
veracrypt_dir = None
|
veracrypt_dir = None
|
||||||
if CREATE_DOCS:
|
if CREATE_DOCS and not CHECKPOINTS["VERACRYPT_DOWNLOADED"]:
|
||||||
veracrypt_dir = download_portable_veracrypt()
|
veracrypt_dir = download_portable_veracrypt()
|
||||||
|
save_state("VERACRYPT_DOWNLOADED", {"veracrypt_dir": veracrypt_dir})
|
||||||
|
elif CREATE_DOCS:
|
||||||
|
# Already downloaded, use cached version
|
||||||
|
veracrypt_dir = "/tmp/veracrypt_download"
|
||||||
|
log("✓ Skipping VeraCrypt download (already completed)")
|
||||||
|
|
||||||
log("\n" + "="*70)
|
if not CHECKPOINTS["DRIVE_SELECTED"]:
|
||||||
log("STEP 1: DRIVE SELECTION")
|
log("\n" + "="*70)
|
||||||
log("="*70)
|
log("STEP 1: DRIVE SELECTION")
|
||||||
log("Available storage devices on your system:")
|
log("="*70)
|
||||||
list_drives()
|
log("Available storage devices on your system:")
|
||||||
log("\nIMPORTANT: Double-check the drive path! All data will be erased.")
|
list_drives()
|
||||||
DRIVE = input("Enter the drive to use for USB (e.g., /dev/sda) [Default: /dev/sda]: ") or "/dev/sda"
|
log("\n⚠️ WARNING: This will repartition and format the selected drive.")
|
||||||
|
log("Make sure you select the correct device!")
|
||||||
|
|
||||||
confirm = input(f"\nYou have selected {DRIVE}. Is this correct? (y/n) [Default: y]: ") or "y"
|
while True:
|
||||||
if confirm.lower() != "y":
|
DRIVE = input("\nEnter the drive to use (e.g., /dev/sdb): ")
|
||||||
log("Drive selection canceled. Exiting.")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
log("\n" + "="*70)
|
if not DRIVE:
|
||||||
log("STEP 2: PREPARING DRIVE")
|
log("Error: No drive specified. Please enter a drive path.")
|
||||||
log("="*70)
|
continue
|
||||||
prepare_drive(DRIVE)
|
|
||||||
|
# Check if drive exists
|
||||||
|
if not os.path.exists(DRIVE):
|
||||||
|
log(f"Error: Drive {DRIVE} does not exist!")
|
||||||
|
log("Please check the available drives listed above and try again.")
|
||||||
|
retry = input("Try again? (y/n) [Default: y]: ") or "y"
|
||||||
|
if retry.lower() != "y":
|
||||||
|
log("Drive selection canceled. Exiting.")
|
||||||
|
sys.exit(1)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Check if it's a block device
|
||||||
|
if not os.path.isdir(DRIVE) and not os.path.exists(DRIVE):
|
||||||
|
log(f"Error: {DRIVE} is not a valid block device!")
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Confirm selection - more accurate warning
|
||||||
|
log(f"\nYou selected: {DRIVE}")
|
||||||
|
log("The script will:")
|
||||||
|
log(" • Clear partition table")
|
||||||
|
log(" • Create new partitions")
|
||||||
|
log(" • Optionally wipe (you'll be asked)")
|
||||||
|
log(" • Format with new filesystems")
|
||||||
|
confirm = input(f"\nProceed with {DRIVE}? (yes/no) [Default: no]: ")
|
||||||
|
if confirm.lower() == "yes":
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
log("Drive selection canceled.")
|
||||||
|
retry = input("Select a different drive? (y/n) [Default: y]: ") or "y"
|
||||||
|
if retry.lower() != "y":
|
||||||
|
log("Exiting.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
log("\n" + "="*70)
|
||||||
|
log("STEP 2: PREPARING DRIVE")
|
||||||
|
log("="*70)
|
||||||
|
prepare_drive(DRIVE)
|
||||||
|
save_state("DRIVE_SELECTED")
|
||||||
|
else:
|
||||||
|
log(f"✓ Skipping drive selection (already selected: {DRIVE})")
|
||||||
|
|
||||||
if CREATE_KALI or CREATE_TAILS or CREATE_DOCS:
|
if CREATE_KALI or CREATE_TAILS or CREATE_DOCS:
|
||||||
log("\n" + "="*70)
|
log("\n" + "="*70)
|
||||||
@@ -477,19 +645,19 @@ def setup_usb():
|
|||||||
if iso_written:
|
if iso_written:
|
||||||
if CREATE_KALI or CREATE_CUSTOM:
|
if CREATE_KALI or CREATE_CUSTOM:
|
||||||
# Both Kali and custom ISOs use the same partitioning approach
|
# Both Kali and custom ISOs use the same partitioning approach
|
||||||
fix_partition_table()
|
fix_partition_table(veracrypt_dir)
|
||||||
elif CREATE_TAILS:
|
elif CREATE_TAILS:
|
||||||
if CREATE_DOCS:
|
if CREATE_DOCS:
|
||||||
# For Tails with docs, add partitions after Tails
|
# For Tails with docs, add partitions after Tails
|
||||||
fix_partition_table_tails()
|
fix_partition_table_tails(veracrypt_dir)
|
||||||
else:
|
else:
|
||||||
# Tails only, no additional partitions
|
# Tails only, no additional partitions
|
||||||
log("Tails installation complete. No additional partitions requested.")
|
log("Tails installation complete. No additional partitions requested.")
|
||||||
elif CREATE_DOCS:
|
elif CREATE_DOCS:
|
||||||
# If no ISO was written, just set up documents partition
|
# If no ISO was written, just set up documents partition
|
||||||
fix_partition_table_docs_only()
|
fix_partition_table_docs_only(veracrypt_dir)
|
||||||
|
|
||||||
def fix_partition_table_docs_only():
|
def fix_partition_table_docs_only(veracrypt_dir=None):
|
||||||
"""
|
"""
|
||||||
Sets up partitions solely for encrypted documents without altering existing OS partitions.
|
Sets up partitions solely for encrypted documents without altering existing OS partitions.
|
||||||
"""
|
"""
|
||||||
@@ -562,7 +730,7 @@ def fix_partition_table_docs_only():
|
|||||||
setup_unencrypted_partition(veracrypt_dir)
|
setup_unencrypted_partition(veracrypt_dir)
|
||||||
setup_docs_partition()
|
setup_docs_partition()
|
||||||
|
|
||||||
def fix_partition_table_tails():
|
def fix_partition_table_tails(veracrypt_dir=None):
|
||||||
"""
|
"""
|
||||||
Adds encrypted documents partition after Tails installation without breaking boot.
|
Adds encrypted documents partition after Tails installation without breaking boot.
|
||||||
Tails creates its own partition table, so we extend it carefully.
|
Tails creates its own partition table, so we extend it carefully.
|
||||||
@@ -655,7 +823,7 @@ def fix_partition_table_tails():
|
|||||||
|
|
||||||
log("Tails + encrypted documents partition setup complete!")
|
log("Tails + encrypted documents partition setup complete!")
|
||||||
|
|
||||||
def fix_partition_table():
|
def fix_partition_table(veracrypt_dir=None):
|
||||||
"""
|
"""
|
||||||
Fixes the partition table for Kali Linux by adding persistence and documents partitions.
|
Fixes the partition table for Kali Linux by adding persistence and documents partitions.
|
||||||
"""
|
"""
|
||||||
@@ -888,7 +1056,7 @@ def setup_docs_partition():
|
|||||||
|
|
||||||
log("\nStarting VeraCrypt encryption (this may take a few minutes)...")
|
log("\nStarting VeraCrypt encryption (this may take a few minutes)...")
|
||||||
log("="*70)
|
log("="*70)
|
||||||
log("VERACRYPT WILL ASK YOU THESE QUESTIONS:")
|
log("VERACRYPT PROMPTS - FOLLOW THESE STEPS:")
|
||||||
log("="*70)
|
log("="*70)
|
||||||
log("")
|
log("")
|
||||||
log("1. 'Enter password:' → Type your strong password (20+ characters)")
|
log("1. 'Enter password:' → Type your strong password (20+ characters)")
|
||||||
@@ -897,18 +1065,16 @@ def setup_docs_partition():
|
|||||||
log("2. 'Re-enter password:' → Type the SAME password again")
|
log("2. 'Re-enter password:' → Type the SAME password again")
|
||||||
log(" Then press ENTER")
|
log(" Then press ENTER")
|
||||||
log("")
|
log("")
|
||||||
log("3. 'Enter PIM:' → Just press ENTER")
|
log("3. 'Enter keyfile path [none]:' → Just press ENTER")
|
||||||
log(f" (We're using PIM {pim_value} automatically)")
|
|
||||||
log("")
|
|
||||||
log("4. 'Enter keyfile path [none]:' → Just press ENTER")
|
|
||||||
log(" (Keyfiles not needed for most users)")
|
log(" (Keyfiles not needed for most users)")
|
||||||
log("")
|
log("")
|
||||||
log("5. 'Please type at least 320 randomly chosen characters'")
|
log("4. 'Please type at least 320 randomly chosen characters'")
|
||||||
log(" → Smash random keys on your keyboard until it says 'Done'")
|
log(" → Smash random keys on your keyboard")
|
||||||
log(" This creates entropy for encryption")
|
log(" → Keep typing until it shows 'Characters remaining: 0'")
|
||||||
|
log(" → Then press ENTER")
|
||||||
|
log(" (This creates random entropy for encryption)")
|
||||||
log("")
|
log("")
|
||||||
log("6. 'Protect hidden volume (if any)? (y=Yes/n=No) [No]:' → Type: n")
|
log(f"ℹ️ NOTE: PIM is set to {pim_value} automatically (not prompted)")
|
||||||
log(" Then press ENTER (we're not using hidden volumes)")
|
|
||||||
log("")
|
log("")
|
||||||
log("="*70)
|
log("="*70)
|
||||||
log("Creating volume now...")
|
log("Creating volume now...")
|
||||||
@@ -920,6 +1086,7 @@ def setup_docs_partition():
|
|||||||
log(f" Hash: SHA-512")
|
log(f" Hash: SHA-512")
|
||||||
log(f" PIM: {pim_value}")
|
log(f" PIM: {pim_value}")
|
||||||
log(f" Filesystem: ext4")
|
log(f" Filesystem: ext4")
|
||||||
|
save_state("DOCS_ENCRYPTED")
|
||||||
|
|
||||||
def setup_unencrypted_partition(veracrypt_dir=None):
|
def setup_unencrypted_partition(veracrypt_dir=None):
|
||||||
"""
|
"""
|
||||||
@@ -1028,6 +1195,7 @@ def setup_unencrypted_partition(veracrypt_dir=None):
|
|||||||
log("\nUnmounting tools partition...")
|
log("\nUnmounting tools partition...")
|
||||||
run_command("sudo umount /mnt/unencrypted", shell=True)
|
run_command("sudo umount /mnt/unencrypted", shell=True)
|
||||||
log("✓ Tools partition setup complete")
|
log("✓ Tools partition setup complete")
|
||||||
|
save_state("TOOLS_SETUP")
|
||||||
|
|
||||||
def get_last_partition_number():
|
def get_last_partition_number():
|
||||||
"""
|
"""
|
||||||
@@ -1081,12 +1249,68 @@ def main():
|
|||||||
parser.add_argument("--fast", action="store_true", help="Enable fast setup with less secure encryption")
|
parser.add_argument("--fast", action="store_true", help="Enable fast setup with less secure encryption")
|
||||||
parser.add_argument("--paranoid", action="store_true", help="Enable paranoid mode: maximum security, 3-pass shred, highest encryption")
|
parser.add_argument("--paranoid", action="store_true", help="Enable paranoid mode: maximum security, 3-pass shred, highest encryption")
|
||||||
parser.add_argument("--debug", action="store_true", help="Enable debug mode")
|
parser.add_argument("--debug", action="store_true", help="Enable debug mode")
|
||||||
|
parser.add_argument("-r", "--resume", action="store_true", help="Resume from previous incomplete setup")
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# Prevent using -a with -t; argparse handles this due to mutually exclusive group
|
# Prevent using -a with -t; argparse handles this due to mutually exclusive group
|
||||||
# However, if you want to provide a custom error message or additional handling, you can add it here
|
# However, if you want to provide a custom error message or additional handling, you can add it here
|
||||||
|
|
||||||
|
# Handle resume flag
|
||||||
|
if args.resume:
|
||||||
|
previous_state = load_state()
|
||||||
|
if previous_state:
|
||||||
|
log("\n" + "="*70)
|
||||||
|
log("🔄 RESUMING PREVIOUS SETUP")
|
||||||
|
log("="*70)
|
||||||
|
log("")
|
||||||
|
log("Found incomplete setup from previous run:")
|
||||||
|
log(f" Drive: {previous_state.get('drive', 'Unknown')}")
|
||||||
|
log(f" Started: {previous_state.get('timestamp', 'Unknown')}")
|
||||||
|
log("")
|
||||||
|
log("Completed steps:")
|
||||||
|
for checkpoint, completed in previous_state.get('checkpoints', {}).items():
|
||||||
|
status = "✓" if completed else "✗"
|
||||||
|
log(f" {status} {checkpoint}")
|
||||||
|
log("")
|
||||||
|
log("✓ Resuming from last checkpoint...")
|
||||||
|
log(f"Continuing log in: {LOG_FILE}")
|
||||||
|
log("")
|
||||||
|
# State already loaded by load_state()
|
||||||
|
# Skip to setup_usb() - it will check checkpoints
|
||||||
|
check_dependencies()
|
||||||
|
setup_usb()
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
log("Error: No previous setup found to resume.")
|
||||||
|
log("State file not found at: /tmp/covert_sd_state.json")
|
||||||
|
log("")
|
||||||
|
log("To start a new setup, run without --resume flag:")
|
||||||
|
log(" sudo ./covert_sd_card_tool.py -d -a -t /path/to/tails.iso")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Check if state exists but user didn't use --resume flag
|
||||||
|
previous_state = load_state()
|
||||||
|
if previous_state:
|
||||||
|
log("\n" + "="*70)
|
||||||
|
log("⚠️ PREVIOUS INCOMPLETE SETUP FOUND")
|
||||||
|
log("="*70)
|
||||||
|
log("")
|
||||||
|
log(f"Drive: {previous_state.get('drive', 'Unknown')}")
|
||||||
|
log(f"Started: {previous_state.get('timestamp', 'Unknown')}")
|
||||||
|
log("")
|
||||||
|
log("You have two options:")
|
||||||
|
log(" 1. Resume previous setup: sudo ./covert_sd_card_tool.py --resume")
|
||||||
|
log(" 2. Start fresh (WARNING: will overwrite any existing setup)")
|
||||||
|
log("")
|
||||||
|
choice = input("Continue with fresh setup? (yes/no) [Default: no]: ") or "no"
|
||||||
|
if choice.lower() != "yes":
|
||||||
|
log("Exiting. Use --resume flag to continue previous setup.")
|
||||||
|
sys.exit(0)
|
||||||
|
else:
|
||||||
|
log("Starting fresh setup (old state will be cleared)...")
|
||||||
|
clear_state()
|
||||||
|
|
||||||
if not any([args.all, args.kali, args.docs, args.tails, args.custom]):
|
if not any([args.all, args.kali, args.docs, args.tails, args.custom]):
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
@@ -1164,7 +1388,21 @@ def main():
|
|||||||
log("")
|
log("")
|
||||||
|
|
||||||
log(f"Log file saved: {LOG_FILE}")
|
log(f"Log file saved: {LOG_FILE}")
|
||||||
|
log("")
|
||||||
|
if CREATE_DOCS and os.path.exists("/tmp/veracrypt_download"):
|
||||||
|
cache_size = sum(os.path.getsize(os.path.join("/tmp/veracrypt_download", f))
|
||||||
|
for f in os.listdir("/tmp/veracrypt_download")
|
||||||
|
if os.path.isfile(os.path.join("/tmp/veracrypt_download", f))) / (1024 * 1024)
|
||||||
|
log("💡 TIP: VeraCrypt downloads cached at /tmp/veracrypt_download")
|
||||||
|
log(f" Size: {cache_size:.1f} MB")
|
||||||
|
log(" Next SD card creation will skip downloads!")
|
||||||
|
log(" To clean up: rm -rf /tmp/veracrypt_download")
|
||||||
|
log("")
|
||||||
log("="*70)
|
log("="*70)
|
||||||
|
|
||||||
|
# Mark as complete and clear state file
|
||||||
|
save_state("COMPLETE")
|
||||||
|
clear_state()
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
main()
|
main()
|
||||||
|
|||||||
Reference in New Issue
Block a user