## Some default values of important variables ## Settings GPG_RECIPIENT="robin.oburka@nic.cz" ## Style TIME_FMT="Time:\t%E" ## Internal variables NAME="" REMOTE="" GENERATE="" COMMAND="" PLACES="" EXCLUDE="" STORE="" ## Pipeline variables PID_GENERATE="" PID_STORE="" PID_FILE="pids" STAGE="0" test_input() { [ -z "$NAME" ] && error "Specify backup name" [ -z "$COMMAND" -a -z "$PLACES" ] && error "Specify backup subject" [ -n "$COMMAND" -a -n "$PLACES" ] && error "Do not specify two types of backup at once" [ -z "$STORE" ] && error "Specify store command" } name() { NAME="$1" compute_variables } remote() { REMOTE="$1" } generate() { GENERATE="$1" } cmd() { COMMAND="$1" } places() { PLACES="$1" [ "$#" -gt 1 ] && error "Specify places as string" #STR="" #for PLACE in "$@"; do # STR="$STR "$PLACE"" #done #PLACES="$STR" } exclude() { STR="" for EXC in "$@"; do STR="$STR --exclude=$EXC" done EXCLUDE="$STR" } store() { STORE="$1" } error() { echo "ERROR: $1" >&2 exit 1 } die() { if [ -n "$1" ]; then echo "DIE: $1" >&2 fi ## -6 ~ SIGABRT ## This is the only SIGNAL that cleanup doesn't reset kill -6 "$$" } compute_variables() { UTS="$(date +"%s")" TS="$(date +"%Y-%m-%d_%H-%M-%S")" FILENAME="backup_"$NAME"_"$TS".tar" FILENAME_ENC="${FILENAME}.bz2.gpg" RUNDIR="/tmp/backuper_run_dir_$$_$UTS" } title() { TXT="$1" printf "\n%s\n==========================================\n" "$TXT" } get_size() { FILE="$1" du -h "$FILE" | awk '{ print $1 }' } prepare() { echo "prepare $$" trap 'error_handler' EXIT INT QUIT TERM ABRT HUP ILL TRAP BUS FPE SEGV mkdir -p "$RUNDIR" } error_handler() { cleanup exit 42 } cleanup() { echo "Cleaning up... ($$)" >&2 trap - EXIT INT QUIT TERM HUP ILL TRAP BUS FPE SEGV for PID in $(cat "$RUNDIR"/"$PID_FILE"); do if ps --ppid $$ | grep -q "$PID"; then echo "Killing "$PID"" kill "$PID" fi done [ -n "$PID_GENERATE" ] && if ps --ppid $$ | grep -q "$PID_GENERATE"; then echo "Killing "$PID_GENERATE"" kill "$PID_GENERATE" fi [ -n "$PID_STORE" ] && if ps --ppid $$ | grep -q "$PID_STORE"; then echo "Killing "$PID_STORE"" kill "$PID_STORE" fi if [ -d "$RUNDIR" ]; then rm -rf "$RUNDIR" fi } add_stage() { ## Prepare pipes NEXTSTAGE="$((STAGE+1))" [ ! -p "$RUNDIR"/fifo_"$STAGE" ] && mkfifo "$RUNDIR"/fifo_"$STAGE" [ ! -p "$RUNDIR"/fifo_"$NEXTSTAGE" ] && mkfifo "$RUNDIR"/fifo_"$NEXTSTAGE" ## Run requested command and store PID $@ > "$RUNDIR"/fifo_"$NEXTSTAGE" < "$RUNDIR"/fifo_"$STAGE" || die & echo "$!" >> "$RUNDIR"/"$PID_FILE" ## Process started - increment STAGE="$NEXTSTAGE" } start_store() { STORE="$STORE < "$RUNDIR"/fifo_"$NEXTSTAGE"" echo "$STORE" | sh -s } start_command() { title "Create backup" if [ -n "$COMMAND" ]; then echo "$COMMAND" | $REMOTE $GENERATE sh -s > "$RUNDIR"/fifo_0 else ## Exclude keep without quotes /usr/bin/time -f "$TIME_FMT" $REMOTE $GENERATE tar c --preserve-permissions $EXCLUDE "$PLACES" > "$RUNDIR"/fifo_0 fi } start_pipeline() { add_stage "mbuffer -q -m 100M" add_stage "pbzip2" add_stage "mbuffer -q -m 100M" add_stage "gpg -z0 -r robin.oburka@nic.cz -e" add_stage "mbuffer -q -m 100M" start_store || die & PID_STORE=$! start_command || die & PID_GENERATE=$! wait "$PID_STORE" "$PID_GENERATE" for PID in $(cat "$RUNDIR"/"$PID_FILE"); do wait "$PID" done } run() { title "Run command" echo "$@" echo $@ | $REMOTE sh -s printf "\n" } store_file() { [ -z "$1" ] && error "Specify destination" store "sh -c 'cat > ${1}/${FILENAME_ENC}'" } #enc() { # title "Encrypt" # /usr/bin/time -f "$TIME_FMT" gpg --compress-algo zlib --recipient "$GPG_RECIPIENT" -e "$DST"/"$FILENAME" # [ "$?" != 0 ] && die "Encription failed" # rm "$DST"/"$FILENAME" # printf "Encrypted backup:\t%s (%s)\n\n" "$FILENAME_ENC" "$(get_size "$DST"/"$FILENAME_ENC")" #} # backup() { test_input prepare start_pipeline cleanup }