diff --git a/backup.sh b/backup.sh new file mode 100755 index 0000000000000000000000000000000000000000..d8a3ad96055dd9d887f32e29f8d398efbe59d554 --- /dev/null +++ b/backup.sh @@ -0,0 +1,178 @@ +#!/bin/bash +snipeitDirectory="/var/www/html/snipeit" +backupDirectory="$snipeitDirectory/storage/app/backups" +dbDumpFile="$snipeitDirectory/vendor/spatie/db-dumper/src/Databases/MySql.php" +destinationDir="/export/home/snipeit/backups" + +#/ Usage: backup.sh [-dbmof] +#/ +#/ Create an incremental backup of a snipeit-instance +#/ +#/ OPTIONS: +#/ -d | --snipeit-directory Set the directory of the instance to be backed up +#/ -b | --backup-directory Set the directory where SnipeIT places the internal backups +#/ -m | --mysql-dump-settings Set the location of the database dump settings file +#/ -o | --output-directory Set the output directory for where to place the backups +#/ -f | --full-backup Make a new, full, backup instead of an incremental one +#/ -h | --help Show this message. + +print_usage () { + grep '^#/' <"$0" | cut -c 4- + exit 1 +} + +#Parse arguments +while [[ $# > 0 ]]; do + case "$1" in + -d|--snipeit-directory) + shift + if test $# -gt 0; then + snipeitDirectory=$(echo "$1" | sed "s,/$,,") + else + echo "No SnipeIT directory specified" + exit 1 + fi + shift + ;; + -b|--backup-directory) + shift + if test $# -gt 0; then + backupDirectory=$(echo "$1" | sed "s,/$,,") + else + echo "No backup directory specified" + exit 1 + fi + shift + ;; + -m|--mysql-dump-settings) + if test $# -gt 0; then + dbDumpFile=$1 + else + echo "No database dump settings specified" + exit 1 + fi + shift + ;; + -o|--output-directory) + if test $# -gt 0; then + destinationDir=$(echo "$1" | sed "s,/$,,") + else + echo "No output directory specified" + exit 1 + fi + shift + ;; + -f|--full-backup) + echo "Creating full backup" + mkdir "$destinationDir/$(date +%s)" + shift + ;; + -h|--help) + print_usage + exit 1 + ;; + -*) + echo "Error: invalid argument: '$1'" 1>&2 + print_usage + exit 1 + ;; + esac +done + +if ! [ -d "$destinationDir/" ]; then + echo "Output directory not found: $destinationDir" + exit 0 +fi + +if ! [ -d "$snipeitDirectory/" ]; then + echo "SnipeIT directory not found: $snipeitDirectory" + exit 0 +fi + +if ! [ -d "$backupDirectory/" ]; then + echo "Backup directory not found: $backupDirectory" + exit 0 +fi + +if ! [ -f "$dbDumpFile" ]; then + echo "Database dump settings file not found: $dbDumpFile" + exit 0 +fi + +#Update value in config file to get correct format +sed -i 's/protected $useExtendedInserts = true;/protected $useExtendedInserts = false;/' $dbDumpFile + +#Generate the internal backup +cd $snipeitDirectory +php artisan backup:run +backupFile=$(ls -lt $backupDirectory | head -3 | tail -1 | awk '{print $9}') +extractDir=$(echo $backupFile | cut -f 1 -d '.') +echo "Current backup: $extractDir" + +#Create the workdir and copy all the important files to it +workdir=$(mktemp -d) +cd $workdir +echo "Tmp dir: $workdir" +mkdir new +unzip -qq "$backupDirectory/$backupFile" -d "./$extractDir" > /dev/null 2>&1 +cd $extractDir +echo "Copied:" +find . -path ".$snipeitDirectory/public/uploads/barcodes" -prune -o -print| egrep '(*\.png|*\.jpg|*\.webp|*\.gif|*\.svg|\.env)$' | cpio -pdmu ../new/ +cd ../ +cp -r $extractDir/db-dumps new/ + +now=$(date +%s) + +#If there are no previous full backups, then create one +if [ -z "$(ls -A "$destinationDir/")" ]; then + mkdir "$destinationDir/$now" +fi + +lastBackup=$(ls -lt $destinationDir | head -2 | tail -1 | awk '{print $9}') + +#If there are no patches, create a folder for them +if ! [ -d "$destinationDir/$lastBackup/patches" ]; then + mkdir "$destinationDir/$lastBackup/patches" +fi + +#Check and copy all files (images, .env) that are either new or changed. +cd new +files=$(find ".$snipeitDirectory" -type f) +echo "Files to check:" +echo "$files" +echo "Trying to copy:" + +while IFS= read -r file; do + if ! [ -f "$destinationDir/$lastBackup/$(echo $file | cut -c 3-)" ] || [ "$destinationDir/$lastBackup/$(echo $file | cut -c 3-)" -ot "$file" ]; then + cp -u --parents "$file" "$destinationDir/$lastBackup/" + echo "Copied $file $destinationDir/$lastBackup/$(echo $file | cut -c 3-)" + else + echo "File already exists: $destinationDir/$lastBackup/$(echo $file | cut -c 3-)" + fi +done <<< "$files" + +#Try to make a patch of the database dump +file="db-dumps/mysql-snipeit.sql" +if [ -z "$(ls -A "$destinationDir/$lastBackup/patches")" ]; then + diff -urN null $file > patch.patch + cp "patch.patch" "$destinationDir/$lastBackup/patches/$now.patch" + echo "Copied patch to $destinationDir/$lastBackup/patches/$now.patch" +else + for p in "$destinationDir/$lastBackup/patches/*.patch"; do + (patch --quiet -p1) < $p + done + + result=$(diff "mysql-snipeit.sql" "$file" > "$now.patch" && echo $? || echo $?) + + #Only save non-empty patches + if [ $result != 0 -a $result != 1 ]; then + echo "Nothing to patch" + exit 1 + fi + if [ -s "$now.patch" ]; then + cp "$now.patch" "$destinationDir/$lastBackup/patches/" + echo "Copied patch to $destinationDir/$lastBackup/patches/$now.patch" + else + echo "Nothing to patch" + fi +fi