ProxMenux/scripts/backup_restore/backup_host3.sh
2025-06-18 18:56:11 +02:00

1294 lines
46 KiB
Bash

#!/usr/bin/env bash
# Configuration ============================================
REPO_URL="https://raw.githubusercontent.com/MacRimi/ProxMenux/main"
BASE_DIR="/usr/local/share/proxmenux"
UTILS_FILE="$BASE_DIR/utils.sh"
VENV_PATH="/opt/googletrans-env"
if [[ -f "$UTILS_FILE" ]]; then
source "$UTILS_FILE"
fi
load_language
initialize_cache
# ==========================================================
get_external_backup_mount_point() {
local BACKUP_MOUNT_FILE="/usr/local/share/proxmenux/last_backup_mount.txt"
local STORAGE_REPO="$REPO_URL/scripts/backup_restore"
local MOUNT_POINT
if [[ -f "$BACKUP_MOUNT_FILE" ]]; then
MOUNT_POINT=$(head -n1 "$BACKUP_MOUNT_FILE" | tr -d '\r\n' | xargs)
>&2 echo "DEBUG: Valor MOUNT_POINT='$MOUNT_POINT'"
if [[ ! -d "$MOUNT_POINT" ]]; then
msg_error "Mount point does not exist: $MOUNT_POINT"
rm -f "$BACKUP_MOUNT_FILE"
return 1
fi
if ! mountpoint -q "$MOUNT_POINT"; then
msg_error "Mount point is not mounted: $MOUNT_POINT"
rm -f "$BACKUP_MOUNT_FILE"
return 1
fi
echo "$MOUNT_POINT"
return 0
else
source <(curl -s "$STORAGE_REPO/mount_disk_host_bk.sh")
MOUNT_POINT=$(mount_disk_host_bk)
[[ -z "$MOUNT_POINT" ]] && msg_error "$(translate "No disk mounted.")" && return 1
echo "$MOUNT_POINT"
return 0
fi
}
# === Host Backup Main Menu ===
host_backup_menu() {
while true; do
local CHOICE
CHOICE=$(dialog --backtitle "ProxMenux" \
--title "$(translate 'Host Backup')" \
--menu "\n$(translate 'Select backup option:')" 22 70 12 \
"" "$(translate '--- FULL BACKUP ---')" \
1 "$(translate 'Full backup to Proxmox Backup Server (PBS)')" \
2 "$(translate 'Full backup with BorgBackup')" \
3 "$(translate 'Full backup to local .tar.gz')" \
"" "$(translate '--- CUSTOM BACKUP ---')" \
4 "$(translate 'Custom backup to PBS')" \
5 "$(translate 'Custom backup with BorgBackup')" \
6 "$(translate 'Custom backup to local .tar.gz')" \
0 "$(translate 'Return')" \
3>&1 1>&2 2>&3) || return 0
case "$CHOICE" in
1) backup_full_pbs_root ;;
2) backup_with_borg "/boot/efi /etc/pve /etc/network /var/lib/pve-cluster /root /etc/ssh /home /usr/local/bin /etc/cron.d /etc/systemd/system /var/lib/vz" ;;
3) backup_to_local_tar "/boot/efi /etc/pve /etc/network /var/lib/pve-cluster /root /etc/ssh /home /usr/local/bin /etc/cron.d /etc/systemd/system /var/lib/vz" ;;
4) custom_backup_menu backup_to_pbs ;;
5) custom_backup_menu backup_with_borg ;;
6) custom_backup_menu backup_to_local_tar ;;
0) break ;;
esac
done
}
# === Menu checklist for custom backup ===
custom_backup_menu() {
declare -A BACKUP_PATHS=(
[etc-pve]="/etc/pve"
[etc-network]="/etc/network"
[var-lib-pve-cluster]="/var/lib/pve-cluster"
[root-dir]="/root"
[etc-ssh]="/etc/ssh"
[home]="/home"
[local-bin]="/usr/local/bin"
[cron]="/etc/cron.d"
[custom-systemd]="/etc/systemd/system"
[var-lib-vz]="/var/lib/vz"
)
local CHECKLIST_OPTIONS=()
for KEY in "${!BACKUP_PATHS[@]}"; do
DIR="${BACKUP_PATHS[$KEY]}"
CHECKLIST_OPTIONS+=("$KEY" "$DIR" "off")
done
SELECTED_KEYS=$(dialog --separate-output --checklist \
"$(translate 'Select directories to backup:')" 22 70 12 \
"${CHECKLIST_OPTIONS[@]}" \
3>&1 1>&2 2>&3) || return 1
local BACKUP_DIRS=()
for KEY in $SELECTED_KEYS; do
BACKUP_DIRS+=("${BACKUP_PATHS[$KEY]}")
done
# "$1" "${BACKUP_DIRS[*]}"
"$1" "${BACKUP_DIRS[@]}"
}
configure_pbs_repository() {
local PBS_REPO_FILE="/usr/local/share/proxmenux/pbs-repo.conf"
local PBS_PASS_FILE="/usr/local/share/proxmenux/pbs-pass.txt"
local PBS_TOKEN_FILE="/usr/local/share/proxmenux/pbs-token.txt"
local PBS_MANUAL_CONFIGS="/usr/local/share/proxmenux/pbs-manual-configs.txt"
[[ ! -f "$PBS_MANUAL_CONFIGS" ]] && touch "$PBS_MANUAL_CONFIGS"
local PBS_CONFIGS=()
local PBS_SOURCES=()
local PBS_USERNAMES=()
if [[ -f "/etc/pve/storage.cfg" ]]; then
local current_pbs="" server="" datastore="" username=""
while IFS= read -r line; do
if [[ $line =~ ^pbs:\ (.+)$ ]]; then
if [[ -n "$current_pbs" && -n "$server" && -n "$datastore" && -n "$username" ]]; then
PBS_CONFIGS+=("$current_pbs|$username@$server:$datastore")
PBS_SOURCES+=("proxmox|$current_pbs")
PBS_USERNAMES+=("$username")
fi
current_pbs="${BASH_REMATCH[1]}"
server="" datastore="" username=""
elif [[ -n "$current_pbs" ]]; then
if [[ $line =~ ^[[:space:]]*server[[:space:]]+(.+)$ ]]; then
server="${BASH_REMATCH[1]}"
elif [[ $line =~ ^[[:space:]]*datastore[[:space:]]+(.+)$ ]]; then
datastore="${BASH_REMATCH[1]}"
elif [[ $line =~ ^[[:space:]]*username[[:space:]]+(.+)$ ]]; then
username="${BASH_REMATCH[1]}"
elif [[ $line =~ ^[a-zA-Z]+: ]]; then
if [[ -n "$server" && -n "$datastore" && -n "$username" ]]; then
PBS_CONFIGS+=("$current_pbs|$username@$server:$datastore")
PBS_SOURCES+=("proxmox|$current_pbs")
PBS_USERNAMES+=("$username")
fi
current_pbs=""
fi
fi
done < "/etc/pve/storage.cfg"
if [[ -n "$current_pbs" && -n "$server" && -n "$datastore" && -n "$username" ]]; then
PBS_CONFIGS+=("$current_pbs|$username@$server:$datastore")
PBS_SOURCES+=("proxmox|$current_pbs")
PBS_USERNAMES+=("$username")
fi
fi
if [[ -f "$PBS_MANUAL_CONFIGS" ]]; then
while IFS= read -r line; do
if [[ -n "$line" ]]; then
PBS_CONFIGS+=("$line")
local name="${line%%|*}"
PBS_SOURCES+=("manual|$name")
PBS_USERNAMES+=("")
fi
done < "$PBS_MANUAL_CONFIGS"
fi
local menu_options=()
local i=1
for j in "${!PBS_CONFIGS[@]}"; do
local config="${PBS_CONFIGS[$j]}"
local source="${PBS_SOURCES[$j]}"
local name="${config%%|*}"
local repo="${config##*|}"
local source_type="${source%%|*}"
if [[ "$source_type" == "proxmox" ]]; then
menu_options+=("$i" " $name ($repo) [Proxmox]")
else
menu_options+=("$i" " $name ($repo) [Manual]")
fi
((i++))
done
menu_options+=("" "")
menu_options+=("$i" "\Z4\Zb $(translate 'Configure new PBS')\Zn")
local choice
choice=$(dialog --colors --backtitle "ProxMenux" --title "PBS Server Selection" \
--menu "$(translate 'Select PBS server for this backup:')" 22 70 12 "${menu_options[@]}" 3>&1 1>&2 2>&3) || return 1
if [[ $choice -eq $i ]]; then
configure_pbs_manually || return 1
else
local selected_config="${PBS_CONFIGS[$((choice-1))]}"
local selected_source="${PBS_SOURCES[$((choice-1))]}"
local selected_username="${PBS_USERNAMES[$((choice-1))]}"
local pbs_name="${selected_config%%|*}"
local source_type="${selected_source%%|*}"
PBS_REPO="${selected_config##*|}"
{
mkdir -p "$(dirname "$PBS_REPO_FILE")"
echo "$PBS_REPO" > "$PBS_REPO_FILE"
} >/dev/null 2>&1
local password_found=false
if [[ "$source_type" == "proxmox" ]]; then
local password_file="/etc/pve/priv/storage/${pbs_name}.pw"
if [[ -f "$password_file" ]]; then
local auth_content
auth_content=$(<"$password_file")
[[ -f "$PBS_PASS_FILE" ]] && rm "$PBS_PASS_FILE"
[[ -f "$PBS_TOKEN_FILE" ]] && rm "$PBS_TOKEN_FILE"
if [[ "$selected_username" == *"@pbs!"* ]]; then
echo "$auth_content" > "$PBS_PASS_FILE"
chmod 600 "$PBS_PASS_FILE"
password_found=true
dialog --backtitle "ProxMenux" --title "PBS Selected" --msgbox "$(translate 'Using Proxmox PBS:') $pbs_name
$(translate 'Repository:') $PBS_REPO
$(translate 'Authentication:') PBS Cloud Token
$(translate 'Token ID:') $selected_username" 15 80
elif [[ "$auth_content" =~ ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$ ]]; then
local full_token="${selected_username}:${auth_content}"
echo "$full_token" > "$PBS_TOKEN_FILE"
chmod 600 "$PBS_TOKEN_FILE"
password_found=true
dialog --backtitle "ProxMenux" --title "PBS Selected" --msgbox "$(translate 'Using Proxmox PBS:') $pbs_name
$(translate 'Repository:') $PBS_REPO
$(translate 'Authentication:') API Token
$(translate 'Token ID:') $selected_username" 15 80
elif [[ "$auth_content" == *":"* ]]; then
echo "$auth_content" > "$PBS_TOKEN_FILE"
chmod 600 "$PBS_TOKEN_FILE"
password_found=true
dialog --backtitle "ProxMenux" --title "PBS Selected" --msgbox "$(translate 'Using Proxmox PBS:') $pbs_name
$(translate 'Repository:') $PBS_REPO
$(translate 'Authentication:') API Token (Complete)" 12 80
else
echo "$auth_content" > "$PBS_PASS_FILE"
chmod 600 "$PBS_PASS_FILE"
password_found=true
dialog --backtitle "ProxMenux" --title "PBS Selected" --msgbox "$(translate 'Using Proxmox PBS:') $pbs_name
$(translate 'Repository:') $PBS_REPO
$(translate 'Authentication:') Password" 12 80
fi
fi
else
local manual_pass_file="/usr/local/share/proxmenux/pbs-pass-${pbs_name}.txt"
if [[ -f "$manual_pass_file" ]]; then
[[ -f "$PBS_TOKEN_FILE" ]] && rm "$PBS_TOKEN_FILE"
{
cp "$manual_pass_file" "$PBS_PASS_FILE"
chmod 600 "$PBS_PASS_FILE"
} >/dev/null 2>&1
password_found=true
dialog --backtitle "ProxMenux" --title "PBS Selected" --msgbox "$(translate 'Using manual PBS:') $pbs_name
$(translate 'Repository:') $PBS_REPO
$(translate 'Password:') $(translate 'Previously saved')" 12 80
fi
fi
if ! $password_found; then
dialog --backtitle "ProxMenux" --title "Password Required" --msgbox "$(translate 'Password not found for:') $pbs_name
$(translate 'Please enter the password.')" 10 60
get_pbs_password "$pbs_name" || return 1
fi
clear
fi
}
# ========== PBS BACKUP ==========
backup_full_pbs_root() {
local HOSTNAME PBS_REPO PBS_KEY_FILE PBS_PASS_FILE PBS_TOKEN_FILE PBS_ENCRYPTION_PASS_FILE ENCRYPT_OPT=""
HOSTNAME=$(hostname)
local PBS_REPO_FILE="/usr/local/share/proxmenux/pbs-repo.conf"
PBS_KEY_FILE="/usr/local/share/proxmenux/pbs-key.conf"
PBS_PASS_FILE="/usr/local/share/proxmenux/pbs-pass.txt"
PBS_TOKEN_FILE="/usr/local/share/proxmenux/pbs-token.txt"
PBS_ENCRYPTION_PASS_FILE="/usr/local/share/proxmenux/pbs-encryption-pass.txt"
LOGFILE="/tmp/pbs-backup-${HOSTNAME}.log"
configure_pbs_repository || return 1
if [[ ! -f "$PBS_REPO_FILE" ]]; then
msg_error "$(translate "Failed to configure PBS connection")"
sleep 3
return 1
fi
PBS_REPO=$(<"$PBS_REPO_FILE")
unset PBS_PASSWORD PBS_API_TOKEN PBS_API_TOKEN_ID PBS_API_TOKEN_SECRET PBS_FINGERPRINT
local AUTH_TYPE="password"
local PBS_AUTH_VALUE=""
if [[ "$PBS_REPO" == *"@pbs!"* ]]; then
AUTH_TYPE="pbs_cloud"
[[ -f "$PBS_PASS_FILE" ]] && PBS_AUTH_VALUE=$(<"$PBS_PASS_FILE")
elif [[ -f "$PBS_TOKEN_FILE" ]]; then
AUTH_TYPE="token"
PBS_AUTH_VALUE=$(<"$PBS_TOKEN_FILE")
elif [[ -f "$PBS_PASS_FILE" ]]; then
AUTH_TYPE="password"
PBS_AUTH_VALUE=$(<"$PBS_PASS_FILE")
else
msg_error "$(translate "No PBS authentication found!")"
sleep 3
return 1
fi
dialog --backtitle "ProxMenux" --title "Encryption" --yesno "$(translate 'Do you want to encrypt the backup?')" 8 60
if [[ $? -eq 0 ]]; then
if [[ ! -f "$PBS_ENCRYPTION_PASS_FILE" ]]; then
while true; do
PBS_KEY_PASS=$(dialog --backtitle "ProxMenux" --title "Encryption Password" --insecure --passwordbox "$(translate 'Enter encryption password (different from PBS login):')" 12 70 "" 3>&1 1>&2 2>&3) || return 1
PBS_KEY_PASS2=$(dialog --backtitle "ProxMenux" --title "Encryption Password" --insecure --passwordbox "$(translate 'Confirm encryption password:')" 10 60 "" 3>&1 1>&2 2>&3) || return 1
if [[ "$PBS_KEY_PASS" == "$PBS_KEY_PASS2" ]]; then
break
else
dialog --backtitle "ProxMenux" --title "Error" --msgbox "$(translate 'Passwords do not match! Please try again.')" 8 50
fi
done
{
echo "$PBS_KEY_PASS" > "$PBS_ENCRYPTION_PASS_FILE"
chmod 600 "$PBS_ENCRYPTION_PASS_FILE"
} >/dev/null 2>&1
dialog --backtitle "ProxMenux" --title "Success" --msgbox "$(translate 'Encryption password saved successfully!')" 8 50
fi
if [[ ! -f "$PBS_KEY_FILE" ]]; then
PBS_ENCRYPTION_PASS=$(<"$PBS_ENCRYPTION_PASS_FILE")
dialog --backtitle "ProxMenux" --title "Encryption" --infobox "$(translate 'Creating encryption key...')" 5 50
expect -c "
set timeout 30
spawn proxmox-backup-client key create \"$PBS_KEY_FILE\"
expect {
\"Encryption Key Password:\" {
send \"$PBS_ENCRYPTION_PASS\r\"
exp_continue
}
\"Verify Password:\" {
send \"$PBS_ENCRYPTION_PASS\r\"
exp_continue
}
eof
}
" >/dev/null 2>&1
if [[ ! -f "$PBS_KEY_FILE" ]]; then
dialog --backtitle "ProxMenux" --title "Error" --msgbox "$(translate 'Error creating encryption key.')" 8 40
return 1
fi
dialog --backtitle "ProxMenux" --title "Important" --msgbox "$(translate 'IMPORTANT: Save the key file. Without it you will not be able to restore your backups!')\n\n$(translate 'Key file location:') $PBS_KEY_FILE" 12 70
fi
ENCRYPT_OPT="--keyfile $PBS_KEY_FILE"
else
ENCRYPT_OPT=""
fi
clear
show_proxmenux_logo
echo -e
msg_info2 "$(translate "Starting backup to PBS")"
echo -e
echo -e "${BL}$(translate "PBS Repository:")${WHITE} $PBS_REPO${RESET}"
echo -e "${BL}$(translate "Backup ID:")${WHITE} $HOSTNAME${RESET}"
echo -e "${BL}$(translate "Included:")${WHITE} /boot/efi /etc/pve (all root)${RESET}"
echo -e "${BL}$(translate "Encryption:")${WHITE} $([[ -n "$ENCRYPT_OPT" ]] && echo "Enabled" || echo "Disabled")${RESET}"
case "$AUTH_TYPE" in
"pbs_cloud") echo -e "${BL}$(translate "Authentication:")${WHITE} PBS Cloud Token${RESET}" ;;
"token") echo -e "${BL}$(translate "Authentication:")${WHITE} API Token${RESET}" ;;
"password") echo -e "${BL}$(translate "Authentication:")${WHITE} Password${RESET}" ;;
esac
echo -e "${BL}$(translate "Log file:")${WHITE} $LOGFILE${RESET}"
echo -e "${BOLD}${NEON_PURPLE_BLUE}-------------------------------${RESET}"
echo ""
local backup_cmd="proxmox-backup-client backup --include-dev /boot/efi --include-dev /etc/pve root-${HOSTNAME}.pxar:/ --repository \"$PBS_REPO\" $ENCRYPT_OPT --backup-type host --backup-id \"$HOSTNAME\" --backup-time \"$(date +%s)\""
local backup_result=0
case "$AUTH_TYPE" in
"pbs_cloud")
if [[ -n "$ENCRYPT_OPT" ]]; then
PBS_ENCRYPTION_PASS=$(<"$PBS_ENCRYPTION_PASS_FILE")
echo "$(translate "Starting encrypted full backup with PBS Cloud...")"
echo ""
env -i PBS_PASSWORD="$PBS_AUTH_VALUE" expect -c "
set timeout 3600
log_file $LOGFILE
spawn $backup_cmd
expect {
\"Encryption Key Password:\" {
send \"$PBS_ENCRYPTION_PASS\r\"
exp_continue
}
eof
}
" | tee -a "$LOGFILE"
backup_result=${PIPESTATUS[0]}
else
echo "$(translate "Starting unencrypted full backup with PBS Cloud...")"
echo ""
env -i PBS_PASSWORD="$PBS_AUTH_VALUE" bash -c "$backup_cmd" | tee -a "$LOGFILE"
backup_result=${PIPESTATUS[0]}
fi
;;
"token")
if [[ -n "$ENCRYPT_OPT" ]]; then
PBS_ENCRYPTION_PASS=$(<"$PBS_ENCRYPTION_PASS_FILE")
echo "$(translate "Starting encrypted full backup with API Token...")"
echo ""
env -i PBS_API_TOKEN="$PBS_AUTH_VALUE" expect -c "
set timeout 3600
log_file $LOGFILE
spawn $backup_cmd
expect {
\"Encryption Key Password:\" {
send \"$PBS_ENCRYPTION_PASS\r\"
exp_continue
}
eof
}
" | tee -a "$LOGFILE"
backup_result=${PIPESTATUS[0]}
else
echo "$(translate "Starting unencrypted full backup with API Token...")"
echo ""
env -i PBS_API_TOKEN="$PBS_AUTH_VALUE" bash -c "$backup_cmd" | tee -a "$LOGFILE"
backup_result=${PIPESTATUS[0]}
fi
;;
"password")
if [[ -n "$ENCRYPT_OPT" ]]; then
PBS_ENCRYPTION_PASS=$(<"$PBS_ENCRYPTION_PASS_FILE")
echo "$(translate "Starting encrypted full backup with password...")"
echo ""
env -i expect -c "
set timeout 3600
log_file $LOGFILE
spawn $backup_cmd
expect {
-re \"Password for .*:\" {
send \"$PBS_AUTH_VALUE\r\"
exp_continue
}
\"Encryption Key Password:\" {
send \"$PBS_ENCRYPTION_PASS\r\"
exp_continue
}
-re \"Are you sure you want to continue connecting.*\" {
send \"y\r\"
exp_continue
}
eof
}
" | tee -a "$LOGFILE"
backup_result=${PIPESTATUS[0]}
else
echo "$(translate "Starting unencrypted full backup with password...")"
echo ""
env -i expect -c "
set timeout 3600
log_file $LOGFILE
spawn $backup_cmd
expect {
-re \"Password for .*:\" {
send \"$PBS_AUTH_VALUE\r\"
exp_continue
}
-re \"Are you sure you want to continue connecting.*\" {
send \"y\r\"
exp_continue
}
eof
}
" | tee -a "$LOGFILE"
backup_result=${PIPESTATUS[0]}
fi
;;
esac
echo -e "${BOLD}${NEON_PURPLE_BLUE}===============================${RESET}\n"
if [[ $backup_result -eq 0 ]]; then
msg_ok "$(translate "Full backup process completed successfully")"
else
msg_error "$(translate "Backup process finished with errors")"
fi
echo ""
msg_success "$(translate "Press Enter to return to the main menu...")"
read -r
}
backup_to_pbs() {
local HOSTNAME TIMESTAMP SNAPSHOT
HOSTNAME=$(hostname)
TIMESTAMP=$(date +%Y-%m-%d_%H-%M)
SNAPSHOT="${HOSTNAME}-${TIMESTAMP}"
local PBS_REPO_FILE="/usr/local/share/proxmenux/pbs-repo.conf"
local PBS_KEY_FILE="/usr/local/share/proxmenux/pbs-key.conf"
local PBS_PASS_FILE="/usr/local/share/proxmenux/pbs-pass.txt"
local PBS_TOKEN_FILE="/usr/local/share/proxmenux/pbs-token.txt"
local PBS_ENCRYPTION_PASS_FILE="/usr/local/share/proxmenux/pbs-encryption-pass.txt"
local PBS_REPO ENCRYPT_OPT USE_ENCRYPTION
local PBS_KEY_PASS PBS_REPO_PASS
configure_pbs_repository || return 1
PBS_REPO=$(<"$PBS_REPO_FILE")
unset PBS_PASSWORD PBS_API_TOKEN PBS_API_TOKEN_ID PBS_API_TOKEN_SECRET PBS_FINGERPRINT
USE_ENCRYPTION=false
dialog --backtitle "ProxMenux" --yesno "$(translate 'Do you want to encrypt the backup?')" 8 60
[[ $? -eq 0 ]] && USE_ENCRYPTION=true
if $USE_ENCRYPTION && ! command -v expect >/dev/null 2>&1; then
apt-get update -qq >/dev/null 2>&1
apt-get install -y expect >/dev/null 2>&1
fi
if [[ "$#" -lt 1 ]]; then
clear
show_proxmenux_logo
msg_error "$(translate "No directories specified for backup.")"
sleep 2
return 1
fi
local TOTAL="$#"
local COUNT=1
local AUTH_TYPE="password"
local PBS_AUTH_VALUE=""
if [[ "$PBS_REPO" == *"@pbs!"* ]]; then
AUTH_TYPE="pbs_cloud"
[[ -f "$PBS_PASS_FILE" ]] && PBS_AUTH_VALUE=$(<"$PBS_PASS_FILE")
elif [[ -f "$PBS_TOKEN_FILE" ]]; then
AUTH_TYPE="token"
PBS_AUTH_VALUE=$(<"$PBS_TOKEN_FILE")
elif [[ -f "$PBS_PASS_FILE" ]]; then
AUTH_TYPE="password"
PBS_AUTH_VALUE=$(<"$PBS_PASS_FILE")
else
msg_error "$(translate "No PBS authentication found!")"
return 1
fi
for dir in "$@"; do
local SAFE_NAME SAFE_ID PXAR_NAME
SAFE_NAME=$(basename "$dir" | tr '.-/' '_')
PXAR_NAME="root-custom-${SAFE_NAME}-${SNAPSHOT}.pxar"
SAFE_ID="custom-${HOSTNAME}-${SAFE_NAME}"
msg_info2 "$(translate "[$COUNT/$TOTAL] Backing up") $dir $(translate "as") $PXAR_NAME"
ENCRYPT_OPT=""
if $USE_ENCRYPTION; then
if [[ -f "$PBS_KEY_FILE" ]]; then
ENCRYPT_OPT="--keyfile $PBS_KEY_FILE"
else
while true; do
PBS_KEY_PASS=$(dialog --backtitle "ProxMenux" --insecure --passwordbox "$(translate 'Enter encryption password (different from PBS login):')" 10 60 "" 3>&1 1>&2 2>&3) || return 1
PBS_KEY_PASS2=$(dialog --backtitle "ProxMenux" --insecure --passwordbox "$(translate 'Confirm encryption password:')" 10 60 "" 3>&1 1>&2 2>&3) || return 1
if [[ "$PBS_KEY_PASS" == "$PBS_KEY_PASS2" ]]; then
break
else
dialog --backtitle "ProxMenux" --msgbox "$(translate 'Passwords do not match! Please try again.')" 8 50
fi
done
{
echo "$PBS_KEY_PASS" > "$PBS_ENCRYPTION_PASS_FILE"
chmod 600 "$PBS_ENCRYPTION_PASS_FILE"
} >/dev/null 2>&1
expect -c "
set timeout 30
spawn proxmox-backup-client key create \"$PBS_KEY_FILE\"
expect {
\"Encryption Key Password:\" {
send \"$PBS_KEY_PASS\r\"
exp_continue
}
\"Verify Password:\" {
send \"$PBS_KEY_PASS\r\"
exp_continue
}
eof
}
" >/dev/null 2>&1
if [[ ! -f "$PBS_KEY_FILE" ]]; then
dialog --backtitle "ProxMenux" --msgbox "$(translate 'Error creating encryption key.')" 8 40
return 1
fi
ENCRYPT_OPT="--keyfile $PBS_KEY_FILE"
dialog --backtitle "ProxMenux" --msgbox "$(translate 'Encryption key generated. Save it in a safe place!')" 10 60
fi
fi
clear
show_proxmenux_logo
echo -e
msg_info2 "$(translate "Starting backup to PBS")"
TOTAL_SIZE=$(du -cb "$@" | awk '/total$/ {print $1}')
TOTAL_SIZE_GB=$(awk "BEGIN {printf \"%.2f\", $TOTAL_SIZE/1024/1024/1024}")
echo -e
echo -e "${BL}$(translate "PBS Repository:")${WHITE} $PBS_REPO${RESET}"
echo -e "${BL}$(translate "Backup ID:")${WHITE} $HOSTNAME${RESET}"
echo -e "${BL}$(translate "Encryption:")${WHITE} $([[ -n "$ENCRYPT_OPT" ]] && echo "Enabled" || echo "Disabled")${RESET}"
case "$AUTH_TYPE" in
"pbs_cloud") echo -e "${BL}$(translate "Authentication:")${WHITE} PBS Cloud Token${RESET}" ;;
"token") echo -e "${BL}$(translate "Authentication:")${WHITE} API Token${RESET}" ;;
"password") echo -e "${BL}$(translate "Authentication:")${WHITE} Password${RESET}" ;;
esac
echo -e "${BL}$(translate "Included directories:")${WHITE} $*${RESET}"
echo -e "${BL}$(translate "Total size:")${WHITE} ${TOTAL_SIZE_GB} GB${RESET}"
echo -e "${BOLD}${NEON_PURPLE_BLUE}-------------------------------${RESET}"
local backup_cmd="proxmox-backup-client backup \"${PXAR_NAME}:$dir\" --repository \"$PBS_REPO\" $ENCRYPT_OPT --backup-type host --backup-id \"$SAFE_ID\" --backup-time \"$(date +%s)\""
case "$AUTH_TYPE" in
"pbs_cloud")
if $USE_ENCRYPTION && [[ -f "$PBS_ENCRYPTION_PASS_FILE" ]]; then
PBS_KEY_PASS=$(<"$PBS_ENCRYPTION_PASS_FILE")
env -i PBS_PASSWORD="$PBS_AUTH_VALUE" expect -c "
set timeout 300
spawn $backup_cmd
expect {
\"Encryption Key Password:\" {
send \"$PBS_KEY_PASS\r\"
exp_continue
}
eof
}
"
else
env -i PBS_PASSWORD="$PBS_AUTH_VALUE" bash -c "$backup_cmd"
fi
;;
"token")
if $USE_ENCRYPTION && [[ -f "$PBS_ENCRYPTION_PASS_FILE" ]]; then
PBS_KEY_PASS=$(<"$PBS_ENCRYPTION_PASS_FILE")
env -i PBS_API_TOKEN="$PBS_AUTH_VALUE" expect -c "
set timeout 300
spawn $backup_cmd
expect {
\"Encryption Key Password:\" {
send \"$PBS_KEY_PASS\r\"
exp_continue
}
eof
}
"
else
env -i PBS_API_TOKEN="$PBS_AUTH_VALUE" bash -c "$backup_cmd"
fi
;;
"password")
if $USE_ENCRYPTION && [[ -f "$PBS_ENCRYPTION_PASS_FILE" ]]; then
PBS_KEY_PASS=$(<"$PBS_ENCRYPTION_PASS_FILE")
env -i expect -c "
set timeout 300
spawn $backup_cmd
expect {
-re \"Password for .*:\" {
send \"$PBS_AUTH_VALUE\r\"
exp_continue
}
\"Encryption Key Password:\" {
send \"$PBS_KEY_PASS\r\"
exp_continue
}
-re \"Are you sure you want to continue connecting.*\" {
send \"y\r\"
exp_continue
}
eof
}
"
else
env -i expect -c "
set timeout 300
spawn $backup_cmd
expect {
-re \"Password for .*:\" {
send \"$PBS_AUTH_VALUE\r\"
exp_continue
}
-re \"Are you sure you want to continue connecting.*\" {
send \"y\r\"
exp_continue
}
eof
}
"
fi
;;
esac
COUNT=$((COUNT+1))
done
echo -e "${BOLD}${NEON_PURPLE_BLUE}===============================${RESET}\n"
msg_ok "$(translate "Backup process finished.")"
echo ""
msg_success "$(translate "Press Enter to return to the main menu...")"
read -r
}
# ===============================
# ========== BORGBACKUP ==========
backup_with_borg() {
local BORG_APPIMAGE="/usr/local/share/proxmenux/borg"
local LOGFILE="/tmp/borg-backup.log"
local BORG_PASS_FILE="/usr/local/share/proxmenux/borg-pass.txt"
local BORG_KEY_FILE="/usr/local/share/proxmenux/borg-key"
local DEST
local TYPE
local ENCRYPT_OPT=""
local BORG_KEY
# Descargar BorgBackup si no existe
if [[ ! -x "$BORG_APPIMAGE" ]]; then
clear
show_proxmenux_logo
msg_info "$(translate "BorgBackup not found. Downloading AppImage...")"
mkdir -p /usr/local/share/proxmenux
wget -qO "$BORG_APPIMAGE" "https://github.com/borgbackup/borg/releases/download/1.2.8/borg-linux64"
chmod +x "$BORG_APPIMAGE"
msg_ok "$(translate "BorgBackup downloaded and ready.")"
fi
# Seleccionar tipo de destino
TYPE=$(dialog --backtitle "ProxMenux" --menu "$(translate 'Select Borg backup destination:')" 15 60 4 \
"local" "$(translate 'Local directory')" \
"usb" "$(translate 'Internal/External dedicated disk')" \
"remote" "$(translate 'Remote server (SSH)')" \
"pbs" "$(translate 'remote-backups.com')" \
3>&1 1>&2 2>&3) || return 1
if [[ "$TYPE" == "local" ]]; then
DEST=$(dialog --backtitle "ProxMenux" --inputbox "$(translate 'Enter local directory for backup:')" 10 60 "/backup/borgbackup" 3>&1 1>&2 2>&3) || return 1
mkdir -p "$DEST"
elif [[ "$TYPE" == "usb" ]]; then
while true; do
BASE_DEST=$(get_external_backup_mount_point)
if [[ -z "$BASE_DEST" ]]; then
dialog --backtitle "ProxMenux" --yesno "$(translate 'No external disk detected or mounted. Would you like to retry?')" 8 60
[[ $? -eq 0 ]] && continue
return 1
fi
DEST="$BASE_DEST/borgbackup"
mkdir -p "$DEST"
DISK_DEV=$(df "$BASE_DEST" | awk 'NR==2{print $1}')
PKNAME=$(lsblk -no PKNAME "$DISK_DEV" 2>/dev/null)
[[ -z "$PKNAME" ]] && PKNAME=$(basename "$DISK_DEV" | sed 's/[0-9]*$//')
if [[ -n "$PKNAME" && -b /dev/$PKNAME ]]; then
DISK_MODEL=$(lsblk -no MODEL "/dev/$PKNAME")
else
DISK_MODEL="(unknown)"
fi
FREE_SPACE=$(df -h "$BASE_DEST" | awk 'NR==2{print $4}')
dialog --backtitle "ProxMenux" \
--title "$(translate "Dedicated Backup Disk")" \
--yesno "\n$(translate "Mount point:") $DEST\n\n\
$(translate "Disk model:") $DISK_MODEL\n\
$(translate "Available space:") $FREE_SPACE\n\n\
$(translate "Use this disk for backup?")" 12 70
if [[ $? -eq 0 ]]; then
break
else
return 1
fi
done
elif [[ "$TYPE" == "remote" ]]; then
REMOTE_USER=$(dialog --backtitle "ProxMenux" --inputbox "$(translate 'Enter SSH user for remote:')" 10 60 "root" 3>&1 1>&2 2>&3) || return 1
REMOTE_HOST=$(dialog --backtitle "ProxMenux" --inputbox "$(translate 'Enter SSH host:')" 10 60 "" 3>&1 1>&2 2>&3) || return 1
REMOTE_PATH=$(dialog --backtitle "ProxMenux" --inputbox "$(translate 'Enter remote path:')" 10 60 "/backup/borgbackup" 3>&1 1>&2 2>&3) || return 1
dialog --backtitle "ProxMenux" --yesno "$(translate 'Do you want to use SSH key authentication?')" 8 60
if [[ $? -eq 0 ]]; then
SSH_KEY=$(dialog --backtitle "ProxMenux" --fselect "$HOME/.ssh/" 10 60 3>&1 1>&2 2>&3) || return 1
export BORG_RSH="ssh -i $SSH_KEY"
fi
DEST="ssh://$REMOTE_USER@$REMOTE_HOST:$REMOTE_PATH"
elif [[ "$TYPE" == "pbs" ]]; then
PBS_CUSTOMER_ID=$(dialog --backtitle "ProxMenux" --inputbox "$(translate 'Enter PBS customer ID (from Connect panel):')" 10 70 "" 3>&1 1>&2 2>&3) || return 1
PBS_SERVER=$(dialog --backtitle "ProxMenux" --inputbox "$(translate 'Enter PBS server (from Connect panel):')" 10 60 "" 3>&1 1>&2 2>&3) || return 1
local SSH_KEYS=()
local SSH_KEY_NAMES=()
for key_file in ~/.ssh/id_rsa ~/.ssh/id_ed25519 ~/.ssh/pbs_host_key ~/.ssh/id_ecdsa; do
if [[ -f "$key_file" && -f "${key_file}.pub" ]]; then
SSH_KEYS+=("$key_file")
local key_type=$(head -1 "${key_file}.pub" | awk '{print $1}')
local key_comment=$(head -1 "${key_file}.pub" | awk '{print $3}')
SSH_KEY_NAMES+=("$(basename "$key_file") ($key_type) - $key_comment")
fi
done
if [[ ${#SSH_KEYS[@]} -eq 0 ]]; then
dialog --backtitle "ProxMenux" --yesno "$(translate 'No SSH keys found. Do you want to create one now?')" 8 60
if [[ $? -eq 0 ]]; then
clear
show_proxmenux_logo
echo -e
msg_info2 "$(translate "Creating SSH key for PBS-host.de...")"
ssh-keygen -t rsa -b 4096 -f ~/.ssh/pbs_host_key -N "" -C "pbs-backup-$(hostname)"
if [[ $? -eq 0 ]]; then
SSH_KEY="$HOME/.ssh/pbs_host_key"
msg_ok "$(translate "SSH key created successfully!")"
else
msg_error "$(translate "Failed to create SSH key")"
return 1
fi
else
return 1
fi
elif [[ ${#SSH_KEYS[@]} -eq 1 ]]; then
SSH_KEY="${SSH_KEYS[0]}"
else
local menu_options=()
for i in "${!SSH_KEYS[@]}"; do
menu_options+=("$i" "${SSH_KEY_NAMES[$i]}")
done
local choice
choice=$(dialog --backtitle "ProxMenux" --menu "$(translate 'Select SSH key to use:')" 15 80 10 "${menu_options[@]}" 3>&1 1>&2 2>&3) || return 1
SSH_KEY="${SSH_KEYS[$choice]}"
fi
export BORG_RSH="ssh -i $SSH_KEY"
DEST="$PBS_CUSTOMER_ID@$PBS_SERVER:./borg"
clear
show_proxmenux_logo
echo -e
msg_info2 "$(translate "PBS-host.de Configuration")"
echo -e "${BL}$(translate "Server:")${WHITE} $PBS_SERVER${RESET}"
echo -e "${BL}$(translate "Customer ID:")${WHITE} $PBS_CUSTOMER_ID${RESET}"
echo -e "${BL}$(translate "SSH Key:")${WHITE} $SSH_KEY${RESET}"
echo -e "${BOLD}${NEON_PURPLE_BLUE}-------------------------------${RESET}"
echo ""
chmod 600 "$SSH_KEY"
local SSH_PUB_KEY="${SSH_KEY}.pub"
if [[ -f "$SSH_PUB_KEY" ]]; then
echo -e "${BL}$(translate "Your SSH Public Key:")${RESET}"
echo -e "${BOLD}${NEON_PURPLE_BLUE}===============================${RESET}"
echo -e "${WHITE}$(cat "$SSH_PUB_KEY")${RESET}"
echo -e "${BOLD}${NEON_PURPLE_BLUE}===============================${RESET}"
echo ""
if command -v xclip >/dev/null 2>&1; then
echo -e "${BL}$(translate "Copying to clipboard...")${RESET}"
cat "$SSH_PUB_KEY" | xclip -selection clipboard
msg_ok "$(translate "Public key copied to clipboard!")"
elif command -v pbcopy >/dev/null 2>&1; then
echo -e "${BL}$(translate "Copying to clipboard...")${RESET}"
cat "$SSH_PUB_KEY" | pbcopy
msg_ok "$(translate "Public key copied to clipboard!")"
fi
echo ""
echo -e "${BL}$(translate "INSTRUCTIONS:")${RESET}"
echo "1. $(translate "Copy the key above (or use clipboard if available)")"
echo "2. $(translate "Go to PBS-host.de panel → Your datastore → Connect")"
echo "3. $(translate "Select 'rsync / borg / sftp' tab")"
echo "4. $(translate "Paste the key in 'Save SSH Key' section")"
echo "5. $(translate "Click 'Save'")"
echo ""
msg_success "$(translate "Press Enter when you have uploaded the key to PBS-host.de panel...")"
read -r
fi
clear
show_proxmenux_logo
echo -e
msg_info2 "$(translate "Testing connection to PBS-host.de...")"
echo ""
echo "$(translate "Connecting... (you may need to type 'yes' to accept the server fingerprint)")"
echo ""
if timeout 30 ssh -i "$SSH_KEY" -o ConnectTimeout=10 -o BatchMode=no "$PBS_CUSTOMER_ID@$PBS_SERVER" borg --version >/dev/null 2>&1; then
echo ""
msg_ok "$(translate "✅ Connection successful! Borg is available on the server.")"
sleep 2
else
echo ""
msg_error "$(translate "❌ Connection failed or requires manual intervention.")"
echo ""
echo -e "${BL}$(translate "This could be normal if:")${RESET}"
echo "$(translate "First time connecting (need to accept fingerprint)")"
echo "$(translate "Key not yet uploaded to PBS-host.de panel")"
echo "$(translate "Network connectivity issues")"
echo ""
dialog --backtitle "ProxMenux" --yesno "$(translate 'Do you want to continue anyway? The backup will test the connection again.')" 10 70
if [[ $? -ne 0 ]]; then
return 1
fi
fi
fi
local USE_ENCRYPTION=false
dialog --backtitle "ProxMenux" --yesno "$(translate 'Do you want to encrypt the backup?')" 8 60
if [[ $? -eq 0 ]]; then
USE_ENCRYPTION=true
ENCRYPT_OPT="--encryption=repokey"
if [[ -f "$BORG_PASS_FILE" ]]; then
dialog --backtitle "ProxMenux" --yesno "$(translate 'A saved encryption passphrase exists. Use it?')" 8 60
if [[ $? -eq 0 ]]; then
BORG_KEY=$(<"$BORG_PASS_FILE")
else
while true; do
BORG_KEY=$(dialog --backtitle "ProxMenux" --insecure --passwordbox "$(translate 'Enter Borg encryption passphrase:')" 10 60 "" 3>&1 1>&2 2>&3) || return 1
BORG_KEY2=$(dialog --backtitle "ProxMenux" --insecure --passwordbox "$(translate 'Confirm encryption passphrase:')" 10 60 "" 3>&1 1>&2 2>&3) || return 1
if [[ "$BORG_KEY" == "$BORG_KEY2" ]]; then
break
else
dialog --backtitle "ProxMenux" --msgbox "$(translate 'Passphrases do not match! Please try again.')" 8 50
fi
done
mkdir -p "$(dirname "$BORG_PASS_FILE")"
echo "$BORG_KEY" > "$BORG_PASS_FILE"
chmod 600 "$BORG_PASS_FILE"
fi
else
while true; do
BORG_KEY=$(dialog --backtitle "ProxMenux" --insecure --passwordbox "$(translate 'Enter Borg encryption passphrase:')" 10 60 "" 3>&1 1>&2 2>&3) || return 1
BORG_KEY2=$(dialog --backtitle "ProxMenux" --insecure --passwordbox "$(translate 'Confirm encryption passphrase:')" 10 60 "" 3>&1 1>&2 2>&3) || return 1
if [[ "$BORG_KEY" == "$BORG_KEY2" ]]; then
break
else
dialog --backtitle "ProxMenux" --msgbox "$(translate 'Passphrases do not match! Please try again.')" 8 50
fi
done
mkdir -p "$(dirname "$BORG_PASS_FILE")"
echo "$BORG_KEY" > "$BORG_PASS_FILE"
chmod 600 "$BORG_PASS_FILE"
fi
export BORG_PASSPHRASE="$BORG_KEY"
else
ENCRYPT_OPT="--encryption=none"
fi
if [[ "$TYPE" == "local" || "$TYPE" == "usb" ]]; then
if [[ ! -f "$DEST/config" ]]; then
dialog --backtitle "ProxMenux" --infobox "$(translate 'Initializing Borg repository...')" 5 50
"$BORG_APPIMAGE" init $ENCRYPT_OPT "$DEST"
if [[ $? -ne 0 ]]; then
clear
show_proxmenux_logo
msg_error "$(translate "Failed to initialize Borg repo at") $DEST"
sleep 5
return 1
fi
fi
elif [[ "$TYPE" == "remote" || "$TYPE" == "pbs" ]]; then
if ! "$BORG_APPIMAGE" list "$DEST" >/dev/null 2>&1; then
dialog --backtitle "ProxMenux" --yesno "$(translate 'Repository does not exist or is not accessible. Initialize it?')" 8 60
if [[ $? -eq 0 ]]; then
dialog --backtitle "ProxMenux" --infobox "$(translate 'Initializing Borg repository...')" 5 50
"$BORG_APPIMAGE" init $ENCRYPT_OPT "$DEST"
if [[ $? -ne 0 ]]; then
clear
show_proxmenux_logo
msg_error "$(translate "Failed to initialize Borg repo at") $DEST"
sleep 5
return 1
fi
else
return 1
fi
fi
fi
dialog --backtitle "ProxMenux" --msgbox "$(translate 'Borg backup will start now. This may take a while.')" 8 40
clear
show_proxmenux_logo
msg_info2 "$(translate "Starting backup with BorgBackup...")"
echo -e
TOTAL_SIZE=$(du -cb "$@" | awk '/total$/ {print $1}')
TOTAL_SIZE_GB=$(awk "BEGIN {printf \"%.2f\", $TOTAL_SIZE/1024/1024/1024}")
echo -e "${BL}$(translate "Destination:")${WHITE} $DEST${RESET}"
echo -e "${BL}$(translate "Encryption:")${WHITE} $($USE_ENCRYPTION && echo "Enabled" || echo "Disabled")${RESET}"
echo -e "${BL}$(translate "Included directories:")${WHITE} $*${RESET}"
echo -e "${BL}$(translate "Total size:")${WHITE} ${TOTAL_SIZE_GB} GB${RESET}"
echo -e "${BOLD}${NEON_PURPLE_BLUE}-------------------------------${RESET}"
local ARCHIVE_NAME="root-$(hostname)-$(date +%Y%m%d_%H%M)"
"$BORG_APPIMAGE" create --progress --stats --compression zstd "$DEST"::$ARCHIVE_NAME "$@" 2>&1 | tee "$LOGFILE"
local BACKUP_RESULT=$?
echo -e "${BOLD}${NEON_PURPLE_BLUE}===============================${RESET}\n"
if [[ $BACKUP_RESULT -eq 0 ]]; then
msg_ok "$(translate "Backup completed successfully!")"
echo -e "\n${BL}$(translate "Backup information:")${RESET}"
"$BORG_APPIMAGE" info "$DEST"::$ARCHIVE_NAME 2>&1 | tee -a "$LOGFILE"
if [[ "$TYPE" == "remote" || "$TYPE" == "pbs" ]]; then
echo -e "\n${BL}$(translate "Tip:")${RESET} $(translate "Run 'borg compact $DEST' to free up space after multiple backups.")"
fi
else
msg_error "$(translate "Backup process failed with error code:") $BACKUP_RESULT"
fi
echo
msg_success "$(translate "Press Enter to return to the main menu...")"
read -r
}
# ===============================
# ========== LOCAL TAR ==========
backup_to_local_tar() {
# local SRC="$1"
local TYPE
local DEST
local LOGFILE="/tmp/tar-backup.log"
if ! command -v pv &>/dev/null; then
apt-get update -qq && apt-get install -y pv >/dev/null 2>&1
fi
TYPE=$(dialog --backtitle "ProxMenux" --menu "$(translate 'Select backup destination:')" 15 60 2 \
"local" "$(translate 'Local directory')" \
"usb" "$(translate 'Internal/External dedicated disk')" \
3>&1 1>&2 2>&3) || return 1
if [[ "$TYPE" == "local" ]]; then
DEST=$(dialog --backtitle "ProxMenux" --inputbox "$(translate 'Enter directory for backup:')" 10 60 "/backup" 3>&1 1>&2 2>&3) || return 1
mkdir -p "$DEST"
else
while true; do
DEST=$(get_external_backup_mount_point)
if [[ -z "$DEST" ]]; then
dialog --backtitle "ProxMenux" --yesno "No external disk detected or mounted. Would you like to retry?" 8 60
[[ $? -eq 0 ]] && continue
return 1
fi
DISK_DEV=$(df "$DEST" | awk 'NR==2{print $1}')
PKNAME=$(lsblk -no PKNAME "$DISK_DEV" 2>/dev/null)
[[ -z "$PKNAME" ]] && PKNAME=$(basename "$DISK_DEV" | sed 's/[0-9]*$//')
if [[ -n "$PKNAME" && -b /dev/$PKNAME ]]; then
DISK_MODEL=$(lsblk -no MODEL "/dev/$PKNAME")
else
DISK_MODEL="(unknown)"
fi
FREE_SPACE=$(df -h "$DEST" | awk 'NR==2{print $4}')
dialog --backtitle "ProxMenux" \
--title "$(translate "Dedicated Backup Disk")" \
--yesno "\n$(translate "Mount point:") $DEST\n\n\
$(translate "Disk model:") $DISK_MODEL\n\
$(translate "Available space:") $FREE_SPACE\n\n\
$(translate "Use this disk for backup?")" 12 70
if [[ $? -eq 0 ]]; then
mkdir -p "$DEST"
break
else
return 1
fi
done
fi
TAR_INPUT=""
TOTAL_SIZE=0
for src in $SRC; do
sz=$(du -sb "$src" 2>/dev/null | awk '{print $1}')
TOTAL_SIZE=$((TOTAL_SIZE + sz))
TAR_INPUT="$TAR_INPUT $src"
done
local FILENAME="root-$(hostname)-$(date +%Y%m%d_%H%M).tar.gz"
clear
show_proxmenux_logo
msg_info2 "$(translate "Starting backup with tar...")"
echo -e
TOTAL_SIZE=$(du -cb "$@" | awk '/total$/ {print $1}')
TOTAL_SIZE_GB=$(awk "BEGIN {printf \"%.2f\", $TOTAL_SIZE/1024/1024/1024}")
echo -e "${BL}$(translate "Included directories:")${WHITE} $*${RESET}"
echo -e "${BL}$(translate "Total size:")${WHITE} ${TOTAL_SIZE_GB} GB${RESET}"
tar -cf - "$@" 2> >(grep -v "Removing leading \`/'" >&2) \
| pv -s "$TOTAL_SIZE" \
| gzip > "$DEST/$FILENAME"
echo -ne "\033[1A\r\033[K"
echo -e "${BOLD}${NEON_PURPLE_BLUE}===============================${RESET}\n"
msg_ok "$(translate "Backup process finished. Review log above or in /tmp/tar-backup.log")"
echo
msg_success "$(translate "Press Enter to return to the main menu...")"
read -r
}
# ===============================
host_backup_menu