#!/bin/bash # # backup_to_NAS # a script to synchronize local files with those on a remote host # # Mark Alford, Oct 2019 # make a note of whether the script was invoked with the -interactive option # this will change later behavior: we will add in a dry run and an option to abort interactive="false" if [[ $1 == "-interactive" || $1 == "-i" ]] then interactive="true" fi # log file for outcome reporting: log_file=${HOME}/NAS_backups.log # list of subdirectories that we do NOT want to include in the backup: exclusions=(/.wastebasket /.cache /.config /.kde /.local /.mozilla /.wine /.wine-pipelight /rsync_backup) rsync_exclusions_file=`mktemp` for pattern in "${exclusions[@]}" do echo $pattern >> ${rsync_exclusions_file} done remote_storage_mountpoint=/backup dir_to_be_backed_up=/home/${USER} # Check that remote_storage_mountpoint is mounted: echo Checking remote storage mount point ${remote_storage_mountpoint} if findmnt ${remote_storage_mountpoint} >&/dev/null then echo Remote storage ${remote_storage_mountpoint} mounted OK else mount ${remote_storage_mountpoint} if ! ( findmnt ${remote_storage_mountpoint} >&/dev/null ) then echo `date '+%F %R'` Failed to mount remote storage ${remote_storage_mountpoint} >> ${log_file} mount_cmd=`which mount.cifs` if [ ! -u ${mount_cmd} ]; then echo \ \ Need to do: sudo chmod u+s ${mount_cmd} >> ${log_file} fi exit 40 fi fi # For the mount command to work, you need to tell Linux how to mount the backup directory, e.g. via a line like this in fstab: # //192.168.0.15/mari /backup cifs users,noauto,uid=mari,gid=mari,username=mari,password=XXX,file_mode=0644,dir_mode=0755 0 0 # Set rsync options, including a directory where it will backup any files on the NAS that it is asked to delete rsync_backupdir=rsync_backup/`date '+%F'` rsync_opts="-r --progress --times --delete --safe-links --backup --backup-dir=${rsync_backupdir}" from_dir=${dir_to_be_backed_up} to_dir=${remote_storage_mountpoint} echo backing up from ${from_dir} echo \ \ \ \ \ \ \ \ \ \ \ \ \ to ${to_dir} declare -A rsync_code_dict rsync_code_dict=( \ ["0"]="Success" \ ["1"]="Syntax or usage error" \ ["2"]="Protocol incompatibility" \ ["3"]="Errors selecting input/output files, dirs" \ ["4"]="Requested action not supported: an attempt was made to manipulate 64-bit files on a platform that cannot support them; or an option was specified that is supported by the client and not by the server." \ ["5"]="Error starting client-server protocol" \ ["6"]="Daemon unable to append to log-file" \ ["10"]="Error in socket I/O" \ ["11"]="Error in file I/O" \ ["12"]="Error in rsync protocol data stream" \ ["13"]="Errors with program diagnostics" \ ["14"]="Error in IPC code" \ ["20"]="Received SIGUSR1 or SIGINT" \ ["21"]="Some error returned by waitpid()" \ ["22"]="Error allocating core memory buffers" \ ["23"]="Partial transfer due to error" \ ["24"]="Partial transfer due to vanished source files" \ ["25"]="The --max-delete limit stopped deletions" \ ["30"]="Timeout in data send/receive" \ ["35"]="Timeout waiting for daemon connection" ) if [[ "${interactive}" == "true" ]] then # if running interactively we will do a dry run first. At the end we # give a list of all files that would be deleted in the target directory echo Doing dry run first... rsyncout=`mktemp` rsync --dry-run ${rsync_opts} --exclude-from=${rsync_exclusions_file} \ ${from_dir}/ ${to_dir} | tee ${rsyncout} echo echo ==== DELETIONS: grep '^deleting' ${rsyncout} echo ==== echo response="xxx" while [[ $response != 'y' && $response != 'n' ]] do read -p "Now do it for real (y|n)? " response done if [[ ${response} != 'y' ]] then exit 0 fi fi # This is the actual backup, done using rsync: rsync ${rsync_opts} --exclude-from=${rsync_exclusions_file} \ ${from_dir}/ ${to_dir} &> ${HOME}/last_rsync.log rsync_status=$? rsync_message="${rsync_code_dict[${rsync_status}]}" # Logging: write a ststus message to the log file echo `date '+%F %R'` rsync exit status ${rsync_status}: ${rsync_message} >> ${log_file} echo Unmounting remote storage mount point ${remote_storage_mountpoint} umount ${remote_storage_mountpoint} exit ${rsync_status}