Add local and chroot backends.
[matthijs/upstream/backupninja.git] / lib / backend.in
1 # -*- mode: sh; sh-basic-offset: 3; indent-tabs-mode: nil; -*-
2 # vim: set filetype=sh sw=3 sts=3 expandtab autoindent:
3
4 defined_backends=(local, chroot)
5 available_backends=()
6
7 function init_backends () {
8    for backend in "${defined_backends[@]}"; do
9       . "$libdirectory/backends/$backend"
10       if "backend_${backend}_init"; then
11          append available_backends "$backend"
12          debug "Backend '$backend' is available on this system"
13       else
14          debug "Backend '$backend' is not available on this system"
15       fi
16    done
17 }
18
19 function init_source_hosts () {
20    # Use our first argument as the name of a configuration parameter to
21    # load the hosts from, or use the "hosts" parameter if nothing was
22    # passed. If the parameter is empty, use "localhost".
23    getconf_words "hosts" "local:"
24    # Allow the default backend variable to be overridden in this
25    # handler's configuration, but fall back to the global default
26    # backend. We use printconf instead of getconf to prevent the global
27    # $default_backend from getting clobbered.
28    local_default_backend=`printconf "default_backend" $default_backend`
29
30    # Check to see if the default backend is valid (don't check
31    # availability yet, though)
32    if [ -n "$local_default_backend" ] && ! backend_defined "$local_default_backend"; then
33       fatal "Default backend '$local_default_backend' does not exist"
34    fi
35
36    local hostspec
37    for hostspec in "${hosts[@]}"; do
38
39       # Find the backend
40       local backend=`backend_for_hostspec "$hostspec"`
41       if [ -z "$backend" ]; then
42          if [ -z "$local_default_backend" ]; then
43             fatal "No default backend set and no explicit backend in hostspec '$hostspec'"
44          else
45             backend=$local_default_backend
46          fi
47       fi
48
49       # Check if the backend is valid and available
50       if ! backend_defined "$backend"; then
51          fatal "Backend '$backend' does not exist"
52       elif ! backend_available "$backend"; then
53          fatal "Backend '$backend' is not available on this system"
54       fi
55
56       # Check if the host is available
57       local reason
58       local host=`host_for_hostspec "$hostspec"`
59       if ! "backend_${backend}_host_available" "$host" reason; then
60          fatal "Host '$hostspec' is not available: $reason"
61       fi
62
63       # Everything is ok, we can run on this host!
64    done;
65 }
66
67 # Run the function pointed to by $1 for each of the source hosts defined
68 # in the configuration. Sets up the current backend and source host
69 # variables, so source_run & friends can be used. Also sets up the $root
70 # variable to point to the current source host's root filesystem (with
71 # no trailing /).
72 # This function should only be used after calling init_source_hosts.
73 function run_for_source_hosts () {
74    # $hosts will have been filled by init_source_hosts
75    for hostspec in "${hosts[@]}"; do
76       current_backend=`backend_for_hostspec "$hostspec"`
77       current_host=`host_for_hostspec "$hostspec"`
78       # Set the current source's root.
79       root=`"backend_${current_backend}_host_root" "$current_host"`
80
81       info "Running on $current_backend:$current_host"
82
83       # Run the actual backup handler
84       "$1"
85    done
86 }
87
88 # Run the given command on the current source host.
89 # The command should be $1, with $2, $3, etc. being its arguments.
90 source_run () {
91    "backend_${current_backend}_run" "$@"
92 }
93
94 function backend_available () {
95    in_array "$1" "${available_backends[@]}"
96 }
97
98 function backend_defined () {
99    in_array "$1" "${defined_backends[@]}"
100 }
101
102 function backend_for_hostspec () {
103    echo "$1" | sed 's/^\(\([^:]*\):\)\?\(.*\)$/\2/'
104 }
105
106 function host_for_hostspec () {
107    echo "$1" | sed 's/^\(\([^:]*\):\)\?\(.*\)$/\3/'
108 }
109
110
111 # Replaces escape sequences in $1 with the proper values for the current
112 # backend.
113 # The result is put on stdout.  If $2 is empty, values for the host are
114 # replaced. The following values are replaced:
115 #
116 # %%  Literal %
117 # %h  The short hostname (as returned by hostname -s)
118 # %H  The full hostname (as returned by hostname --fqdn)
119 # %n  The vserver name, or empty for the host
120 # %N  The vserver name, or "host" for the host
121 # %v  The vserver root directory, or empty for the host
122 #
123 # Note that the given vserver must be running!
124 #
125 function interpolate() {
126    path=$1
127
128    expr=''
129    # Allow backends to supply extra vars
130    vars=`"backend_${current_backend}_interpolate_vars"`
131    vars="h H s S r $vars"
132    for var in $vars; do
133       # Do indirect lookup of the value to replace
134       val=`interpolate_value "$var"`
135       # Escape slashes, backslashes and ampersands, since those have
136       # special meaning for sed (note that we need to double the \
137       # twice, since it has special meaning to bash in the val=
138       # assignment, but also to sed.
139       val=`echo "$val" | sed 's#[/&\\\\]#\\\\&#g'`
140       # Add replacement pattern. The first part checks that there is
141       # an odd number of percent signs before the variable, so
142       # double % is properly left alone.
143       expr="${expr}s/\(\(^\|[^%]\)\(%%\)*\)%$var/\1$val/g;"
144    done
145    # Finally replace literal % signs
146    expr="${expr}s/%%/%/g"
147
148    # Do the actual interpolation
149    echo $path | sed "$expr"
150 }
151
152 function interpolate_value () {
153    case "$1" in
154       h) `source_run hostname -s`;;
155       H) `source_run hostname --fqdn`;;
156       s) echo "$current_host";;
157       S) echo "$current_backend:$current_host";;
158       r) echo "$root";;
159       # Not one of the defaults, ask the backend
160       *) "backend_${current_backend}_interpolate_value" "$current_host" "$1"
161    esac
162 }