# -*- mode: sh; sh-basic-offset: 3; indent-tabs-mode: nil; -*- # vim: set filetype=sh sw=3 sts=3 expandtab autoindent: defined_backends=() available_backends=() function init_backends () { for backend in "${defined_backends[@]}"; do . "$libdirectory/backends/$backend" if "backend_${backend}_init"; then append available_backends "$backend" debug "Backend '$backend' is available on this system" else debug "Backend '$backend' is not available on this system" fi done } function init_source_hosts () { # Use our first argument as the name of a configuration parameter to # load the hosts from, or use the "hosts" parameter if nothing was # passed. If the parameter is empty, use "localhost". getconf_words "hosts" "local:" # Allow the default backend variable to be overridden in this # handler's configuration, but fall back to the global default # backend. We use printconf instead of getconf to prevent the global # $default_backend from getting clobbered. local_default_backend=`printconf "default_backend" $default_backend` # Check to see if the default backend is valid (don't check # availability yet, though) if [ -n "$local_default_backend" ] && ! backend_defined "$local_default_backend"; then fatal "Default backend '$local_default_backend' does not exist" fi local hostspec for hostspec in "${hosts[@]}"; do # Find the backend local backend=`backend_for_hostspec "$hostspec"` if [ -z "$backend" ]; then if [ -z "$local_default_backend" ]; then fatal "No default backend set and no explicit backend in hostspec '$hostspec'" else backend=$local_default_backend fi fi # Check if the backend is valid and available if ! backend_defined "$backend"; then fatal "Backend '$backend' does not exist" elif ! backend_available "$backend"; then fatal "Backend '$backend' is not available on this system" fi # Check if the host is available local reason local host=`host_for_hostspec "$hostspec"` if ! "backend_${backend}_host_available" "$host" reason; then fatal "Host '$hostspec' is not available: $reason" fi # Everything is ok, we can run on this host! done; } # Run the function pointed to by $1 for each of the source hosts defined # in the configuration. Sets up the current backend and source host # variables, so source_run & friends can be used. Also sets up the $root # variable to point to the current source host's root filesystem (with # no trailing /). # This function should only be used after calling init_source_hosts. function run_for_source_hosts () { # $hosts will have been filled by init_source_hosts for hostspec in "${hosts[@]}"; do current_backend=`backend_for_hostspec "$hostspec"` current_host=`host_for_hostspec "$hostspec"` # Set the current source's root. root=`"backend_${current_backend}_host_root" "$current_host"` info "Running on $current_backend:$current_host" # Run the actual backup handler "$1" done } # Run the given command on the current source host. # The command should be $1, with $2, $3, etc. being its arguments. source_run () { "backend_${current_backend}_run" "$@" } function backend_available () { in_array "$1" "${available_backends[@]}" } function backend_defined () { in_array "$1" "${defined_backends[@]}" } function backend_for_hostspec () { echo "$1" | sed 's/^\(\([^:]*\):\)\?\(.*\)$/\2/' } function host_for_hostspec () { echo "$1" | sed 's/^\(\([^:]*\):\)\?\(.*\)$/\3/' } # Replaces escape sequences in $1 with the proper values for the current # backend. # The result is put on stdout. If $2 is empty, values for the host are # replaced. The following values are replaced: # # %% Literal % # %h The short hostname (as returned by hostname -s) # %H The full hostname (as returned by hostname --fqdn) # %n The vserver name, or empty for the host # %N The vserver name, or "host" for the host # %v The vserver root directory, or empty for the host # # Note that the given vserver must be running! # function interpolate() { path=$1 expr='' # Allow backends to supply extra vars vars=`"backend_${current_backend}_interpolate_vars"` vars="h H s S r $vars" for var in $vars; do # Do indirect lookup of the value to replace val=`interpolate_value "$var"` # Escape slashes, backslashes and ampersands, since those have # special meaning for sed (note that we need to double the \ # twice, since it has special meaning to bash in the val= # assignment, but also to sed. val=`echo "$val" | sed 's#[/&\\\\]#\\\\&#g'` # Add replacement pattern. The first part checks that there is # an odd number of percent signs before the variable, so # double % is properly left alone. expr="${expr}s/\(\(^\|[^%]\)\(%%\)*\)%$var/\1$val/g;" done # Finally replace literal % signs expr="${expr}s/%%/%/g" # Do the actual interpolation echo $path | sed "$expr" } function interpolate_value () { case "$1" in h) `source_run hostname -s`;; H) `source_run hostname --fqdn`;; s) echo "$current_host";; S) echo "$current_backend:$current_host";; r) echo "$root";; # Not one of the defaults, ask the backend *) "backend_${current_backend}_interpolate_value" "$current_host" "$1" esac }