|
|
241f4b |
--- /usr/share/rear/lib/global-functions.sh 2015-09-03 15:43:01.000000000 +0200
|
|
|
241f4b |
+++ /usr/share/rear/lib/global-functions.sh 2017-01-06 12:02:52.000000000 +0100
|
|
|
241f4b |
@@ -2,27 +2,14 @@
|
|
|
241f4b |
#
|
|
|
241f4b |
# global functions for Relax-and-Recover
|
|
|
241f4b |
#
|
|
|
241f4b |
-# Relax-and-Recover is free software; you can redistribute it and/or modify
|
|
|
241f4b |
-# it under the terms of the GNU General Public License as published by
|
|
|
241f4b |
-# the Free Software Foundation; either version 2 of the License, or
|
|
|
241f4b |
-# (at your option) any later version.
|
|
|
241f4b |
-
|
|
|
241f4b |
-# Relax-and-Recover is distributed in the hope that it will be useful,
|
|
|
241f4b |
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
241f4b |
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
241f4b |
-# GNU General Public License for more details.
|
|
|
241f4b |
-
|
|
|
241f4b |
-# You should have received a copy of the GNU General Public License
|
|
|
241f4b |
-# along with Relax-and-Recover; if not, write to the Free Software
|
|
|
241f4b |
-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
241f4b |
-#
|
|
|
241f4b |
-#
|
|
|
241f4b |
+# This file is part of Relax-and-Recover, licensed under the GNU General
|
|
|
241f4b |
+# Public License. Refer to the included COPYING for full text of license.
|
|
|
241f4b |
|
|
|
241f4b |
function read_and_strip_file () {
|
|
|
241f4b |
# extracts content from config files. In other words: strips the comments and new lines
|
|
|
241f4b |
- if test -s "$1" ; then
|
|
|
241f4b |
- sed -e '/^[[:space:]]/d;/^$/d;/^#/d' "$1"
|
|
|
241f4b |
- fi
|
|
|
241f4b |
+ if test -s "$1" ; then
|
|
|
241f4b |
+ sed -e '/^[[:space:]]/d;/^$/d;/^#/d' "$1"
|
|
|
241f4b |
+ fi
|
|
|
241f4b |
}
|
|
|
241f4b |
|
|
|
241f4b |
function is_numeric () {
|
|
|
241f4b |
@@ -34,27 +21,143 @@
|
|
|
241f4b |
fi
|
|
|
241f4b |
}
|
|
|
241f4b |
|
|
|
241f4b |
+# two explicit functions to be able to test explicitly for true and false (see issue #625)
|
|
|
241f4b |
+# because "tertium non datur" (cf. https://en.wikipedia.org/wiki/Law_of_excluded_middle)
|
|
|
241f4b |
+# does not hold for variables because variables could be unset or have empty value
|
|
|
241f4b |
+# and to test if a variable is true or false its value is tested by that functions
|
|
|
241f4b |
+# but the variable may not have a real value (i.e. be unset or have empty value):
|
|
|
241f4b |
+
|
|
|
241f4b |
+function is_true () {
|
|
|
241f4b |
+ # the argument is usually the value of a variable which needs to be tested
|
|
|
241f4b |
+ # only if there is explicitly a 'true' value then is_true returns true
|
|
|
241f4b |
+ # so that an unset variable or an empty value is not true:
|
|
|
241f4b |
+ case "$1" in
|
|
|
241f4b |
+ ([tT] | [yY] | [yY][eE][sS] | [tT][rR][uU][eE] | 1)
|
|
|
241f4b |
+ return 0 ;;
|
|
|
241f4b |
+ esac
|
|
|
241f4b |
+ return 1
|
|
|
241f4b |
+}
|
|
|
241f4b |
+
|
|
|
241f4b |
+function is_false () {
|
|
|
241f4b |
+ # the argument is usually the value of a variable which needs to be tested
|
|
|
241f4b |
+ # only if there is explicitly a 'false' value then is_false returns true
|
|
|
241f4b |
+ # so that an unset variable or an empty value is not false
|
|
|
241f4b |
+ # caution: for unset or empty variables is_false is false
|
|
|
241f4b |
+ case "$1" in
|
|
|
241f4b |
+ ([fF] | [nN] | [nN][oO] | [fF][aA][lL][sS][eE] | 0)
|
|
|
241f4b |
+ return 0 ;;
|
|
|
241f4b |
+ esac
|
|
|
241f4b |
+ return 1
|
|
|
241f4b |
+}
|
|
|
241f4b |
+
|
|
|
241f4b |
######
|
|
|
241f4b |
### Functions for dealing with URLs
|
|
|
241f4b |
######
|
|
|
241f4b |
+# URL is the most common form of URI
|
|
|
241f4b |
+# see https://en.wikipedia.org/wiki/Uniform_Resource_Identifier
|
|
|
241f4b |
+# where a generic URI is of the form
|
|
|
241f4b |
+# scheme:[//[user:password@]host[:port]][/]path[?query][#fragment]
|
|
|
241f4b |
+# e.g. for BACKUP_URL=sshfs://user@host/G/rear/
|
|
|
241f4b |
+# url_scheme = 'sshfs' , url_host = 'user@host' , url_hostname = 'host' , url_username = 'user' , url_path = '/G/rear/'
|
|
|
241f4b |
+# e.g. for BACKUP_URL=usb:///dev/sdb1
|
|
|
241f4b |
+# url_scheme = 'usb' , url_host = '' , url_hostname = '' , url_username = '' , url_path = '/dev/sdb1'
|
|
|
241f4b |
+# FIXME: the ulr_* functions are not safe against special characters
|
|
|
241f4b |
+# for example they break when the password contains spaces
|
|
|
241f4b |
+# but on the other hand permitted characters for values in a URI
|
|
|
241f4b |
+# are ASCII letters, digits, dot, hyphen, underscore, and tilde
|
|
|
241f4b |
+# and any other character must be percent-encoded (in particular the
|
|
|
241f4b |
+# characters : / ? # [ ] @ are reserved as delimiters of URI components
|
|
|
241f4b |
+# and must be percent-encoded when used in the value of a URI component)
|
|
|
241f4b |
+# so that what is missing is support for percent-encoded characters
|
|
|
241f4b |
+# but user-friendly support for percent-encoded characters is not possible
|
|
|
241f4b |
+# cf. http://bugzilla.opensuse.org/show_bug.cgi?id=561626#c7
|
|
|
241f4b |
|
|
|
241f4b |
-url_scheme() {
|
|
|
241f4b |
+function url_scheme() {
|
|
|
241f4b |
local url=$1
|
|
|
241f4b |
+ # the scheme is the leading part up to '://'
|
|
|
241f4b |
local scheme=${url%%://*}
|
|
|
241f4b |
# rsync scheme does not have to start with rsync:// it can also be scp style
|
|
|
241f4b |
+ # see the comments in usr/share/rear/prep/RSYNC/default/100_check_rsync.sh
|
|
|
241f4b |
echo $scheme | grep -q ":" && echo rsync || echo $scheme
|
|
|
241f4b |
}
|
|
|
241f4b |
|
|
|
241f4b |
-url_host() {
|
|
|
241f4b |
+function url_host() {
|
|
|
241f4b |
+ local url=$1
|
|
|
241f4b |
+ local url_without_scheme=${url#*//}
|
|
|
241f4b |
+ # the authority part is the part after the scheme (e.g. 'host' or 'user@host')
|
|
|
241f4b |
+ # i.e. after 'scheme://' all up to but excluding the next '/'
|
|
|
241f4b |
+ # which means it breaks if there is a username that contains a '/'
|
|
|
241f4b |
+ # which should not happen because a POSIX-compliant username
|
|
|
241f4b |
+ # should have only characters from the portable filename character set
|
|
|
241f4b |
+ # which is ASCII letters, digits, dot, hyphen, and underscore
|
|
|
241f4b |
+ # (a hostname must not contain a '/' see RFC 952 and RFC 1123)
|
|
|
241f4b |
+ local authority_part=${url_without_scheme%%/*}
|
|
|
241f4b |
+ # for backward compatibility the url_host function returns the whole authority part
|
|
|
241f4b |
+ # see https://github.com/rear/rear/issues/856
|
|
|
241f4b |
+ # to get only hostname or username use the url_hostname and url_username functions
|
|
|
241f4b |
+ echo $authority_part
|
|
|
241f4b |
+}
|
|
|
241f4b |
+
|
|
|
241f4b |
+function url_hostname() {
|
|
|
241f4b |
local url=$1
|
|
|
241f4b |
- local host=${url#*//}
|
|
|
241f4b |
- echo ${host%%/*}
|
|
|
241f4b |
+ local url_without_scheme=${url#*//}
|
|
|
241f4b |
+ local authority_part=${url_without_scheme%%/*}
|
|
|
241f4b |
+ # if authority_part contains a '@' we assume the 'user@host' format and
|
|
|
241f4b |
+ # then we remove the 'user@' part (i.e. all up to and including the last '@')
|
|
|
241f4b |
+ # so that it also works when the username contains a '@'
|
|
|
241f4b |
+ # like 'john@doe' in BACKUP_URL=sshfs://john@doe@host/G/rear/
|
|
|
241f4b |
+ # (a hostname must not contain a '@' see RFC 952 and RFC 1123)
|
|
|
241f4b |
+ local host_and_port=${authority_part##*@}
|
|
|
241f4b |
+ # if host_and_port contains a ':' we assume the 'host:port' format and
|
|
|
241f4b |
+ # then we remove the ':port' part (i.e. all from and including the last ':')
|
|
|
241f4b |
+ # so that it even works when the hostname contains a ':' (in spite of RFC 952 and RFC 1123)
|
|
|
241f4b |
+ echo ${host_and_port%:*}
|
|
|
241f4b |
}
|
|
|
241f4b |
|
|
|
241f4b |
-url_path() {
|
|
|
241f4b |
+function url_username() {
|
|
|
241f4b |
local url=$1
|
|
|
241f4b |
- local path=${url#*//}
|
|
|
241f4b |
- echo /${path#*/}
|
|
|
241f4b |
+ local url_without_scheme=${url#*//}
|
|
|
241f4b |
+ local authority_part=${url_without_scheme%%/*}
|
|
|
241f4b |
+ # authority_part must contain a '@' when a username is specified
|
|
|
241f4b |
+ echo $authority_part | grep -q '@' || return 0
|
|
|
241f4b |
+ # we remove the '@host' part (i.e. all from and including the last '@')
|
|
|
241f4b |
+ # so that it also works when the username contains a '@'
|
|
|
241f4b |
+ # like 'john@doe' in BACKUP_URL=sshfs://john@doe@host/G/rear/
|
|
|
241f4b |
+ # (a hostname must not contain a '@' see RFC 952 and RFC 1123)
|
|
|
241f4b |
+ local user_and_password=${authority_part%@*}
|
|
|
241f4b |
+ # if user_and_password contains a ':' we assume the 'user:password' format and
|
|
|
241f4b |
+ # then we remove the ':password' part (i.e. all from and including the first ':')
|
|
|
241f4b |
+ # so that it works when the password contains a ':'
|
|
|
241f4b |
+ # (a POSIX-compliant username should not contain a ':')
|
|
|
241f4b |
+ echo $user_and_password | grep -q ':' && echo ${user_and_password%%:*} || echo $user_and_password
|
|
|
241f4b |
+}
|
|
|
241f4b |
+
|
|
|
241f4b |
+function url_password() {
|
|
|
241f4b |
+ local url=$1
|
|
|
241f4b |
+ local url_without_scheme=${url#*//}
|
|
|
241f4b |
+ local authority_part=${url_without_scheme%%/*}
|
|
|
241f4b |
+ # authority_part must contain a '@' when a username is specified
|
|
|
241f4b |
+ echo $authority_part | grep -q '@' || return 0
|
|
|
241f4b |
+ # we remove the '@host' part (i.e. all from and including the last '@')
|
|
|
241f4b |
+ # so that it also works when the username contains a '@'
|
|
|
241f4b |
+ # like 'john@doe' in BACKUP_URL=sshfs://john@doe@host/G/rear/
|
|
|
241f4b |
+ # (a hostname must not contain a '@' see RFC 952 and RFC 1123)
|
|
|
241f4b |
+ local user_and_password=${authority_part%@*}
|
|
|
241f4b |
+ # user_and_password must contain a ':' when a password is specified
|
|
|
241f4b |
+ echo $user_and_password | grep -q ':' || return 0
|
|
|
241f4b |
+ # we remove the 'user:' part (i.e. all up to and including the first ':')
|
|
|
241f4b |
+ # so that it works when the password contains a ':'
|
|
|
241f4b |
+ # (a POSIX-compliant username should not contain a ':')
|
|
|
241f4b |
+ echo ${user_and_password#*:}
|
|
|
241f4b |
+}
|
|
|
241f4b |
+
|
|
|
241f4b |
+function url_path() {
|
|
|
241f4b |
+ local url=$1
|
|
|
241f4b |
+ local url_without_scheme=${url#*//}
|
|
|
241f4b |
+ # the path is all from and including the first '/' in url_without_scheme
|
|
|
241f4b |
+ # i.e. the whole rest after the authority part so that
|
|
|
241f4b |
+ # it may contain an optional trailing '?query' and '#fragment'
|
|
|
241f4b |
+ echo /${url_without_scheme#*/}
|
|
|
241f4b |
}
|
|
|
241f4b |
|
|
|
241f4b |
backup_path() {
|
|
|
241f4b |
@@ -76,7 +179,7 @@
|
|
|
241f4b |
path="${TMP_DIR}/isofs${path}"
|
|
|
241f4b |
fi
|
|
|
241f4b |
;;
|
|
|
241f4b |
- (*) # nfs, cifs, usb, a.o. need a temporary mount-path
|
|
|
241f4b |
+ (*) # nfs, cifs, usb, a.o. need a temporary mount-path
|
|
|
241f4b |
path="${BUILD_DIR}/outputfs/${NETFS_PREFIX}"
|
|
|
241f4b |
;;
|
|
|
241f4b |
esac
|
|
|
241f4b |
@@ -93,7 +196,7 @@
|
|
|
241f4b |
(file) # type file needs a local path (must be mounted by user)
|
|
|
241f4b |
path="$path/${OUTPUT_PREFIX}"
|
|
|
241f4b |
;;
|
|
|
241f4b |
- (*) # nfs, cifs, usb, a.o. need a temporary mount-path
|
|
|
241f4b |
+ (*) # nfs, cifs, usb, a.o. need a temporary mount-path
|
|
|
241f4b |
path="${BUILD_DIR}/outputfs/${OUTPUT_PREFIX}"
|
|
|
241f4b |
;;
|
|
|
241f4b |
esac
|
|
|
241f4b |
@@ -129,7 +232,8 @@
|
|
|
241f4b |
;;
|
|
|
241f4b |
(cifs)
|
|
|
241f4b |
if [ x"$options" = x"$defaultoptions" ];then
|
|
|
241f4b |
- mount_cmd="mount $v -o $options,guest //$(url_host $url)$(url_path $url) $mountpoint"
|
|
|
241f4b |
+ # defaultoptions contains noatime which is not valid for cifs (issue #752)
|
|
|
241f4b |
+ mount_cmd="mount $v -o rw,guest //$(url_host $url)$(url_path $url) $mountpoint"
|
|
|
241f4b |
else
|
|
|
241f4b |
mount_cmd="mount $v -o $options //$(url_host $url)$(url_path $url) $mountpoint"
|
|
|
241f4b |
fi
|
|
|
241f4b |
@@ -137,19 +241,48 @@
|
|
|
241f4b |
(usb)
|
|
|
241f4b |
mount_cmd="mount $v -o $options $(url_path $url) $mountpoint"
|
|
|
241f4b |
;;
|
|
|
241f4b |
- (sshfs)
|
|
|
241f4b |
- mount_cmd="sshfs $(url_host $url):$(url_path $url) $mountpoint -o $options"
|
|
|
241f4b |
+ (sshfs)
|
|
|
241f4b |
+ local authority=$( url_host $url )
|
|
|
241f4b |
+ test "$authority" || Error "Cannot run 'sshfs' because no authority '[user@]host' found in URL '$url'."
|
|
|
241f4b |
+ local path=$( url_path $url )
|
|
|
241f4b |
+ test "$path" || Error "Cannot run 'sshfs' because no path found in URL '$url'."
|
|
|
241f4b |
+ # ensure the fuse kernel module is loaded because sshfs is based on FUSE
|
|
|
241f4b |
+ lsmod | grep -q '^fuse' || modprobe $verbose fuse || Error "Cannot run 'sshfs' because 'fuse' kernel module is not loadable."
|
|
|
241f4b |
+ mount_cmd="sshfs $authority:$path $mountpoint -o $options"
|
|
|
241f4b |
+ ;;
|
|
|
241f4b |
+ (ftpfs)
|
|
|
241f4b |
+ local hostname=$( url_hostname $url )
|
|
|
241f4b |
+ test "$hostname" || Error "Cannot run 'curlftpfs' because no hostname found in URL '$url'."
|
|
|
241f4b |
+ local path=$( url_path $url )
|
|
|
241f4b |
+ test "$path" || Error "Cannot run 'curlftpfs' because no path found in URL '$url'."
|
|
|
241f4b |
+ local username=$( url_username $url )
|
|
|
241f4b |
+ # ensure the fuse kernel module is loaded because ftpfs (via CurlFtpFS) is based on FUSE
|
|
|
241f4b |
+ lsmod | grep -q '^fuse' || modprobe $verbose fuse || Error "Cannot run 'curlftpfs' because 'fuse' kernel module is not loadable."
|
|
|
241f4b |
+ if test "$username" ; then
|
|
|
241f4b |
+ local password=$( url_password $url )
|
|
|
241f4b |
+ if test "$password" ; then
|
|
|
241f4b |
+ # single quoting is a must for the password
|
|
|
241f4b |
+ mount_cmd="curlftpfs $verbose -o user='$username:$password' ftp://$hostname$path $mountpoint"
|
|
|
241f4b |
+ else
|
|
|
241f4b |
+ # also single quoting for the plain username so that it also works for non-POSIX-compliant usernames
|
|
|
241f4b |
+ # (a POSIX-compliant username should only contain ASCII letters, digits, dot, hyphen, and underscore)
|
|
|
241f4b |
+ mount_cmd="curlftpfs $verbose -o user='$username' ftp://$hostname$path $mountpoint"
|
|
|
241f4b |
+ fi
|
|
|
241f4b |
+ else
|
|
|
241f4b |
+ mount_cmd="curlftpfs $verbose ftp://$hostname$path $mountpoint"
|
|
|
241f4b |
+ fi
|
|
|
241f4b |
+ ;;
|
|
|
241f4b |
+ (davfs)
|
|
|
241f4b |
+ mount_cmd="mount $v -t davfs http://$(url_host $url)$(url_path $url) $mountpoint"
|
|
|
241f4b |
;;
|
|
|
241f4b |
- (davfs)
|
|
|
241f4b |
- mount_cmd="mount $v -t davfs http://$(url_host $url)$(url_path $url) $mountpoint"
|
|
|
241f4b |
- ;;
|
|
|
241f4b |
(*)
|
|
|
241f4b |
mount_cmd="mount $v -t $(url_scheme $url) -o $options $(url_host $url):$(url_path $url) $mountpoint"
|
|
|
241f4b |
;;
|
|
|
241f4b |
esac
|
|
|
241f4b |
|
|
|
241f4b |
Log "Mounting with '$mount_cmd'"
|
|
|
241f4b |
- $mount_cmd >&2
|
|
|
241f4b |
+ # eval is required when mount_cmd contains single quoted stuff (e.g. see the above mount_cmd for curlftpfs)
|
|
|
241f4b |
+ eval $mount_cmd >&2
|
|
|
241f4b |
StopIfError "Mount command '$mount_cmd' failed."
|
|
|
241f4b |
|
|
|
241f4b |
AddExitTask "umount -f $v '$mountpoint' >&2"
|
|
|
241f4b |
@@ -182,7 +315,7 @@
|
|
|
241f4b |
# and delete only the just used cache
|
|
|
241f4b |
#rm -rf /var/cache/davfs2/*<mountpoint-hash>*
|
|
|
241f4b |
rm -rf /var/cache/davfs2/*outputfs*
|
|
|
241f4b |
-
|
|
|
241f4b |
+
|
|
|
241f4b |
;;
|
|
|
241f4b |
(var)
|
|
|
241f4b |
local var=$(url_host $url)
|
|
|
241f4b |
@@ -228,3 +361,4 @@
|
|
|
241f4b |
Log "Unmounting '$mountpoint' failed."
|
|
|
241f4b |
return 1
|
|
|
241f4b |
}
|
|
|
241f4b |
+
|