#!/usr/bin/env bash ################################ # ckupeye executable # # (Frogeye's backup script v4) # ################################ # # Load config file # CLIENT_CONFIG_FILE="${1:-/etc/ckupeye/config.sh}" if [ -f "$CLIENT_CONFIG_FILE" ] then . "$CLIENT_CONFIG_FILE" else echo "Configuration file not found on $CLIENT_CONFIG_FILE." exit 1 fi # # Required configuration # if [ -z ${BORG_REPO+x} ] then echo "Please specify BORG_REPO in the configuration file." echo "See https://borgbackup.readthedocs.io/en/stable/usage/general.html?highlight=borg_repo#repository-urls" exit 1 fi if [[ -z ${BORG_PASSPHRASE+x} && -z ${BORG_PASSCOMMAND+x} && -z ${BORG_PASSPHRASE_FD+x} ]] then echo "Please specify one of BORG_PASSPHRASE, BORG_PASSCOMMAND or BORG_PASSPHRASE_FD in the configuration file." echo "See https://borgbackup.readthedocs.io/en/stable/man_intro.html?highlight=borg_passphrase#environment-variables" exit 1 fi # # Default configuration # : "${BASE_DIR:="/var/lib/ckupeye"}" # Directories to backup [ -z ${BACKUP_FILES+x} ] && BACKUP_FILES=("/") # What to include in the backup [ -z ${BACKUP_EXCLUDES+x} ] && BACKUP_EXCLUDES=("/var/cache" "**.lock" "**/.cache/") # What to exclue from the backup : "${BACKUP_TAG:="$(date -Isec)"}" # “Name” of the backup : "${BACKUP_OPTIONS:="--one-file-system --compression auto,zstd"}" # Configuration of the backup # Default folder where the database / package managers / ACL exported data will be stored. : "${EXPORT_DIR:="$BASE_DIR"}" # Things to export the data of : "${EXPORT_MARIADB:="false"}" : "${EXPORT_POSTGRESQL:="false"}" : "${EXPORT_APT:="false"}" : "${EXPORT_PACMAN:="false"}" : "${EXPORT_ACL:="false"}" : "${EXPORT_ETCKEEPER:="false"}" # Where to put the exported data : "${EXPORT_MARIADB_FILE:="$EXPORT_DIR/mariadb.sql"}" : "${EXPORT_POSTGRESQL_FILE:="$EXPORT_DIR/postgresql.sql"}" : "${EXPORT_APT_FILE:="$EXPORT_DIR/apt.list"}" : "${EXPORT_PACMAN_FILE:="$EXPORT_DIR/pacman.list"}" : "${EXPORT_ACL_FILE:="$EXPORT_DIR/acl.list"}" # Options for exporting data [ -z ${EXPORT_ACL_DIRECTORIES+x} ] && EXPORT_ACL_DIRECTORIES=("${BACKUP_FILES[@]}") : "${EXPORT_ETCKEEPER_MESSAGE:="ckupeye backup for $(date -Isec)"}" : "${EXPORT_POSTGRESQL_OPTIONS:=""}" : "${EXPORT_MARIADB_OPTIONS:="--all-databases --flush-privileges"}" : "${EXPORT_MARIADB_CREDENTIALS:="$BASE_DIR/mariadb.cnf"}" # Pruning the backup : "${PRUNE:="false"}" : "${PRUNE_OPTIONS:="--keep-hourly 24 --keep-daily 7 --keep-weekly 4 --keep-monthly 12 --keep-yearly 10"}" # Borg specific : "${BORG_BASE_DIR:="$BASE_DIR"}" : "${BORG_EXECUTABLE:="$(command -v borg)"}" # Path to BorgBackup executable : "${BORG_SSH_IDENTITY_FILE:="/etc/ckupeye/id_ed25519"}" # Identity file to use to connect to remote repo (will overwrite $BORG_RSH) : "${BORG_RSH_EXTRA:=""}" # Options to add to $BORG_RSH (even after overriden by BORG_SSH_IDENTITY_FILE) : "${BORG_OPTIONS:=""}" # Additional options to pass to BorgBackup : "${BORG_ENCRYPTION:="repokey-blake2"}" # Passed `borg init` # Answer borg questions : "${BORG_UNKNOWN_UNENCRYPTED_REPO_ACCESS_IS_OK:="no"}" : "${BORG_RELOCATED_REPO_ACCESS_IS_OK:="no"}" : "${BORG_CHECK_I_KNOW_WHAT_I_AM_DOING:="NO"}" : "${BORG_DELETE_I_KNOW_WHAT_I_AM_DOING:="NO"}" : "${BORG_RECREATE_I_KNOW_WHAT_I_AM_DOING:="NO"}" # Ckupeye specific : "${CLIENT_RUNFILE:="$BASE_DIR/ckupeye.pid"}" # Vim macro to copy the above defaults to the config file (minus the arrays): # :%s/: "\${\(\w\+\):=\(.\+\)}"/\1=\2 # Export borg environment variables export BORG_REPO export BORG_PASSPHRASE export BORG_PASSCOMMAND export BORG_PASSPHRASE_FD export BORG_BASE_DIR # this should be done in the configuration file too, # for consistency # # Preparation # if [ -z $BORG_EXECUTABLE ] then echo "Borg executable not found." exit 1 fi if [ -e $CLIENT_RUNFILE ] && ps -p $(cat $CLIENT_RUNFILE) > /dev/null then echo "Another backup instance is running. Skipping" exit 1 fi if ! touch $CLIENT_RUNFILE then echo "Could not create a runfile on $CLIENT_RUNFILE. Please change CLIENT_RUNFILE according to this user's permissions." exit 1 fi echo $$ > $CLIENT_RUNFILE # # Test repository, create it if not present # if [ ! -z "$BORG_SSH_IDENTITY_FILE" ] then export BORG_RSH="ssh -oIdentitiesOnly=yes -oBatchMode=yes -i $BORG_SSH_IDENTITY_FILE $BORG_RSH_EXTRA" fi echo "→ Opening repository" $BORG_EXECUTABLE $BORG_OPTIONS info if [ $? != 0 ] then echo "→ Could not open repository, trying to create it" $BORG_EXECUTABLE $BORG_OPTIONS init --encryption "$BORG_ENCRYPTION" if [ $? != 0 ] then echo "Could not create repository." exit 1 fi fi # # Exporting databases # if [ ! -z ${EXPORT_DIR+x} ] then mkdir -p "$EXPORT_DIR" fi if $EXPORT_ETCKEEPR then echo → Creating etckeeper commit etckeeper commit "$EXPORT_ETCKEEPER_MESSAGE" &> /dev/null & fi function _feedExport() { # export_file touch "$1" chmod 700 "$1" cat - > "$1" } EXPORT_FILEs="" if $EXPORT_ACL then echo → Exporting ACL sudo getfacl -R "$EXPORT_ACL_DESTINATION[@]" 2> /dev/null | _feedExport "$EXPORT_ACL_FILE" EXPORT_FILES="$EXPORT_ACL_FILE $EXPORT_FILES" fi if $EXPORT_POSTGRESQL then echo → Exporting PostgreSQL sudo -u postgres pg_dumpall $EXPORT_POSTGRESQL_OPTIONS | _feedExport "$EXPORT_POSTGRESQL_FILE" EXPORT_FILES="$EXPORT_POSTGRESQL_FILE $EXPORT_FILES" fi if $EXPORT_MARIADB then echo → Exporting MariaDB if [ ! -z $EXPORT_MARIADB_CREDENTIALS ] then EXPORT_MARIADB_OPTIONS="--defaults-extra-file=$EXPORT_MARIADB_CREDENTIALS $EXPORT_MARIADB_OPTIONS" fi mysqldump $EXPORT_MARIADB_OPTIONS | _feedExport "$EXPORT_MARIADB_FILE" EXPORT_FILES="$EXPORT_MARIADB_FILE $EXPORT_FILES" fi if $EXPORT_PACMAN then echo → Exporting Pacman package list pacman -Qeq | _feedExport "$EXPORT_PACMAN_FILE" EXPORT_FILES="$EXPORT_PACMAN_FILE $EXPORT_FILES" fi if $EXPORT_APT then echo → Exporting Apt package list apt list --installed 2> /dev/null | _feedExport "$EXPORT_APT_FILE" EXPORT_FILES="$EXPORT_APT_FILE $EXPORT_FILES" fi echo "→ Transfering files" for exclude in "${BACKUP_EXCLUDES[@]}" do BACKUP_OPTIONS="$BACKUP_OPTIONS --exclude=$exclude" done sudo -E $BORG_EXECUTABLE $BORG_OPTIONS create --stats $BACKUP_OPTIONS "${BORG_REPO}::${BACKUP_TAG}" ${BACKUP_FILES[@]} $EXPORT_FILES 2>&1 echo "→ Remove temporary files" rm -f $EXPORT_FILES if $PRUNE then echo "→ Pruning old backups" $BORG_EXECUTABLE $BORG_OPTIONS prune --stats $PRUNE_OPTIONS $BORG_REPO 2>&1 fi echo "→ Done!" rm "$CLIENT_RUNFILE"