backupd/backupd
洛天依 f17345dae8
All checks were successful
Lint / Lint (push) Successful in 15s
initial commit
2025-01-20 02:50:30 +00:00

99 lines
3.6 KiB
Bash
Executable File

#!/usr/bin/bash
# backupd - v1.0.0
# a simple backup script
#
# Copyright (c) 2025 Tianyi CodeLab, under the MIT License.
DATA_DIR="$(cd "$(dirname "$0")" && pwd)"
RCLONE_DEST_NAME="dest"
ZSTD_LEVEL=13
main() {
local backup_name backup_remote
backup_name="backups_$(hostname)_$(date +%Y-%m-%d)_$(date +%H:%M:%S)"
backup_remote="$RCLONE_DEST_NAME:server-$(hostname)"
check_files
# shellcheck disable=SC1091
. "$DATA_DIR/passwd"
if [ -z "$AES_PASSWD" ]; then
echo -ne "\033[1;31mAES_PASSWD is not set in file 'passwd'. Using default hostname as password.\033[0m\n"
echo -ne "\033[1;31mWarning: THIS IS NOT SECURE!\033[0m\n"
AES_PASSWD="$(hostname)"
fi
if [ -z "$ITER_COUNT" ]; then
echo -ne "\033[1;31mITER_COUNT is not set in file 'passwd'. Using default value 100000.\033[0m\n"
ITER_COUNT=100000
fi
local ctx
local tar_file zst_file enc_file ext_list inc_list
local tar_hash zst_hash enc_hash
ctx="$(mktemp -d)"
tar_file="$ctx/$backup_name.tar"
zst_file="$ctx/$backup_name.tar.zst"
enc_file="$ctx/$backup_name.tar.zst.enc"
ext_list="$DATA_DIR/excludes"
inc_list="$DATA_DIR/includes"
echo -ne "\033[1;33mCreating backup $backup_name\033[0m\n"
exec_hooks pre
echo -ne "\033[1;33mCreating archive $tar_file\033[0m\n"
tar -cvf "$tar_file" -X "$ext_list" -T "$inc_list"
echo -ne "\033[1;33mCompressing archive $zst_file\033[0m\n"
zstd -T -${ZSTD_LEVEL} "$tar_file" -o "$zst_file"
echo -ne "\033[1;33mEncrypting archive $enc_file\033[0m\n"
openssl enc -aes-256-cbc -salt -pbkdf2 -iter "$ITER_COUNT" -in "$zst_file" -out "$enc_file" -k "$AES_PASSWD"
tar_hash="$(sha256sum "$tar_file" | cut -d ' ' -f 1)"
zst_hash="$(sha256sum "$zst_file" | cut -d ' ' -f 1)"
enc_hash="$(sha256sum "$enc_file" | cut -d ' ' -f 1)"
echo -ne "\033[1;34mArchive hash: $tar_hash\033[0m\n"
echo -ne "\033[1;34mCompressed hash: $zst_hash\033[0m\n"
echo -ne "\033[1;34mEncrypted hash: $enc_hash\033[0m\n"
echo -ne "\033[1;33mUploading archive to remote...\033[0m\n"
echo -ne "\033[1;34mRemote filename: $backup_remote\033[0m\n"
RCLONE_CONFIG="$DATA_DIR/rclone.conf" rclone copy \
-vv --checksum --no-traverse --s3-no-check-bucket --metadata \
--metadata-set "sha256-enc=$enc_hash" \
--metadata-set "sha256-zst=$zst_hash" \
--metadata-set "sha256-tar=$tar_hash" \
-P "$enc_file" "$backup_remote"
exec_hooks post
rm -rvf "$ctx"
echo -ne "\033[1;34m------------ backup done ------------\033[0m\n"
}
check_files() {
if [ ! -f "$DATA_DIR/includes" ]; then
echo -ne "\033[1;31mCreating configuration file 'includes'...\033[0m\n"
touch "$DATA_DIR/includes"
fi
if [ ! -f "$DATA_DIR/excludes" ]; then
echo -ne "\033[1;31mCreating configuration file 'excludes'...\033[0m\n"
touch "$DATA_DIR/excludes"
fi
if [ ! -d "$DATA_DIR/hooks-pre.d" ]; then
echo -ne "\033[1;31mCreating directory 'hooks-pre.d'...\033[0m\n"
mkdir -p "$DATA_DIR/hooks-pre.d"
fi
if [ ! -d "$DATA_DIR/hooks-post.d" ]; then
echo -ne "\033[1;31mCreating directory 'hooks-post.d'...\033[0m\n"
mkdir -p "$DATA_DIR/hooks-post.d"
fi
}
exec_hooks() {
local hook_type="$1"
echo -ne "\033[1;32mRunning $hook_type hooks...\033[0m\n"
for hook in "$DATA_DIR/hooks-$hook_type.d"/*; do
if [ -x "$hook" ]; then
echo -ne "------------ Running hook: $hook\n"
"$hook"
fi
done
}
main "$@"