port OFFSITE backup to MacOS script with spotlight launcher
This commit is contained in:
1 parent
9f0eafee19
commit
6b37013994
3 files changed
+264
No files matched your search
@@ -0,0 +1,158 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Sichert die Freigaben von bfds auf die OFFSITE-Platte (VeraCrypt-Partition).
|
||||||
|
# macOS-Portierung von robocopy-bfds-offsite/bfds-offsite-backup.cmd.
|
||||||
|
# Kompatibel mit dem mit macOS ausgelieferten Bash 3.2.
|
||||||
|
#
|
||||||
|
# Ablauf: VeraCrypt-Partition entschluesseln und einbinden, SMB-Freigaben von
|
||||||
|
# bfds per rsync kopieren, Partition wieder aushaengen.
|
||||||
|
#
|
||||||
|
# Voraussetzung: VeraCrypt (+ macFUSE) installiert.
|
||||||
|
# Optional vorab setzen: DEVICE=/dev/disk4s1 ./backup-bfds-storage-offsite.sh
|
||||||
|
|
||||||
|
PATH="/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/opt/homebrew/bin"
|
||||||
|
export PATH
|
||||||
|
|
||||||
|
SHARES=(
|
||||||
|
# photos
|
||||||
|
# rob
|
||||||
|
# movies
|
||||||
|
# music
|
||||||
|
# peggy
|
||||||
|
ebooks
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
VOLUME_LABEL="${VOLUME_LABEL:-NASOFFSITE1}"
|
||||||
|
VERACRYPT="${VERACRYPT:-/Applications/VeraCrypt.app/Contents/MacOS/VeraCrypt}"
|
||||||
|
MOUNT_POINT="${MOUNT_POINT:-/Volumes/$VOLUME_LABEL}"
|
||||||
|
SOURCE_HOST="${SOURCE_HOST:-bfds}"
|
||||||
|
DEVICE="${DEVICE:-}"
|
||||||
|
|
||||||
|
|
||||||
|
MOUNTED_BY_US=0
|
||||||
|
|
||||||
|
log() {
|
||||||
|
printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*"
|
||||||
|
}
|
||||||
|
|
||||||
|
die() {
|
||||||
|
log "FEHLER: $*"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
unmount_volume() {
|
||||||
|
[ "$MOUNTED_BY_US" = "1" ] || return 0
|
||||||
|
log "Partition wird ausgehaengt"
|
||||||
|
"$VERACRYPT" --text --dismount "$MOUNT_POINT" --non-interactive \
|
||||||
|
|| log "WARNUNG: Aushaengen fehlgeschlagen, bitte in VeraCrypt manuell trennen"
|
||||||
|
MOUNTED_BY_US=0
|
||||||
|
}
|
||||||
|
|
||||||
|
# Die Disk-Nummer wechselt (disk4, disk6, ...). Gesucht wird daher die
|
||||||
|
# Partition 1 auf externen, physischen Platten, die >= MIN_SIZE_GB gross sind
|
||||||
|
# und nicht von macOS eingebunden werden koennen (Typ "Microsoft Basic Data",
|
||||||
|
# verschluesselt). Nur bei genau einem Treffer wird sie verwendet.
|
||||||
|
MIN_SIZE_GB="${MIN_SIZE_GB:-3000}"
|
||||||
|
|
||||||
|
find_offsite_partition() {
|
||||||
|
local disk part bytes
|
||||||
|
local found=()
|
||||||
|
for disk in $(diskutil list external physical | awk '/^\/dev\/disk/ {gsub(/[:]/,"",$1); sub("/dev/","",$1); print $1}'); do
|
||||||
|
part="${disk}s1"
|
||||||
|
diskutil info "$part" >/dev/null 2>&1 || continue
|
||||||
|
diskutil list "$disk" | grep -q "Microsoft Basic Data.*${part}\$" || continue
|
||||||
|
bytes="$(diskutil info "$disk" | sed -n 's/.*Disk Size:.*(\([0-9]*\) Bytes).*/\1/p' | head -1)"
|
||||||
|
[ -n "$bytes" ] && [ "$bytes" -ge $((MIN_SIZE_GB * 1000000000)) ] || continue
|
||||||
|
# Schon eingebundene Partition (normales Dateisystem) ist nicht die gesuchte
|
||||||
|
[ -z "$(diskutil info "$part" | sed -n 's/^ *Mount Point: *\(.\+\)$/\1/p')" ] || continue
|
||||||
|
found+=("/dev/$part")
|
||||||
|
done
|
||||||
|
if [ "${#found[@]}" -ne 1 ]; then
|
||||||
|
log "FEHLER: Keine eindeutige OFFSITE-Partition gefunden (Treffer: ${#found[@]})" >&2
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
log "OFFSITE-Partition erkannt: ${found[0]}" >&2
|
||||||
|
echo "${found[0]}"
|
||||||
|
}
|
||||||
|
|
||||||
|
trap 'unmount_volume' EXIT
|
||||||
|
trap 'log "Abgebrochen"; exit 130' INT TERM
|
||||||
|
|
||||||
|
# **************************************************
|
||||||
|
# Einbinden der VeraCrypt Partition
|
||||||
|
# **************************************************
|
||||||
|
[ -x "$VERACRYPT" ] || die "VeraCrypt nicht gefunden: $VERACRYPT"
|
||||||
|
|
||||||
|
if [ -d "$MOUNT_POINT" ] && mount | grep -q " on $MOUNT_POINT "; then
|
||||||
|
log "Festplatte $VOLUME_LABEL ist bereits eingebunden: $MOUNT_POINT"
|
||||||
|
else
|
||||||
|
if [ -z "$DEVICE" ]; then
|
||||||
|
DEVICE="$(find_offsite_partition)" || exit 1
|
||||||
|
fi
|
||||||
|
# "disk4s1" und "/dev/disk4s1" akzeptieren
|
||||||
|
case "$DEVICE" in
|
||||||
|
disk*) DEVICE="/dev/$DEVICE" ;;
|
||||||
|
esac
|
||||||
|
[ -e "$DEVICE" ] || die "Device nicht gefunden: $DEVICE"
|
||||||
|
|
||||||
|
read -r -s -p "Bitte geben Sie das Passwort fuer die Festplatte $VOLUME_LABEL ein: " VOLUME_PASSWORD
|
||||||
|
echo
|
||||||
|
|
||||||
|
log "Festplatte $VOLUME_LABEL wird entschluesselt und eingebunden"
|
||||||
|
"$VERACRYPT" --text --non-interactive --mount "$DEVICE" "$MOUNT_POINT" \
|
||||||
|
--password="$VOLUME_PASSWORD" --pim=0 --keyfiles="" --protect-hidden=no \
|
||||||
|
|| die "Einbinden mit VeraCrypt fehlgeschlagen"
|
||||||
|
unset VOLUME_PASSWORD
|
||||||
|
MOUNTED_BY_US=1
|
||||||
|
fi
|
||||||
|
|
||||||
|
[ -d "$MOUNT_POINT" ] || die "Festplatte $VOLUME_LABEL nicht gefunden unter $MOUNT_POINT"
|
||||||
|
|
||||||
|
# **************************************************
|
||||||
|
# Kopieren der SMB-Freigaben
|
||||||
|
# **************************************************
|
||||||
|
EXIT_CODE=0
|
||||||
|
|
||||||
|
run_rsync() {
|
||||||
|
local share="$1"
|
||||||
|
local source="/Volumes/$share"
|
||||||
|
|
||||||
|
if [ ! -d "$source" ]; then
|
||||||
|
log "Binde SMB-Freigabe smb://$SOURCE_HOST/$share ein"
|
||||||
|
# Unter sudo als eigentlicher Benutzer oeffnen, damit dessen Keychain/Finder genutzt wird
|
||||||
|
if [ -n "${SUDO_USER:-}" ]; then
|
||||||
|
sudo -u "$SUDO_USER" open "smb://$SOURCE_HOST/$share"
|
||||||
|
else
|
||||||
|
open "smb://$SOURCE_HOST/$share"
|
||||||
|
fi
|
||||||
|
local i
|
||||||
|
for i in 1 2 3 4 5 6 7 8 9 10; do
|
||||||
|
[ -d "$source" ] && break
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
if [ ! -d "$source" ]; then
|
||||||
|
log "WARNUNG: Quelle nicht gefunden, bitte SMB-Freigabe oeffnen: smb://$SOURCE_HOST/$share"
|
||||||
|
EXIT_CODE=1
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Sichere $share"
|
||||||
|
# -r Unterverzeichnisse inkl. leerer, -l Symlinks, -t Zeitstempel (wie /COPY:DAT),
|
||||||
|
# --partial setzt abgebrochene Uebertragungen fort (wie /z). Kein --delete:
|
||||||
|
# robocopy /E spiegelt ebenfalls nicht.
|
||||||
|
rsync -rlt -h -v --progress --partial --stats --exclude=".DS_Store" --exclude="._.DS_Store" "$source/" "$MOUNT_POINT/$share/"
|
||||||
|
local rc=$?
|
||||||
|
if [ "$rc" -ne 0 ]; then
|
||||||
|
log "WARNUNG: rsync fuer $share endete mit Code $rc"
|
||||||
|
EXIT_CODE=1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
for share in "${SHARES[@]}"; do
|
||||||
|
run_rsync "$share"
|
||||||
|
done
|
||||||
|
|
||||||
|
log "Backupprozess beendet"
|
||||||
|
exit "$EXIT_CODE"
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Erstellt ~/Applications/BFDS Offsite Backup.app, damit das Backup per
|
||||||
|
# Spotlight ("bfds offsite backup") gestartet werden kann. Die App oeffnet
|
||||||
|
# ein Terminal-Fenster und startet dort launch-backup.sh (Header, dann sudo-Start)
|
||||||
|
# (Passwort-Abfragen und Ausgabe brauchen ein Terminal).
|
||||||
|
# Kompatibel mit dem mit macOS ausgelieferten Bash 3.2.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
APP_NAME="${APP_NAME:-BFDS Offsite Backup}"
|
||||||
|
APP_DIR="${APP_DIR:-$HOME/Applications}"
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
BACKUP_SCRIPT="$SCRIPT_DIR/launch-backup.sh"
|
||||||
|
APP_PATH="$APP_DIR/$APP_NAME.app"
|
||||||
|
|
||||||
|
[ -x "$BACKUP_SCRIPT" ] || { echo "FEHLER: $BACKUP_SCRIPT nicht ausfuehrbar" >&2; exit 1; }
|
||||||
|
|
||||||
|
mkdir -p "$APP_DIR"
|
||||||
|
rm -rf "$APP_PATH"
|
||||||
|
|
||||||
|
# Pfad fuer AppleScript-String und Shell quoten
|
||||||
|
SHELL_CMD="$(printf '%q' "$BACKUP_SCRIPT")"
|
||||||
|
SHELL_CMD="${SHELL_CMD//\\/\\\\}"
|
||||||
|
SHELL_CMD="${SHELL_CMD//\"/\\\"}"
|
||||||
|
|
||||||
|
/usr/bin/osacompile -o "$APP_PATH" <<EOF
|
||||||
|
set wasRunning to application "Terminal" is running
|
||||||
|
tell application "Terminal"
|
||||||
|
activate
|
||||||
|
if wasRunning then
|
||||||
|
do script "$SHELL_CMD"
|
||||||
|
else
|
||||||
|
-- Terminal oeffnet beim Start selbst ein Fenster: dieses mitverwenden
|
||||||
|
repeat 50 times
|
||||||
|
if (count of windows) > 0 then exit repeat
|
||||||
|
delay 0.1
|
||||||
|
end repeat
|
||||||
|
if (count of windows) > 0 then
|
||||||
|
do script "$SHELL_CMD" in window 1
|
||||||
|
else
|
||||||
|
do script "$SHELL_CMD"
|
||||||
|
end if
|
||||||
|
end if
|
||||||
|
end tell
|
||||||
|
EOF
|
||||||
|
|
||||||
|
echo "Installiert: $APP_PATH"
|
||||||
|
echo "Spotlight: \"bfds offsite backup\" eintippen (Indexierung kann kurz dauern)."
|
||||||
|
|
||||||
|
# Standardmaessig heisst die App intern "applet" (so erscheint sie auch in den
|
||||||
|
# Datenschutz-Listen). Ausfuehrbare Datei, Bundle-Name und -ID umbenennen und neu signieren.
|
||||||
|
PLIST="$APP_PATH/Contents/Info.plist"
|
||||||
|
EXEC_NAME="BFDS-Offsite-Backup"
|
||||||
|
mv "$APP_PATH/Contents/MacOS/applet" "$APP_PATH/Contents/MacOS/$EXEC_NAME"
|
||||||
|
PB=/usr/libexec/PlistBuddy
|
||||||
|
"$PB" -c "Set :CFBundleExecutable $EXEC_NAME" "$PLIST"
|
||||||
|
"$PB" -c "Set :CFBundleName $APP_NAME" "$PLIST"
|
||||||
|
"$PB" -c "Add :CFBundleIdentifier string de.streber24.bfds-offsite-backup" "$PLIST" 2>/dev/null \
|
||||||
|
|| "$PB" -c "Set :CFBundleIdentifier de.streber24.bfds-offsite-backup" "$PLIST"
|
||||||
|
"$PB" -c "Add :CFBundleDisplayName string $APP_NAME" "$PLIST" 2>/dev/null \
|
||||||
|
|| "$PB" -c "Set :CFBundleDisplayName $APP_NAME" "$PLIST"
|
||||||
|
/usr/bin/codesign --force --deep --sign - "$APP_PATH"
|
||||||
|
|
||||||
|
# Voller Festplattenzugriff laesst sich nicht per Script erteilen (macOS schuetzt
|
||||||
|
# die Freigabe, nur MDM oder der Nutzer selbst kann sie setzen). Deshalb: Einstellungen
|
||||||
|
# oeffnen und die App im Finder markieren, zum Hineinziehen in die Liste.
|
||||||
|
echo
|
||||||
|
echo "Bitte jetzt einmalig 'Voller Festplattenzugriff' fuer die App erteilen:"
|
||||||
|
echo " App aus dem Finder-Fenster in die Liste ziehen (oder + klicken) und Schalter aktivieren."
|
||||||
|
open "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles"
|
||||||
|
open -R "$APP_PATH"
|
||||||
+34
@@ -0,0 +1,34 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# Startet das Backup aus der Spotlight-App: zeigt zuerst einen Willkommens-
|
||||||
|
# Header samt Hinweis auf die sudo-Passwortabfrage, dann das eigentliche Script.
|
||||||
|
# Kompatibel mit dem mit macOS ausgelieferten Bash 3.2.
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||||
|
|
||||||
|
clear
|
||||||
|
cat <<'BANNER'
|
||||||
|
#####################################################
|
||||||
|
## ##
|
||||||
|
## BFDS OFFSITE BACKUP ##
|
||||||
|
## ##
|
||||||
|
## NAS-Freigaben -> verschluesselte Platte ##
|
||||||
|
## ##
|
||||||
|
#####################################################
|
||||||
|
|
||||||
|
Willkommen!
|
||||||
|
|
||||||
|
1. Zuerst wird jetzt Dein MAC-PASSWORT (sudo) abgefragt,
|
||||||
|
damit das Programm gestartet werden kann.
|
||||||
|
Beim Tippen erscheinen keine Zeichen.
|
||||||
|
2. Danach folgt das Passwort der VeraCrypt-Festplatte.
|
||||||
|
|
||||||
|
BANNER
|
||||||
|
|
||||||
|
sudo "$SCRIPT_DIR/backup-bfds-storage-offsite.sh"
|
||||||
|
status=$?
|
||||||
|
|
||||||
|
echo
|
||||||
|
read -r -n 1 -s -p "Fertig (Exit-Code $status). Taste druecken zum Schliessen... "
|
||||||
|
echo
|
||||||
|
exit "$status"
|
||||||
Reference in new issue
Block a user