1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
| import tarfile import os import sys import re import argparse
BACKUP_BASE_DIR = "/opt/backup_clients/backups" STAGING_BASE = "/opt/backup_clients/restored_backups"
def validate_backup_name(filename): if not re.fullmatch(r"^backup_\d+\.tar$", filename): return False client_id = filename.split('_')[1].rstrip('.tar') return client_id.isdigit() and client_id != "0"
def validate_restore_tag(tag): return bool(re.fullmatch(r"^[a-zA-Z0-9_]{1,24}$", tag))
def main(): parser = argparse.ArgumentParser( description="Restore client configuration from a validated backup tarball.", epilog="Example: sudo %(prog)s -b backup_1001.tar -r restore_john" ) parser.add_argument( "-b", "--backup", required=True, help="Backup filename (must be in /home/wacky/backup_clients/ and match backup_<client_id>.tar, " "where <client_id> is a positive integer, e.g., backup_1001.tar)" ) parser.add_argument( "-r", "--restore-dir", required=True, help="Staging directory name for the restore operation. " "Must follow the format: restore_<client_user> (e.g., restore_john). " "Only alphanumeric characters and underscores are allowed in the <client_user> part (1–24 characters)." )
args = parser.parse_args()
if not validate_backup_name(args.backup): print("[!] Invalid backup name. Expected format: backup_<client_id>.tar (e.g., backup_1001.tar)", file=sys.stderr) sys.exit(1)
backup_path = os.path.join(BACKUP_BASE_DIR, args.backup) if not os.path.isfile(backup_path): print(f"[!] Backup file not found: {backup_path}", file=sys.stderr) sys.exit(1)
if not args.restore_dir.startswith("restore_"): print("[!] --restore-dir must start with 'restore_'", file=sys.stderr) sys.exit(1)
tag = args.restore_dir[8:] if not tag: print("[!] --restore-dir must include a non-empty tag after 'restore_'", file=sys.stderr) sys.exit(1)
if not validate_restore_tag(tag): print("[!] Restore tag must be 1–24 characters long and contain only letters, digits, or underscores", file=sys.stderr) sys.exit(1)
staging_dir = os.path.join(STAGING_BASE, args.restore_dir) print(f"[+] Backup: {args.backup}") print(f"[+] Staging directory: {staging_dir}")
os.makedirs(staging_dir, exist_ok=True)
try: with tarfile.open(backup_path, "r") as tar: tar.extractall(path=staging_dir, filter="data") print(f"[+] Extraction completed in {staging_dir}") except (tarfile.TarError, OSError, Exception) as e: print(f"[!] Error during extraction: {e}", file=sys.stderr) sys.exit(2)
if __name__ == "__main__": main()
|