541 lines
19 KiB
Bash
Executable File
541 lines
19 KiB
Bash
Executable File
#!/bin/bash
|
|
#===============================================================================
|
|
#
|
|
# DIRECTORY:
|
|
# ---
|
|
#
|
|
# FILE:
|
|
# ./functions.sh
|
|
#
|
|
# USAGE:
|
|
# . functions.sh
|
|
# OR
|
|
# source functions.sh
|
|
#
|
|
# OPTIONS:
|
|
# none
|
|
#
|
|
# EXIT STATES:
|
|
# 101 = uncommon binary not installed
|
|
# 102 = logfile not defined/supplied
|
|
# 103 = dir for logfile not writable
|
|
# 104 = logfile already exists but is not writable
|
|
# 105 = common binary not installed
|
|
# 106 = your os is not supported (yet)
|
|
# 107 = illegal browser command supplied
|
|
# 108 = no case number supplied
|
|
# 109 = folder not defined/supplied
|
|
# 110 = folder already exists
|
|
# 111 = unable to create folder
|
|
# 112 = ios_backup not supplied
|
|
# 113 = ios_backup does not exist
|
|
# 114 = ios_backup is not a directory
|
|
# 115 = ios_backup is empty
|
|
#
|
|
# DESCRIPTION:
|
|
# Global functions (and configuration library) for scripts.
|
|
#
|
|
# REQUIREMENTS:
|
|
# which, uname, basename, ps, grep, awk, sed, dirname, tee, ...
|
|
#
|
|
# BUGS:
|
|
# ---
|
|
#
|
|
# TESTS:
|
|
# - shellcheck -s bash -e SC2034,SC2016,SC2027,SC2086 ./functions.sh
|
|
# - shellcheck -s bksh -e SC2034,SC2016,SC2027,SC2086 ./functions.sh
|
|
# - shellcheck -s dash -e SC2034,SC2016,SC2027,SC2086 ./functions.sh
|
|
#
|
|
# AUTHOR:
|
|
# Patrick Neumann, patrick@neumannsland.de
|
|
#
|
|
# COAUTHOR(S):
|
|
# Odin Heitmann, odin.heitmann@gmail.com
|
|
#
|
|
# COMPANY:
|
|
# (privately)
|
|
#
|
|
# VERSION:
|
|
# 1.0
|
|
#
|
|
# LINK TO THE MOST CURRENT VERSION:
|
|
# (Sorry, I bet, I'm not allowed to publish it over GitHub!)
|
|
#
|
|
# CREATED:
|
|
# 2018-06-01
|
|
#
|
|
# COPYRIGHT (C):
|
|
# 2018 - Patrick Neumann & Odin Heitmann
|
|
#
|
|
# LICENSE:
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# WARRANTY:
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
# NOTES:
|
|
# ---
|
|
#
|
|
# TODO:
|
|
# - check if HOLE directory (ios_backup) is read-only
|
|
# - find a more portable solution for [[ in abspath
|
|
#
|
|
# HISTORY:
|
|
# 1.0 - P. N. & O. H. - Initial (for the trainers eyes only) release
|
|
#
|
|
#===============================================================================
|
|
|
|
# Relative paths are more portable but less secure.
|
|
# Absolute paths are more secure but less portable.
|
|
readonly BIN_WHICH="/usr/bin/which" # common
|
|
|
|
readonly BIN_AWK="$( ${BIN_WHICH} "awk" )" # common
|
|
readonly BIN_BASENAME="$( ${BIN_WHICH} "basename" )" # common
|
|
readonly BIN_DIRNAME="$( ${BIN_WHICH} "dirname" )" # common
|
|
readonly BIN_GREP="$( ${BIN_WHICH} "grep" )" # common
|
|
readonly BIN_PS="$( ${BIN_WHICH} "ps" )" # common
|
|
readonly BIN_TEE="$( ${BIN_WHICH} "tee" )" # common
|
|
readonly BIN_UNAME="$( ${BIN_WHICH} "uname" )" # common
|
|
readonly BIN_TR="$( ${BIN_WHICH} "tr" )" # common
|
|
readonly BIN_LS="$( ${BIN_WHICH} "ls" )" # common
|
|
readonly BIN_MKDIR="$( ${BIN_WHICH} "mkdir" )" # common
|
|
readonly BIN_CUT="$( ${BIN_WHICH} "cut" )" # common
|
|
readonly BIN_RM="$( ${BIN_WHICH} "rm" )" # common
|
|
readonly BIN_RMDIR="$( ${BIN_WHICH} "rmdir" )" # common
|
|
readonly BIN_PWD="$( ${BIN_WHICH} "pwd" )" # common
|
|
|
|
#-------------------------------------------------------------------------------
|
|
# Check existence of uncommon binaries.
|
|
#-------------------------------------------------------------------------------
|
|
#[ -z "${BIN_BC}" ] && error_exit "please install bc and retry" 2
|
|
|
|
# Changeable defaults:
|
|
DEFAULT_SHELL="bash"
|
|
ECHO_FUNC="display_and_log"
|
|
GET_HELP="no"
|
|
DISABLE_LOGGING="no"
|
|
DISABLE_STDOUT="no"
|
|
GET_VERSION_ONLY="no"
|
|
|
|
#-------------------------------------------------------------------------------
|
|
# Detect the shell in which we are running and set shell depended vars.
|
|
#-------------------------------------------------------------------------------
|
|
# SC2016: shellcheck fails if awk/sed is used!
|
|
readonly PROCESS="$( ${BIN_BASENAME} "$( ${BIN_PS} -axco pid,command \
|
|
| ${BIN_GREP} "$$" \
|
|
| ${BIN_GREP} -v "grep" \
|
|
| ${BIN_AWK} '{ print $2; }' )" )"
|
|
|
|
# Why conditinal command should be prefered over test:
|
|
# https://google-styleguide.googlecode.com/svn/trunk/shell.xml#Test,_[_and_[[
|
|
# and why you don't, if you would support "dash":
|
|
# http://mywiki.wooledge.org/Bashism
|
|
if [ "${PROCESS}" = "$( ${BIN_BASENAME} "${0}" )" ] ; then
|
|
readonly CURRENT_SHELL="${DEFAULT_SHELL}"
|
|
else
|
|
readonly CURRENT_SHELL="${PROCESS}"
|
|
fi
|
|
|
|
# Linux can have alle shells and "/bin/echo" has no limitations.
|
|
# Darwin (14.5.0) has bash 3.2.57, zsh 5.0.5, ksh 93 and tcsh 6.17.00
|
|
# - kshs and tcshs builtin echo does not support "-e" and/or "-n"!
|
|
# - "/bin/echo" does not support "-e"!
|
|
# FreeBSD can have all shells, but "/bin/echo" has the same limitations!
|
|
# Solution: use printf instead!
|
|
# Worth readable Link: http://hyperpolyglot.org/unix-shells#echo-note
|
|
if [ "${CURRENT_SHELL}" = "zsh" ] ; then
|
|
# zsh does not split a string into words separated by spaces by default!
|
|
setopt shwordsplit
|
|
# zshs "which" find the builtin without "-p"!
|
|
readonly BIN_PRINTF="$( which -p printf )"
|
|
else
|
|
readonly BIN_PRINTF="$( which printf )"
|
|
fi
|
|
|
|
if [ "${DEBUG}" = "on" ] ; then
|
|
${BIN_PRINTF} "CURRENT_SHELL: %s\\n" "${CURRENT_SHELL}" 1>&2
|
|
fi
|
|
|
|
#-------------------------------------------------------------------------------
|
|
# Detect operating system name and set os depended vars.
|
|
# (eg. "sed -E" on macOS is the same as "sed -r" on Linux)
|
|
#-------------------------------------------------------------------------------
|
|
readonly OS_NAME="$( ${BIN_UNAME} -s )"
|
|
|
|
case "${OS_NAME}" in
|
|
Darwin) readonly BIN_ID="$( ${BIN_WHICH} "id" )" # common
|
|
readonly BIN_OPEN="$( ${BIN_WHICH} "open" )" # common
|
|
readonly SED_EXT_REGEXP="-E"
|
|
readonly DARWIN_FIND_REGEXP_TYPE="-E "
|
|
readonly DATE_DISPLAY="-j -f %s "
|
|
;;
|
|
Linux) readonly BIN_GETENT="$( ${BIN_WHICH} "getent" )" # common
|
|
readonly SED_EXT_REGEXP="--regexp-extended"
|
|
readonly DATE_DISPLAY="-d @"
|
|
;;
|
|
FreeBSD) readonly BIN_GETENT="$( ${BIN_WHICH} "getent" )" # common
|
|
readonly SED_EXT_REGEXP="-E"
|
|
readonly DATE_DISPLAY="-j -f %s "
|
|
readonly LINUX_FIND_REGEXP_TYPE="-regextype posix-extended "
|
|
;;
|
|
esac
|
|
|
|
if [ "${DEBUG}" = "on" ] ; then
|
|
# printf has to be assinged before!
|
|
${BIN_PRINTF} "OS_NAME: %s\\n" "${OS_NAME}" 1>&2
|
|
fi
|
|
|
|
#=== FUNCTION ==================================================================
|
|
# NAME: check_logfile
|
|
# DESCRIPTION: Checks if a logfile is set and can be created.
|
|
# (needed in "log" and "display_and_log"!)
|
|
# PARAMETERS: none (a global var will be used.)
|
|
#===============================================================================
|
|
# Do not use "function" if you want to support dash:
|
|
# http://mywiki.wooledge.org/Bashism
|
|
check_logfile () {
|
|
if [ -z "${LOG_FILE}" ] ; then
|
|
# "error_exit" will be defined later!
|
|
${BIN_PRINTF} "\\033[01;31;40mERROR: logfile not defined/supplied... EXIT!!!\\033[00m\\n"
|
|
exit 102
|
|
fi
|
|
if ! [ -w "$( ${BIN_DIRNAME} "${LOG_FILE}" )" ] ; then
|
|
${BIN_PRINTF} "\\033[01;31;40mERROR: dir for logfile not writable... EXIT!!!\\033[00m\\n"
|
|
exit 103
|
|
fi
|
|
|
|
if [ -e "${LOG_FILE}" ] ; then
|
|
if ! [ -w "${LOG_FILE}" ] ; then
|
|
${BIN_PRINTF} "\\033[01;31;40mERROR: logfile already exists but is not writable... EXIT!!!\\033[00m\\n"
|
|
exit 104
|
|
else
|
|
${BIN_PRINTF} "\\nlogfile does already exist, overwrite? \
|
|
(type YES in UPPER letters and hit return!) : "
|
|
read -r answer
|
|
if [ "${answer}" != "YES" ] ; then
|
|
${BIN_PRINTF} "\\033[01;34;40mHINT: move the old logfile to a save place and try again... EXIT!!!\\033[00m\\n"
|
|
exit 0
|
|
fi
|
|
# clear logfile
|
|
${BIN_PRINTF} "" > "${LOG_FILE}"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
#=== FUNCTION ==================================================================
|
|
# NAME: display
|
|
# DESCRIPTION: Wrapper for "echo -n -e".
|
|
# PARAMETER 1: message (string)
|
|
#===============================================================================
|
|
display () {
|
|
${BIN_PRINTF} "${1}"
|
|
}
|
|
|
|
#=== FUNCTION ==================================================================
|
|
# NAME: log
|
|
# DESCRIPTION: Wrapper for "echo -n -e" incl. redirection into logfile.
|
|
# PARAMETER 1: message (string)
|
|
#===============================================================================
|
|
log () {
|
|
${BIN_PRINTF} "${1}" >> "${LOG_FILE}"
|
|
}
|
|
|
|
#=== FUNCTION ==================================================================
|
|
# NAME: display_and_log
|
|
# DESCRIPTION: Wrapper for "echo -n -e" incl. output to stdout AND redirection
|
|
# into logfile.
|
|
# PARAMETER 1: message (string)
|
|
#===============================================================================
|
|
display_and_log () {
|
|
${BIN_PRINTF} "${1}" | ${BIN_TEE} -a "${LOG_FILE}"
|
|
}
|
|
|
|
#=== FUNCTION ==================================================================
|
|
# NAME: quiet
|
|
# DESCRIPTION: Wrapper for "echo -n -e" incl. redirection into "nirvana".
|
|
# PARAMETER 1: message (string)
|
|
#===============================================================================
|
|
quiet () {
|
|
${BIN_PRINTF} "${1}" > /dev/null
|
|
}
|
|
|
|
#=== FUNCTION ==================================================================
|
|
# NAME: error
|
|
# DESCRIPTION: Display red error messages starting with "ERROR:".
|
|
# PARAMETER 1: message (string)
|
|
#===============================================================================
|
|
error () {
|
|
# TODO: stderr too!?
|
|
"${ECHO_FUNC}" "\\033[01;31;40mERROR: ${1}!!!\\033[00m\\n"
|
|
}
|
|
|
|
#=== FUNCTION ==================================================================
|
|
# NAME: error_exit
|
|
# DESCRIPTION: Display red error messages surrounded by "ERROR:" and "EXIT!!!".
|
|
# PARAMETER 1: message (string)
|
|
# PARAMETER 2: exit state (integer)
|
|
# PARAMETER 3: command (optional)
|
|
#===============================================================================
|
|
error_exit () {
|
|
"${BIN_PRINTF}" "\\n\\033[01;31;40mERROR: ${1}... EXIT!!!\\033[00m\\n\\n"
|
|
|
|
# Execute command/function before exit
|
|
if [ -n "${3}" ] ; then
|
|
${3}
|
|
fi
|
|
|
|
# Clean up before exit
|
|
${BIN_RM} "${LOG_FILE}"
|
|
${BIN_RMDIR} "${FOLDER}"
|
|
|
|
if ! [ "${2}" -eq "${2}" ] 2> /dev/null ; then
|
|
exit "${2}"
|
|
else
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
#=== FUNCTION ==================================================================
|
|
# NAME: hint
|
|
# DESCRIPTION: Display blue hint messages starting with "HINT:".
|
|
# PARAMETER 1: message (string)
|
|
#===============================================================================
|
|
hint () {
|
|
"${ECHO_FUNC}" "\\033[01;34;40m${1}\\033[00m\\n"
|
|
}
|
|
|
|
#=== FUNCTION ==================================================================
|
|
# NAME: success
|
|
# DESCRIPTION: Display green success messages starting with "SUCCESS:".
|
|
# PARAMETER 1: message (string)
|
|
#===============================================================================
|
|
success () {
|
|
"${ECHO_FUNC}" "\\033[01;32;40mSUCCESS: ${1}!\\033[00m\\n"
|
|
}
|
|
|
|
#=== FUNCTION ==================================================================
|
|
# NAME: assign_binary
|
|
# DESCRIPTION: check if binary exists and store the absolute path in a var.
|
|
# PARAMETER 1: command (string)
|
|
#===============================================================================
|
|
assign_binary () {
|
|
# Because in dash, string indexing is not supported we can not use:
|
|
# "${1:0:1}" = "/"
|
|
if [ "$( ${BIN_PRINTF} "${1}" | ${BIN_CUT} -c 1 )" = "/" ] ; then
|
|
# Absolute paths are more secure but less portable.
|
|
if ! [ -e "${1}" ] ; then
|
|
error_exit "${1} not installed" 105
|
|
fi
|
|
local var="BIN_$( ${BIN_PRINTF} "$( ${BIN_BASENAME} "${1}" )" \
|
|
| ${BIN_TR} "[[:lower:]]" "[[:upper:]]" \
|
|
| ${BIN_TR} -d '.' )"
|
|
eval "readonly $var=\${1}"
|
|
else
|
|
# Relative paths are more portable but less secure.
|
|
local var="BIN_$( ${BIN_PRINTF} "${1}" \
|
|
| ${BIN_TR} "[[:lower:]]" "[[:upper:]]" \
|
|
| ${BIN_TR} -d '.' )"
|
|
# SC2027 & SC2086: It's not a bug... it's a feature!
|
|
eval "readonly $var=\$( ${BIN_WHICH} "${1}" )"
|
|
if [ -z "$( eval "${BIN_PRINTF} \$$var" )" ] ; then
|
|
error_exit "${1} not installed" 105
|
|
fi
|
|
fi
|
|
}
|
|
|
|
#=== FUNCTION ==================================================================
|
|
# NAME: check_browser
|
|
# DESCRIPTION: Check for browser (default: firefox) and store in var.
|
|
# (If no Desktop Environment is installed, try "true" as "a browser".)
|
|
# PARAMETERS: none (a global var will be used.)
|
|
#===============================================================================
|
|
check_browser () {
|
|
if [ -z "${BROWSER}" ] ; then
|
|
case "${OS_NAME}" in
|
|
Darwin) readonly BROWSER="Firefox"
|
|
;;
|
|
Linux|FreeBSD) BROWSER="firefox"
|
|
;;
|
|
*) error_exit "your os is not supported (yet)" 106
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
case "${OS_NAME}" in
|
|
Darwin) if ! [ -d "/Applications/${BROWSER}.app" ] ; then
|
|
error_exit "illegal browser command (${BROWSER}) supplied" 107
|
|
fi
|
|
;;
|
|
Linux|FreeBSD) readonly BROWSER="$( ${BIN_WHICH} "${BROWSER}" )"
|
|
if ! [ -x "${BROWSER}" ] ; then
|
|
error_exit "illegal browser command (${BROWSER}) supplied" 107
|
|
fi
|
|
;;
|
|
esac
|
|
|
|
hint "Defined/supplied browser:\\n ${BROWSER}\\n"
|
|
}
|
|
|
|
#=== FUNCTION ==================================================================
|
|
# NAME: check_case_number
|
|
# DESCRIPTION: Check if case number is given and store in var.
|
|
# PARAMETERS: none (a global var will be used.)
|
|
#===============================================================================
|
|
check_case_number () {
|
|
if [ -z "${CASE_NUMBER}" ] ; then
|
|
${BIN_PRINTF} "\\nNo case number supplied but mandatory - type case numer in and hit return: "
|
|
read -r case_number
|
|
if [ -n "${case_number}" ] ; then
|
|
readonly CASE_NUMBER="${case_number}"
|
|
${BIN_PRINTF} "\\n"
|
|
else
|
|
error_exit "no case number supplied" 108 usage
|
|
fi
|
|
fi
|
|
|
|
hint "Supplied case number:\\n ${CASE_NUMBER}\\n"
|
|
}
|
|
|
|
#=== FUNCTION ==================================================================
|
|
# NAME: abspath
|
|
# DESCRIPTION: generate absolute path from relative path
|
|
# PARAMETERS 1: string (relative or absolute path to directory or file)
|
|
# SOURCE:
|
|
# https://stackoverflow.com/questions/3915040/bash-fish-command-to-print-absolute-path-to-a-file#23002317
|
|
#===============================================================================
|
|
abspath () {
|
|
if [ -d "${1}" ]; then
|
|
# dir
|
|
( cd "${1}"; ${BIN_PWD} )
|
|
elif [ -f "${1}" ]; then
|
|
# file
|
|
if [[ ${1} = /* ]]; then
|
|
echo "${1}"
|
|
elif [[ ${1} == */* ]]; then
|
|
echo "$( cd "${1%/*}"; ${BIN_PWD} )/${1##*/}"
|
|
else
|
|
echo "$( ${BIN_PWD} )/${1}"
|
|
fi
|
|
fi
|
|
}
|
|
|
|
#=== FUNCTION ==================================================================
|
|
# NAME: check_folder
|
|
# DESCRIPTION: Check if folder does not exist, could be created in the given
|
|
# location and store in var.
|
|
# PARAMETERS: none (a global var will be used.)
|
|
#===============================================================================
|
|
check_folder () {
|
|
if [ -z "${FOLDER}" ] ; then
|
|
error_exit "folder not defined/supplied" 109 usage
|
|
fi
|
|
|
|
if [ -d "${FOLDER}" ] ; then
|
|
# I prefer to check for an existing report folder from a previous call
|
|
# over "just" check if the folder is empty.
|
|
error_exit "directory (${FOLDER}) already exists" 110
|
|
fi
|
|
|
|
if ! [ -w "$( ${BIN_DIRNAME} "${FOLDER}" )" ] ; then
|
|
error_exit "unable to create directory (${FOLDER})" 111
|
|
fi
|
|
|
|
# Create folder before abspath
|
|
${BIN_MKDIR} "${FOLDER}"
|
|
# because abspath checks for existence!
|
|
readonly FOLDER="$( abspath "${FOLDER}" )"
|
|
}
|
|
|
|
#=== FUNCTION ==================================================================
|
|
# NAME: check_officer
|
|
# DESCRIPTION: Check if name of officer is given otherwise use
|
|
# /etc/passwd or OpenDirectory.
|
|
# PARAMETERS: none (a global var will be used.)
|
|
#===============================================================================
|
|
check_officer () {
|
|
if [ -z "${OFFICER}" ] ; then
|
|
case "${OS_NAME}" in
|
|
Darwin) OFFICER="$( ${BIN_ID} -F )"
|
|
;;
|
|
Linux|FreeBSD) OFFICER="$( ${BIN_GETENT} passwd "${LOGNAME}" \
|
|
| cut -d ":" -f 5 | cut -d "," -f 1 )"
|
|
;;
|
|
esac
|
|
# Sometimes the system don't know the fullname of the user.
|
|
# The default in Bash on Ubuntu on Windows 10 is "".
|
|
if [ -z "${OFFICER}" ] || [ "${OFFICER}" = "\"\"" ] ; then
|
|
readonly OFFICER="unknown"
|
|
fi
|
|
fi
|
|
|
|
hint "Guessed/supplied officers name:\\n ${OFFICER}\\n"
|
|
}
|
|
|
|
#=== FUNCTION ==================================================================
|
|
# NAME: remove_final_dashes
|
|
# DESCRIPTION: Check if ios_backup has one or more final dash(es) and
|
|
# remove them.
|
|
# PARAMETER 1: string (eg. path to source)
|
|
#===============================================================================
|
|
remove_final_dashes () {
|
|
# Because in dash, string indexing is not supported we can not use:
|
|
# "${STRING:(-1)}" = "/" and STRING="${STRING:0:(-1)}"
|
|
local STRING="${1}"
|
|
local LENGTH="${#STRING}"
|
|
while [ "$( ${BIN_PRINTF} "${STRING}" | ${BIN_CUT} -c "${LENGTH}" )" = "/" ] ; do
|
|
STRING="$( ${BIN_PRINTF} "${STRING}" | ${BIN_CUT} -c 1-$(( LENGTH - 1 )) )"
|
|
LENGTH="$(( LENGTH - 1 ))"
|
|
done
|
|
${BIN_PRINTF} "%s\\n" "${STRING}"
|
|
}
|
|
|
|
#=== FUNCTION ==================================================================
|
|
# NAME: check_source
|
|
# DESCRIPTION: Check if ios_backup is given and store in var.
|
|
# Otherwise EXIT!
|
|
# PARAMETERS: none (a global var will be used.)
|
|
#===============================================================================
|
|
check_source () {
|
|
if [ "${DEBUG}" = "on" ] ; then
|
|
${BIN_PRINTF} "SOURCE: ${1}\\n" 1>&2
|
|
fi
|
|
|
|
if [ -z "${1}" ] ; then
|
|
error_exit "ios_backup not supplied" 112 usage
|
|
fi
|
|
|
|
if ! [ -e "${1}" ] ; then
|
|
error_exit "ios_backup (${1}) does not exist" 113
|
|
fi
|
|
|
|
if ! [ -d "${1}" ] ; then
|
|
error_exit "ios_backup (${1}) is not a directory" 114
|
|
fi
|
|
|
|
if [ -z "$( ${BIN_LS} "${1}" )" ] ; then
|
|
error_exit "ios_backup (${1}) is empty" 115
|
|
fi
|
|
|
|
# TODO: check if hole directory is read-only
|
|
|
|
IOS_BACKUP="$( remove_final_dashes "${1}" )"
|
|
readonly IOS_BACKUP="$( abspath "${IOS_BACKUP}" )"
|
|
|
|
hint "Supplied iOS backup folder:\\n ${IOS_BACKUP}\\n"
|
|
}
|
|
|
|
readonly FUNCTIONS_LOADED="true"
|
|
|
|
if [ "${DEBUG}" = "on" ] ; then
|
|
${BIN_PRINTF} "INFO: functions.sh loaded.\\n" 1>&2
|
|
fi
|
|
# Do not use "exit" at the end of a sourced library! |