#!/data/data/com.termux/files/usr/bin/bash # https://neverpanic.de/blog/2022/01/25/backing-up-your-android-phone-with-borgbackup/ #export HOST="" #export HOSTNAME="" #export TARGET="borg@${HOST}:/backup/${HOSTNAME}" #export BORG_PASSPHRASE='' #export BORG_RSH="" source $HOME/backup/env.sh declare -a TERMUX_NOTIFICATIONS=() TERMUX_NOTIFICATION_ID="borgbackup-${HOSTNAME}" set -o pipefail cleanup() { for notification in "${TERMUX_NOTIFICATIONS[@]}"; do termux-notification-remove "$notification" done termux-wake-unlock } ## # Send a notification to the user. # # Usage: echo "message" | notify persist identifier [options...] # # If persist is 0, the notification will be removed when the script exits. # Otherwise, it will be kept (e.g. for warning or error messages). # # The identifier can be used to overwrite a previous notification with the same # identifier. This can be useful for progress messages. # # Further options are those supported by termux-notification. The message must # be passed on stdin. notify() { local persist=$1 shift local id="$1" shift local -a args=("--group" "${TERMUX_NOTIFICATION_ID}" "--id" "$id") if termux-notification "${args[@]}" "$@"; then if [ "$persist" -eq 0 ]; then TERMUX_NOTIFICATIONS+=("$id") fi fi } msg() { echo "***" "$@" } info() { msg "INFO:" "$@" termux-toast -s "$*" } warn() { msg "WARN:" "$@" echo "Warning:" "$@" | \ notify 1 failure \ --title "borgbackup" \ --alert-once \ --priority low } err() { msg "ERROR:" "$@" echo "Error:" "$@" | \ notify 1 failure \ --title "borgbackup" \ --alert-once \ --priority high exit 1 } prepare() { if ! termux-battery-status | grep "status" | grep -qE '"(CHARGING|FULL)"'; then warn "Not charging, not performing backup" return 1 fi if ! termux-wifi-connectioninfo | grep "supplicant_state" | grep -q "COMPLETED"; then warn "WiFi not connected, not performing backup" return 1 fi if ! ping -w 10 -c 3 "$HOST" >/dev/null; then warn "Failed to ping target $HOST" return 1 fi } backup() { local -a flags=() # enable interactive output if [ -t 0 ] && [ -t 1 ]; then flags+=('--stats' '--progress' '--list') fi info "Starting backup" ionice -c 3 \ nice -n20 \ borg create \ --noatime \ --compression='lz4' \ --exclude-caches \ --exclude='fm:/storage/emulated/0/*/.thumbnails' \ --exclude='pp:/data/data/com.termux/files/home/.config/borg' \ --exclude='pp:/storage/emulated/0/Android/data' \ --exclude='pp:/storage/emulated/0/DCIM/Camera' \ --exclude='pp:/storage/emulated/0/Android/obb' \ "${flags[@]}" \ "${TARGET}::${HOSTNAME}-{utcnow:%Y-%m-%dT%H:%M:%S}" \ /storage/emulated/0/ \ /data/data/com.termux/files/home } prune() { local -a flags=() # enable interactive output if [ -t 0 ] && [ -t 1 ]; then flags+=('--stats' '--list') fi info "Pruning old backups..." borg prune \ --prefix="${HOSTNAME}-" \ --keep-within=14d \ --keep-daily=31 \ --keep-weekly=$((6 * 4)) \ --keep-monthly=$(( 2 * 12 )) \ "${flags[@]}" \ "${TARGET}" } # Run once per day, unless BORGBACKUP_FORCE=1 MARKER_FILE=~/.borgbackup-"${HOSTNAME}-$(date +%Y-%m-%d)" if [ "${BORGBACKUP_FORCE:-0}" -eq 0 ]; then if [ "$(date +%H)" -lt 4 ]; then echo "Backup not yet due, waiting..." exit 0 elif [ -f "$MARKER_FILE" ]; then echo "Backup already ran today" exit 0 fi fi if ! prepare; then info "Server connectivity or charging status does not meet expectations, skipping backup." exit 1 fi rm -f ~/.borgbackup-"${HOSTNAME}"-* touch "$MARKER_FILE" trap "cleanup" EXIT termux-wake-lock notify 0 progress \ --alert-once \ --ongoing \ --priority low \ --title "borgbackup" \ --content "Running backup for ${HOSTNAME}" if ! backup; then err "Backup failed, aborting!" fi if ! prune; then warn "Pruning failed. Continuing anyway." fi info "Backup finished successfully"