mirror of
https://github.com/jayofelony/pwnagotchi.git
synced 2025-07-01 18:37:27 -04:00
Merge pull request #348 from wpa-2/noai
New autobackup plugin as default, fixes to backup scripts,
This commit is contained in:
@ -18,6 +18,27 @@ main.custom_plugin_repos = [
|
|||||||
|
|
||||||
main.custom_plugins = "/usr/local/share/pwnagotchi/custom-plugins/"
|
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-tune.enabled = true
|
||||||
|
|
||||||
main.plugins.auto-update.enabled = true
|
main.plugins.auto-update.enabled = true
|
||||||
|
146
pwnagotchi/plugins/default/auto_backup.py
Normal file
146
pwnagotchi/plugins/default/auto_backup.py
Normal file
@ -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()
|
142
scripts/BR.bat
Normal file
142
scripts/BR.bat
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
@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 "LOGFILE=%~dp0BR_GPT.log"
|
||||||
|
echo [INFO] Script started at %DATE% %TIME% > "%LOGFILE%"
|
||||||
|
|
||||||
|
REM ---------------------------------------------------------------------------
|
||||||
|
REM Check for Arguments
|
||||||
|
if "%~1"=="" goto usage
|
||||||
|
|
||||||
|
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 [ERROR] Unknown or invalid argument: %~1 >> "%LOGFILE%"
|
||||||
|
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
|
||||||
|
if "%OUTPUT%"=="" (
|
||||||
|
set /a RAND=%random%
|
||||||
|
set "OUTPUT=%UNIT_HOSTNAME%-backup-%RAND%.tgz"
|
||||||
|
)
|
||||||
|
|
||||||
|
echo [INFO] Checking connectivity to %UNIT_HOSTNAME% >> "%LOGFILE%"
|
||||||
|
ping -n 1 %UNIT_HOSTNAME% >nul 2>&1
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo [ERROR] Device %UNIT_HOSTNAME% is unreachable. >> "%LOGFILE%"
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
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"
|
||||||
|
|
||||||
|
ssh %UNIT_USERNAME%@%UNIT_HOSTNAME% "sudo tar -cf - %FILES_TO_BACKUP% | gzip -9" > "%OUTPUT%" 2>> "%LOGFILE%"
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo [ERROR] Backup failed! >> "%LOGFILE%"
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
echo [INFO] Backup completed successfully: %OUTPUT% >> "%LOGFILE%"
|
||||||
|
exit /b 0
|
||||||
|
|
||||||
|
REM ===========================================================================
|
||||||
|
:do_restore
|
||||||
|
if "%BACKUP_FILE%"=="" (
|
||||||
|
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 [ERROR] No backup file found. >> "%LOGFILE%"
|
||||||
|
exit /b 1
|
||||||
|
|
||||||
|
:found_file
|
||||||
|
echo [INFO] Found backup file: %BACKUP_FILE% >> "%LOGFILE%"
|
||||||
|
)
|
||||||
|
|
||||||
|
echo [INFO] Checking connectivity to %UNIT_HOSTNAME% >> "%LOGFILE%"
|
||||||
|
ping -n 1 %UNIT_HOSTNAME% > nul 2>&1
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo [ERROR] Device %UNIT_HOSTNAME% is unreachable. >> "%LOGFILE%"
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
echo [INFO] Copying backup file to remote device... >> "%LOGFILE%"
|
||||||
|
scp "%BACKUP_FILE%" %UNIT_USERNAME%@%UNIT_HOSTNAME%:/tmp/ 2>> "%LOGFILE%"
|
||||||
|
if errorlevel 1 (
|
||||||
|
echo [ERROR] Failed to copy backup file. >> "%LOGFILE%"
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
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 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
|
197
scripts/BR.sh
Normal file
197
scripts/BR.sh
Normal file
@ -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
|
@ -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"
|
|
@ -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 /"
|
|
Reference in New Issue
Block a user