From fe7e7ec31a182e586625abe9504cdf4d569be6ca Mon Sep 17 00:00:00 2001 From: wpa-2 <9049886+wpa-2@users.noreply.github.com> Date: Sun, 2 Feb 2025 19:34:51 +0000 Subject: [PATCH 1/6] Backup and restore edits Windows and linux files Signed-off-by: wpa-2 <9049886+wpa-2@users.noreply.github.com> --- scripts/BR.bat | 171 ++++++++++++++++++++++++++++++++++++++++++ scripts/BR.sh | 197 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 368 insertions(+) create mode 100644 scripts/BR.bat create mode 100644 scripts/BR.sh diff --git a/scripts/BR.bat b/scripts/BR.bat new file mode 100644 index 00000000..ed94a3b8 --- /dev/null +++ b/scripts/BR.bat @@ -0,0 +1,171 @@ +@echo off +setlocal + +REM --------------------------------------------------------------------------- +REM A simple .bat script that handles two subcommands: "backup" and "restore" +REM USAGE: +REM backup-restore.bat backup [ -n HOST ] [ -u USER ] [ -o OUTPUT ] +REM backup-restore.bat restore [ -n HOST ] [ -u USER ] [ -b BACKUP_FILE ] +REM --------------------------------------------------------------------------- + +set "SCRIPTNAME=%~0" + +REM --------------------------------------------------------------------------- +REM If no arguments, show usage +if "%~1"=="" goto usage + +REM First argument is the subcommand: "backup" or "restore" +set "SUBCOMMAND=%~1" +shift + +REM Default values +set "UNIT_HOSTNAME=10.0.0.2" +set "UNIT_USERNAME=pi" +set "OUTPUT=" +set "BACKUP_FILE=" + +:parse_args +if "%~1"=="" goto done_args + +if "%~1"=="-n" ( + set "UNIT_HOSTNAME=%~2" + shift + shift + goto parse_args +) + +if "%~1"=="-u" ( + set "UNIT_USERNAME=%~2" + shift + shift + goto parse_args +) + +if "%SUBCOMMAND%"=="backup" ( + if "%~1"=="-o" ( + set "OUTPUT=%~2" + shift + shift + goto parse_args + ) +) + +if "%SUBCOMMAND%"=="restore" ( + if "%~1"=="-b" ( + set "BACKUP_FILE=%~2" + shift + shift + goto parse_args + ) +) + +echo "Unknown or invalid argument: %~1" +goto usage + +:done_args + +REM --------------------------------------------------------------------------- +REM Subcommand routing +if "%SUBCOMMAND%"=="backup" goto do_backup +if "%SUBCOMMAND%"=="restore" goto do_restore +goto usage + +REM =========================================================================== +:do_backup +REM If OUTPUT not specified, generate a name like HOST-backup-RANDOM.tgz +if "%OUTPUT%"=="" ( + set /a RAND=%random% + set "OUTPUT=%UNIT_HOSTNAME%-backup-%RAND%.tgz" +) + +echo @ Checking connectivity to %UNIT_HOSTNAME% ... +ping -n 1 %UNIT_HOSTNAME% >nul 2>&1 +if errorlevel 1 ( + echo @ unit %UNIT_HOSTNAME% can't be reached. + exit /b 1 +) + +echo @ Backing up %UNIT_HOSTNAME% to %OUTPUT% ... + +REM List of files to back up from the remote device: +set "FILES_TO_BACKUP=/root/settings.yaml /root/client_secrets.json /root/.ssh /root/.api-report.json /root/.bashrc /root/.profile /home/pi/handshakes /root/peers /etc/pwnagotchi/ /usr/local/share/pwnagotchi/custom-plugins /etc/ssh/ /home/pi/.bashrc /home/pi/.profile /home/pi/.wpa_sec_uploads" + +REM --------------------------------------------------------------------------- +REM We'll have the REMOTE do the tar + gzip (since Windows cmd lacks gzip) +REM so we capture the compressed stream directly into %OUTPUT% +REM --------------------------------------------------------------------------- +ssh %UNIT_USERNAME%@%UNIT_HOSTNAME% "sudo tar -cf - %FILES_TO_BACKUP% | gzip -9" > "%OUTPUT%" +if errorlevel 1 ( + echo @ Backup failed + exit /b 1 +) + +echo @ Backup finished. Archive: %OUTPUT% +exit /b 0 + +REM =========================================================================== +:do_restore +if "%BACKUP_FILE%"=="" ( + REM If user didn't specify -b, try to find the latest *.tgz with the hostname prefix + for /f "delims=" %%A in ('dir /b /a-d /O-D "%UNIT_HOSTNAME%-backup-*.tgz" 2^>nul') do ( + set "BACKUP_FILE=%%A" + goto found_file + ) + echo @ Can't find backup file. Please specify one with '-b'. + exit /b 1 + +:found_file + echo @ Found backup file: %BACKUP_FILE% + set /p CONTINUE="@ Continue restoring this file? (y/n) " + if /i "%CONTINUE%"=="y" ( + echo (continuing...) + ) else ( + exit /b 1 + ) +) + +echo @ Checking connectivity to %UNIT_HOSTNAME% ... +ping -n 1 %UNIT_HOSTNAME% > nul 2>&1 +if errorlevel 1 ( + echo @ unit %UNIT_HOSTNAME% can't be reached. + exit /b 1 +) + +echo @ Restoring %BACKUP_FILE% to %UNIT_HOSTNAME% ... + +REM We'll send the local file contents over SSH; the remote will do tar xzv +type "%BACKUP_FILE%" | ssh %UNIT_USERNAME%@%UNIT_HOSTNAME% "tar xzv -C /" +if errorlevel 1 ( + echo @ Restore failed. + exit /b 1 +) + +echo @ Restore finished. +exit /b 0 + +REM =========================================================================== +:usage +echo Usage: +echo %SCRIPTNAME% backup [ -n HOST ] [ -u USER ] [ -o OUTPUT ] +echo %SCRIPTNAME% restore [ -n HOST ] [ -u USER ] [ -b BACKUP_FILE ] +echo. +echo Subcommands: +echo backup Backup files from the remote device. +echo restore Restore files to the remote device. +echo. +echo Common Options: +echo -n HOST Hostname or IP of remote device (default: 10.0.0.2) +echo -u USER Username for SSH (default: pi) +echo. +echo Options for 'backup': +echo -o OUTPUT Path/name of the output archive (default: HOST-backup-RANDOM.tgz) +echo. +echo Options for 'restore': +echo -b BACKUP Path to the local backup archive to restore. +echo. +echo Examples: +echo %SCRIPTNAME% backup +echo %SCRIPTNAME% backup -n 10.0.0.2 -u pi -o my-backup.tgz +echo %SCRIPTNAME% restore -b my-backup.tgz +echo. +exit /b 1 diff --git a/scripts/BR.sh b/scripts/BR.sh new file mode 100644 index 00000000..79b4233d --- /dev/null +++ b/scripts/BR.sh @@ -0,0 +1,197 @@ +#!/usr/bin/env bash +# +# A Combined backup/restore script for linux +# Usage: +# backup-restore.sh backup [ -n HOST ] [ -u USER ] [ -o OUTPUT ] +# backup-restore.sh restore [ -n HOST ] [ -u USER ] [ -b BACKUP_FILE ] +# + +############################################################################### +# GLOBAL USAGE +############################################################################### +usage() { + echo "Usage:" + echo " $0 backup [ -n HOST ] [ -u USER ] [ -o OUTPUT ]" + echo " $0 restore [ -n HOST ] [ -u USER ] [ -b BACKUP_FILE ]" + echo + echo "Subcommands:" + echo " backup Backup files from the remote device." + echo " restore Restore files to the remote device." + echo + echo "Common Options:" + echo " -n HOST Hostname or IP of remote device (default: 10.0.0.2)" + echo " -u USER Username for SSH (default: pi)" + echo + echo "Options for 'backup':" + echo " -o OUTPUT Path/name of the output archive (default: \$HOST-backup-\$(date +%s).tgz)" + echo + echo "Options for 'restore':" + echo " -b BACKUP Path to the local backup archive to restore." + echo + echo "Examples:" + echo " $0 backup" + echo " $0 backup -n 10.0.0.2 -u pi -o my-backup.tgz" + echo " $0 restore -b 10.0.0.2-backup-123456789.tgz" + echo +} + +############################################################################### +# BACKUP FUNCTION +############################################################################### +do_backup() { + # Defaults + UNIT_HOSTNAME="10.0.0.2" + UNIT_USERNAME="pi" + OUTPUT="" + + # Parse arguments specific to backup + while getopts "hn:u:o:" arg; do + case $arg in + h) + usage + exit 0 + ;; + n) + UNIT_HOSTNAME=$OPTARG + ;; + u) + UNIT_USERNAME=$OPTARG + ;; + o) + OUTPUT=$OPTARG + ;; + *) + usage + exit 1 + ;; + esac + done + + # If OUTPUT was not specified, set a default + if [[ -z "$OUTPUT" ]]; then + OUTPUT="${UNIT_HOSTNAME}-backup-$(date +%s).tgz" + fi + + # List of files/directories to backup + # (the same list you used in your backup.sh script) + FILES_TO_BACKUP=" +/root/settings.yaml +/root/client_secrets.json +/root/.api-report.json +/root/.ssh +/root/.bashrc +/root/.profile +/home/pi/handshakes +/root/peers +/etc/pwnagotchi/ +/usr/local/share/pwnagotchi/custom-plugins +/etc/ssh/ +/home/pi/.bashrc +/home/pi/.profile +/home/pi/.wpa_sec_uploads +" + # Convert multiline variable into a space-separated list + FILES_TO_BACKUP=$(echo "$FILES_TO_BACKUP" | tr '\n' ' ') + + echo "@ Checking connectivity to $UNIT_HOSTNAME ..." + if ! ping -c 1 "$UNIT_HOSTNAME" &>/dev/null; then + echo "@ unit ${UNIT_HOSTNAME} can't be reached, check network or USB interface IP." + exit 1 + fi + + echo "@ Backing up ${UNIT_HOSTNAME} to ${OUTPUT} ..." + # -n => do not read from stdin + ssh -n "${UNIT_USERNAME}@${UNIT_HOSTNAME}" \ + "sudo tar -cf - ${FILES_TO_BACKUP}" \ + | gzip -9 > "${OUTPUT}" + + echo "@ Backup finished. Archive: ${OUTPUT}" +} + +############################################################################### +# RESTORE FUNCTION +############################################################################### +do_restore() { + # Defaults + UNIT_HOSTNAME="10.0.0.2" + UNIT_USERNAME="pi" + BACKUP_FILE="" + + # Parse arguments specific to restore + while getopts "hn:u:b:" arg; do + case $arg in + h) + usage + exit 0 + ;; + n) + UNIT_HOSTNAME=$OPTARG + ;; + u) + UNIT_USERNAME=$OPTARG + ;; + b) + BACKUP_FILE=$OPTARG + ;; + *) + usage + exit 1 + ;; + esac + done + + # If no backup file given, try to find the latest + if [[ -z "$BACKUP_FILE" ]]; then + BACKUP_FILE=$(ls -rt "${UNIT_HOSTNAME}"-backup-*.tgz 2>/dev/null | tail -n1) + if [[ -z "$BACKUP_FILE" ]]; then + echo "@ Can't find backup file. Please specify one with '-b'." + exit 1 + fi + echo "@ Found backup file: $BACKUP_FILE" + echo -n "@ Continue restoring this file? (y/n) " + read -r CONTINUE + CONTINUE=$(echo "${CONTINUE}" | tr "[:upper:]" "[:lower:]") + if [[ "${CONTINUE}" != "y" ]]; then + exit 1 + fi + fi + + echo "@ Checking connectivity to $UNIT_HOSTNAME ..." + if ! ping -c 1 "$UNIT_HOSTNAME" &>/dev/null; then + echo "@ unit ${UNIT_HOSTNAME} can't be reached, make sure it's connected and a static IP assigned." + exit 1 + fi + + echo "@ Restoring $BACKUP_FILE to $UNIT_HOSTNAME ..." + cat "${BACKUP_FILE}" | ssh "${UNIT_USERNAME}@${UNIT_HOSTNAME}" "sudo tar xzv -C /" + + echo "@ Restore finished." +} + +############################################################################### +# MAIN ENTRY POINT +############################################################################### +# We expect the first argument to be either 'backup', 'restore', or '-h'. +SUBCOMMAND=$1 +if [[ -z "$SUBCOMMAND" ]]; then + usage + exit 1 +fi +shift # Shift past subcommand + +case "$SUBCOMMAND" in + backup) + do_backup "$@" + ;; + restore) + do_restore "$@" + ;; + -h|--help) + usage + exit 0 + ;; + *) + usage + exit 1 + ;; +esac From a54579cf3d27a288e342f94eb783c627bf078406 Mon Sep 17 00:00:00 2001 From: wpa-2 <9049886+wpa-2@users.noreply.github.com> Date: Sun, 2 Feb 2025 19:35:51 +0000 Subject: [PATCH 2/6] Delete scripts/backup.sh Signed-off-by: wpa-2 <9049886+wpa-2@users.noreply.github.com> --- scripts/backup.sh | 67 ----------------------------------------------- 1 file changed, 67 deletions(-) delete mode 100755 scripts/backup.sh diff --git a/scripts/backup.sh b/scripts/backup.sh deleted file mode 100755 index b41d4690..00000000 --- a/scripts/backup.sh +++ /dev/null @@ -1,67 +0,0 @@ -#!/bin/sh - -usage() { - echo "Usage: backup.sh [-honu] [-h] [-u user] [-n host name or ip] [-o output]" -} - -while getopts "ho:n:u:" arg; do - case $arg in - h) - usage - exit - ;; - n) - UNIT_HOSTNAME=$OPTARG - ;; - o) - OUTPUT=$OPTARG - ;; - u) - UNIT_USERNAME=$OPTARG - ;; - *) - usage - exit 1 - esac -done - -# name of the ethernet gadget interface on the host -UNIT_HOSTNAME=${UNIT_HOSTNAME:-10.0.0.2} -# output backup tgz file -OUTPUT=${OUTPUT:-${UNIT_HOSTNAME}-backup-$(date +%s).tgz} -# username to use for ssh -UNIT_USERNAME=${UNIT_USERNAME:-pi} -# what to backup -FILES_TO_BACKUP="/boot/firmware/cmdline.txt \ - /boot/firmware/config.txt \ - /root/settings.yaml \ - /root/client_secrets.json \ - /root/.api-report.json \ - /root/.ssh \ - /root/.bashrc \ - /root/.profile \ - /home/pi/handshakes \ - /root/peers \ - /etc/modprobe.d/g_ether.conf \ - /etc/pwnagotchi/ \ - /etc/ssh/ \ - /etc/pwnagotchi/log/pwnagotchi.log \ - /etc/pwnagotchi/log/pwnagotchi*.gz \ - /home/pi/.ssh \ - /home/pi/.bashrc \ - /home/pi/.profile \ - /root/.api-report.json \ - /root/.auto-update \ - /root/.bt-tether* \ - /root/.ohc_uploads \ - /root/.wigle_uploads \ - /home/pi/.wpa_sec_uploads" - -ping -c 1 "${UNIT_HOSTNAME}" > /dev/null 2>&1 || { - echo "@ unit ${UNIT_HOSTNAME} can't be reached, make sure it's connected and a static IP assigned to the USB interface." - exit 1 -} - -echo "@ backing up $UNIT_HOSTNAME to $OUTPUT ..." -# shellcheck disable=SC2029 -ssh "${UNIT_USERNAME}@${UNIT_HOSTNAME}" "sudo find ${FILES_TO_BACKUP} -type f -print0 | xargs -0 sudo tar cv" | gzip -9 > "$OUTPUT" From ef0680a14018a50d9f0cbbd2b3b7afdad5c81487 Mon Sep 17 00:00:00 2001 From: wpa-2 <9049886+wpa-2@users.noreply.github.com> Date: Sun, 2 Feb 2025 19:36:01 +0000 Subject: [PATCH 3/6] Delete scripts/restore.sh Signed-off-by: wpa-2 <9049886+wpa-2@users.noreply.github.com> --- scripts/restore.sh | 60 ---------------------------------------------- 1 file changed, 60 deletions(-) delete mode 100755 scripts/restore.sh diff --git a/scripts/restore.sh b/scripts/restore.sh deleted file mode 100755 index b805a01a..00000000 --- a/scripts/restore.sh +++ /dev/null @@ -1,60 +0,0 @@ -#!/bin/sh - -usage() { - echo "Usage: restore.sh [-bhnu] [-h] [-b backup name] [-n host name] [-u user name]" -} - -while getopts "hb:n:u:" arg; do - case $arg in - b) - BACKUP=$OPTARG - ;; - h) - usage - exit - ;; - n) - UNIT_HOSTNAME=$OPTARG - ;; - u) - UNIT_USERNAME=$OPTARG - ;; - *) - usage - exit 1 - esac -done -# name of the ethernet gadget interface on the host -UNIT_HOSTNAME=${UNIT_HOSTNAME:-10.0.0.2} -# output backup tgz file -# shellcheck disable=SC2086 -if [ -z $BACKUP ]; then - # shellcheck disable=SC2012 - BACKUP=$(ls -rt "${UNIT_HOSTNAME}"-backup-*.tgz 2>/dev/null | tail -n1) - if [ -z "$BACKUP" ]; then - echo "@ Can't find backup file. Please specify one with '-b'" - exit 1 - fi - echo "@ Found backup file:" - # shellcheck disable=SC2028 - echo "\t${BACKUP}" - # shellcheck disable=SC2039 - echo -n "@ continue restroring this file? (y/n) " - # shellcheck disable=SC2162 - read CONTINUE - CONTINUE=$(echo "${CONTINUE}" | tr "[:upper:]" "[:lower:]") - if [ "${CONTINUE}" != "y" ]; then - exit 1 - fi -fi -# username to use for ssh -UNIT_USERNAME=${UNIT_USERNAME:-pi} - -ping -c 1 "${UNIT_HOSTNAME}" > /dev/null 2>&1 || { - echo "@ unit ${UNIT_HOSTNAME} can't be reached, make sure it's connected and a static IP assigned to the USB interface." - exit 1 -} - -echo "@ restoring $BACKUP to $UNIT_HOSTNAME ..." -# shellcheck disable=SC2002 -cat "${BACKUP}" | ssh "${UNIT_USERNAME}@${UNIT_HOSTNAME}" "sudo tar xzv -C /" From 67e28fa7ab095b93fd4eb7ef6af323d2009738e2 Mon Sep 17 00:00:00 2001 From: wpa-2 <9049886+wpa-2@users.noreply.github.com> Date: Mon, 24 Feb 2025 16:20:02 +0000 Subject: [PATCH 4/6] Update defaults.toml Signed-off-by: wpa-2 <9049886+wpa-2@users.noreply.github.com> --- pwnagotchi/defaults.toml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/pwnagotchi/defaults.toml b/pwnagotchi/defaults.toml index 15820132..012bf951 100644 --- a/pwnagotchi/defaults.toml +++ b/pwnagotchi/defaults.toml @@ -18,6 +18,27 @@ main.custom_plugin_repos = [ main.custom_plugins = "/usr/local/share/pwnagotchi/custom-plugins/" +main.plugins.auto_backup.enabled = true +main.plugins.auto_backup.interval = "daily" # or "hourly", or a number (minutes) +main.plugins.auto_backup.max_tries = 0 +main.plugins.auto_backup.backup_location = "/home/pi/" +main.plugins.auto_backup.files = [ + "/root/settings.yaml", + "/root/client_secrets.json", + "/root/.api-report.json", + "/root/.ssh", + "/root/.bashrc", + "/root/.profile", + "/home/pi/handshakes", + "/root/peers", + "/etc/pwnagotchi/", + "/usr/local/share/pwnagotchi/custom-plugins", + "/etc/ssh/", + "/home/pi/.bashrc", + "/home/pi/.profile", + "/home/pi/.wpa_sec_uploads", +] + main.plugins.auto-tune.enabled = true main.plugins.auto-update.enabled = true From 87730543d1635e8380db85556bf6e7a742c1eb47 Mon Sep 17 00:00:00 2001 From: wpa-2 <9049886+wpa-2@users.noreply.github.com> Date: Mon, 24 Feb 2025 16:20:27 +0000 Subject: [PATCH 5/6] Add files via upload Signed-off-by: wpa-2 <9049886+wpa-2@users.noreply.github.com> --- pwnagotchi/plugins/default/auto_backup.py | 146 ++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 pwnagotchi/plugins/default/auto_backup.py diff --git a/pwnagotchi/plugins/default/auto_backup.py b/pwnagotchi/plugins/default/auto_backup.py new file mode 100644 index 00000000..cd381b0b --- /dev/null +++ b/pwnagotchi/plugins/default/auto_backup.py @@ -0,0 +1,146 @@ +import pwnagotchi.plugins as plugins +from pwnagotchi.utils import StatusFile +import logging +import os +import subprocess +import time +import socket + +class AutoBackup(plugins.Plugin): + __author__ = 'WPA2' + __version__ = '1.1.1' + __license__ = 'GPL3' + __description__ = 'Backs up files when internet is available, using new file list and options.' + + def __init__(self): + self.ready = False + self.tries = 0 + # Used to throttle repeated log messages for "backup not due yet" + self.last_not_due_logged = 0 + # Store the status file path separately. + self.status_file = '/root/.auto-backup' + self.status = StatusFile(self.status_file) + + def on_loaded(self): + required_options = ['files', 'interval', 'backup_location', 'max_tries'] + for opt in required_options: + if opt not in self.options or self.options[opt] is None: + logging.error(f"AUTO-BACKUP: Option '{opt}' is not set.") + return + + # If no custom command(s) are provided, use the default plain tar command. + if 'commands' not in self.options or not self.options['commands']: + self.options['commands'] = ["tar cf {backup_file} {files}"] + # For a tar.gz archive, use: + # self.options['commands'] = ["tar czf {backup_file} {files}"] + + self.ready = True + logging.info("AUTO-BACKUP: Successfully loaded.") + + def get_interval_seconds(self): + """ + Convert the interval option into seconds. + Supports: + - "daily" for 24 hours, + - "hourly" for 60 minutes, + - or a numeric value (interpreted as minutes). + """ + interval = self.options['interval'] + if isinstance(interval, str): + if interval.lower() == "daily": + return 24 * 60 * 60 + elif interval.lower() == "hourly": + return 60 * 60 + else: + try: + minutes = float(interval) + return minutes * 60 + except ValueError: + logging.error("AUTO-BACKUP: Invalid interval format. Defaulting to daily interval.") + return 24 * 60 * 60 + elif isinstance(interval, (int, float)): + return float(interval) * 60 + else: + logging.error("AUTO-BACKUP: Unrecognized type for interval. Defaulting to daily interval.") + return 24 * 60 * 60 + + def is_backup_due(self): + """ + Determines if enough time has passed since the last backup. + If the status file does not exist, a backup is due. + """ + interval_sec = self.get_interval_seconds() + try: + last_backup = os.path.getmtime(self.status_file) + except OSError: + # Status file doesn't exist—backup is due. + return True + now = time.time() + return (now - last_backup) >= interval_sec + + def on_internet_available(self, agent): + if not self.ready: + return + + if self.options['max_tries'] and self.tries >= self.options['max_tries']: + logging.info("AUTO-BACKUP: Maximum tries reached, skipping backup.") + return + + if not self.is_backup_due(): + now = time.time() + # Log "backup not due" only once every 60 seconds + if now - self.last_not_due_logged > 60: + logging.info("AUTO-BACKUP: Backup not due yet based on the interval.") + self.last_not_due_logged = now + return + + # Only include files/directories that exist to prevent errors. + existing_files = list(filter(lambda f: os.path.exists(f), self.options['files'])) + if not existing_files: + logging.warning("AUTO-BACKUP: No files found to backup.") + return + files_to_backup = " ".join(existing_files) + + # Get the backup location from config. + backup_location = self.options['backup_location'] + + # Retrieve the global config from agent. If agent.config is callable, call it. + global_config = getattr(agent, 'config', None) + if callable(global_config): + global_config = global_config() + if global_config is None: + global_config = {} + pwnagotchi_name = global_config.get('main', {}).get('name', socket.gethostname()) + backup_file = os.path.join(backup_location, f"{pwnagotchi_name}-backup.tar") + + try: + display = agent.view() + logging.info("AUTO-BACKUP: Starting backup process...") + display.set('status', 'Backing up ...') + display.update() + + # Execute each backup command. + for cmd in self.options['commands']: + formatted_cmd = cmd.format(backup_file=backup_file, files=files_to_backup) + logging.info(f"AUTO-BACKUP: Running command: {formatted_cmd}") + process = subprocess.Popen( + formatted_cmd, + shell=True, + stdin=None, + stdout=open("/dev/null", "w"), + stderr=subprocess.STDOUT, + executable="/bin/bash" + ) + process.wait() + if process.returncode > 0: + raise OSError(f"Command failed with return code: {process.returncode}") + + logging.info(f"AUTO-BACKUP: Backup completed successfully. File created at {backup_file}") + display.set('status', 'Backup done!') + display.update() + self.status.update() + except OSError as os_e: + self.tries += 1 + logging.error(f"AUTO-BACKUP: Backup error: {os_e}") + display.set('status', 'Backup failed!') + display.update() From 27b9ec49da552e3d09927932cd366cd6747cdf41 Mon Sep 17 00:00:00 2001 From: wpa-2 <9049886+wpa-2@users.noreply.github.com> Date: Mon, 24 Feb 2025 16:20:59 +0000 Subject: [PATCH 6/6] Add files via upload Signed-off-by: wpa-2 <9049886+wpa-2@users.noreply.github.com> --- scripts/BR.bat | 89 +++++++++++++++++--------------------------------- 1 file changed, 30 insertions(+), 59 deletions(-) diff --git a/scripts/BR.bat b/scripts/BR.bat index ed94a3b8..3d3e94e8 100644 --- a/scripts/BR.bat +++ b/scripts/BR.bat @@ -8,17 +8,17 @@ REM backup-restore.bat backup [ -n HOST ] [ -u USER ] [ -o OUTPUT ] REM backup-restore.bat restore [ -n HOST ] [ -u USER ] [ -b BACKUP_FILE ] REM --------------------------------------------------------------------------- -set "SCRIPTNAME=%~0" +set "LOGFILE=%~dp0BR_GPT.log" +echo [INFO] Script started at %DATE% %TIME% > "%LOGFILE%" REM --------------------------------------------------------------------------- -REM If no arguments, show usage +REM Check for Arguments if "%~1"=="" goto usage -REM First argument is the subcommand: "backup" or "restore" set "SUBCOMMAND=%~1" shift -REM Default values +REM Default Values set "UNIT_HOSTNAME=10.0.0.2" set "UNIT_USERNAME=pi" set "OUTPUT=" @@ -59,113 +59,84 @@ if "%SUBCOMMAND%"=="restore" ( ) ) -echo "Unknown or invalid argument: %~1" +echo [ERROR] Unknown or invalid argument: %~1 >> "%LOGFILE%" goto usage :done_args REM --------------------------------------------------------------------------- -REM Subcommand routing +REM Subcommand Routing if "%SUBCOMMAND%"=="backup" goto do_backup if "%SUBCOMMAND%"=="restore" goto do_restore goto usage REM =========================================================================== :do_backup -REM If OUTPUT not specified, generate a name like HOST-backup-RANDOM.tgz if "%OUTPUT%"=="" ( - set /a RAND=%random% + set /a RAND=%random% set "OUTPUT=%UNIT_HOSTNAME%-backup-%RAND%.tgz" ) -echo @ Checking connectivity to %UNIT_HOSTNAME% ... +echo [INFO] Checking connectivity to %UNIT_HOSTNAME% >> "%LOGFILE%" ping -n 1 %UNIT_HOSTNAME% >nul 2>&1 if errorlevel 1 ( - echo @ unit %UNIT_HOSTNAME% can't be reached. + echo [ERROR] Device %UNIT_HOSTNAME% is unreachable. >> "%LOGFILE%" exit /b 1 ) -echo @ Backing up %UNIT_HOSTNAME% to %OUTPUT% ... - -REM List of files to back up from the remote device: +echo [INFO] Backing up %UNIT_HOSTNAME% to %OUTPUT% ... >> "%LOGFILE%" set "FILES_TO_BACKUP=/root/settings.yaml /root/client_secrets.json /root/.ssh /root/.api-report.json /root/.bashrc /root/.profile /home/pi/handshakes /root/peers /etc/pwnagotchi/ /usr/local/share/pwnagotchi/custom-plugins /etc/ssh/ /home/pi/.bashrc /home/pi/.profile /home/pi/.wpa_sec_uploads" -REM --------------------------------------------------------------------------- -REM We'll have the REMOTE do the tar + gzip (since Windows cmd lacks gzip) -REM so we capture the compressed stream directly into %OUTPUT% -REM --------------------------------------------------------------------------- -ssh %UNIT_USERNAME%@%UNIT_HOSTNAME% "sudo tar -cf - %FILES_TO_BACKUP% | gzip -9" > "%OUTPUT%" +ssh %UNIT_USERNAME%@%UNIT_HOSTNAME% "sudo tar -cf - %FILES_TO_BACKUP% | gzip -9" > "%OUTPUT%" 2>> "%LOGFILE%" if errorlevel 1 ( - echo @ Backup failed + echo [ERROR] Backup failed! >> "%LOGFILE%" exit /b 1 ) -echo @ Backup finished. Archive: %OUTPUT% +echo [INFO] Backup completed successfully: %OUTPUT% >> "%LOGFILE%" exit /b 0 REM =========================================================================== :do_restore if "%BACKUP_FILE%"=="" ( - REM If user didn't specify -b, try to find the latest *.tgz with the hostname prefix for /f "delims=" %%A in ('dir /b /a-d /O-D "%UNIT_HOSTNAME%-backup-*.tgz" 2^>nul') do ( set "BACKUP_FILE=%%A" goto found_file ) - echo @ Can't find backup file. Please specify one with '-b'. + echo [ERROR] No backup file found. >> "%LOGFILE%" exit /b 1 :found_file - echo @ Found backup file: %BACKUP_FILE% - set /p CONTINUE="@ Continue restoring this file? (y/n) " - if /i "%CONTINUE%"=="y" ( - echo (continuing...) - ) else ( - exit /b 1 - ) + echo [INFO] Found backup file: %BACKUP_FILE% >> "%LOGFILE%" ) -echo @ Checking connectivity to %UNIT_HOSTNAME% ... +echo [INFO] Checking connectivity to %UNIT_HOSTNAME% >> "%LOGFILE%" ping -n 1 %UNIT_HOSTNAME% > nul 2>&1 if errorlevel 1 ( - echo @ unit %UNIT_HOSTNAME% can't be reached. + echo [ERROR] Device %UNIT_HOSTNAME% is unreachable. >> "%LOGFILE%" exit /b 1 ) -echo @ Restoring %BACKUP_FILE% to %UNIT_HOSTNAME% ... - -REM We'll send the local file contents over SSH; the remote will do tar xzv -type "%BACKUP_FILE%" | ssh %UNIT_USERNAME%@%UNIT_HOSTNAME% "tar xzv -C /" +echo [INFO] Copying backup file to remote device... >> "%LOGFILE%" +scp "%BACKUP_FILE%" %UNIT_USERNAME%@%UNIT_HOSTNAME%:/tmp/ 2>> "%LOGFILE%" if errorlevel 1 ( - echo @ Restore failed. + echo [ERROR] Failed to copy backup file. >> "%LOGFILE%" exit /b 1 ) -echo @ Restore finished. +echo [INFO] Restoring %BACKUP_FILE% on %UNIT_HOSTNAME% >> "%LOGFILE%" +ssh %UNIT_USERNAME%@%UNIT_HOSTNAME% "sudo tar xzvf /tmp/%BACKUP_FILE% -C /" 2>> "%LOGFILE%" +if errorlevel 1 ( + echo [ERROR] Restore failed! >> "%LOGFILE%" + exit /b 1 +) + +echo [INFO] Restore completed successfully. >> "%LOGFILE%" exit /b 0 REM =========================================================================== :usage echo Usage: -echo %SCRIPTNAME% backup [ -n HOST ] [ -u USER ] [ -o OUTPUT ] -echo %SCRIPTNAME% restore [ -n HOST ] [ -u USER ] [ -b BACKUP_FILE ] -echo. -echo Subcommands: -echo backup Backup files from the remote device. -echo restore Restore files to the remote device. -echo. -echo Common Options: -echo -n HOST Hostname or IP of remote device (default: 10.0.0.2) -echo -u USER Username for SSH (default: pi) -echo. -echo Options for 'backup': -echo -o OUTPUT Path/name of the output archive (default: HOST-backup-RANDOM.tgz) -echo. -echo Options for 'restore': -echo -b BACKUP Path to the local backup archive to restore. -echo. -echo Examples: -echo %SCRIPTNAME% backup -echo %SCRIPTNAME% backup -n 10.0.0.2 -u pi -o my-backup.tgz -echo %SCRIPTNAME% restore -b my-backup.tgz -echo. +echo BR_GPT.bat backup [ -n HOST ] [ -u USER ] [ -o OUTPUT ] +echo BR_GPT.bat restore [ -n HOST ] [ -u USER ] [ -b BACKUP_FILE ] exit /b 1