#!/bin/bash # Informational output w/ happy colors debug () { [[ $DEBUG ]] && echo -e '\033[1;33mDEBUG ::\033[1;m ' $* } info () { echo -e '\033[1;34m::\033[1;m ' $* } die () { echo -e '\033[1;31mFATAL ::\033[1;m ' $* >&2 exit 1 } mount_squash () { # Arguments: none # Returns: return code of mount command mount -t loop,ro "$SEED" "${BKUP_ROOT}/ro" return $? } mount_union_with_bins () { # Arguments: numbers of bins to be mounted (variable number) # Returns: 0 on successful mount, non-zero on failure # Mount first as rw, shift, and mount the rest ro branches="br=${BINS_DIR}/$1=rw:"; shift for bin in $*; do branches="${branches}/bins/$bin=ro:" done branches="${branches}${BKUP_ROOT}/ro=ro" debug "mount -t aufs none "${BKUP_ROOT}/rw" -o udba=reval,$branches" mount -t aufs none "${BKUP_ROOT}/rw" -o udba=reval,$branches return $? } get_next_available_bin () { # Arguments: none # Returns: Numeric value of the next unused bin return $[ $(cut -d: -f1 "$BINVENTORY" | sort -n | tail -1) + 1 ] } sweep_bins () { # Arguments: none # Returns: none count=1 # Make sure bins are numbered in order, clean up if not. In other words, # if we have 10 bins, make sure they're ordered 1 through 10. for bin in "${BINS_DIR}/*"; do if [[ ! -d "${BINS_DIR}/$count" ]]; then high_bin=$(ls "${BINS_DIR}" | sort -n | tail -1) mv "${BINS_DIR}/$high_bin" "${BINS_DIR}/$count" sed -i "/^$high_bin:/s/^$high_bin:/$count:/" "$BINVENTORY" fi count=$[ $count + 1 ] done } call_rsync () { # Arguments: none # Returns: return code from rsync # Parse includes and excludes from heredocs in config INCLUDES=($(sed -n '/^<> "$BINVENTORY" return $? } # Unmounting functions unmount_union () { # Args: none # Returns: return code from umount umount "${BKUP_ROOT}/rw" return $? } unmount_seed () { # Args: none # Returns: return code from umount umount "${BKUP_ROOT}/ro" return $? } unmount_all () { # Args: none # Returns: none # Union MUST be unmounted first unmount_union unmoun_seed } check_for_resquash () { # Args: none # Returns: number of bins needing to be merged local number_of_bins=$(wc -l "$BINVENTORY") if [[ $number_of_bins -gt $MAX_BINS ]]; then return $[ $number_of_bins - $MIN_BINS ] else return 0 fi } create_new_squash () { # Args: number of bins to be squashed (as determined by check_for_resquash), -1 on initial creation # Returns: 0 on success, non-zero on failure # If making first seed, create it empty and return if [[ $1 -eq -1 ]]; then mksquashfs "${BKUP_ROOT}/rw" "$SEED" -b 65536 return $? fi # Determine oldest $1 bins and mount them with the current squash local old_bins=($(sort -n -r -t: -k2 "$BINVENTORY" | tail -$1 | cut -d: -f1)) mount_union_with_bins ${old_bins[@]} # Create new squash with temp name mksquashfs "${BKUP_ROOT}/rw" "$SEED.replace" -b 65536 # If the squash wasn't made correctly, we don't want to continue if [[ $? -ne 0 ]]; then return 1 fi unmount_all # Replace old squash mv "${SEED}.replace" "$SEED" # Delete old bins, and remove entry from binventory for bin in $old_bins; do rm -rf "${BKUP_ROOT}/bins/$bin" sed -i "/^$bin:/d" "$BINVENTORY" done } create_new_incremental () { # Args: none # Returns: 0 on success, non-zero on error # Make a new bin for this incremenetal get_next_available_bin create_new_bin $? # Determine the mount order via binventory bin_order=($(sort -n -r -t:2 -k2 "$BINVENTORY" | cut -d: -f1)) mount_union_with_bins ${BIN_ORDER[@]} # Die with error on mount, else start rsync if [[ $? -ne 0 ]]; then return 1; fi call_rsync return $? }