#!/usr/bin/env bash # Copyright 2010-2014 Frank Liepold / 1&1 Internet AG # Email: frank.liepold@1und1.de # # Key note: Thomas Schoebel-Theuer # # 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 2 # of the License, or (at your option) any later version. # # 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, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # this may be later overridden by distros / install scripts / etc # $sript_dir is assumed to be already set by the caller base_dir="$(cd "$script_dir/.."; pwd)" ##################################################################### # general error exit function function lib_callstack { echo "================= Callstack ====================================================" local argv_index=0 i for i in ${!FUNCNAME[*]}; do local j args= argc=${BASH_ARGC[$i]} if [ ${argc:-0} -gt 0 ]; then for j in $(seq 1 1 $argc); do args='"'"${BASH_ARGV[$argv_index]}"'" '"$args" let argv_index+=1 done fi echo ${BASH_SOURCE[(($i + 1))]:-"stdin"}:${BASH_LINENO[$i]} ${FUNCNAME[$i]} $args done echo "================= End callstack ================================================" } function lib_exit { local rc=$1 msg="$2" if [ -n "$msg" ];then echo " $msg" >&2 fi if [ $rc -ne 0 -a -z "$lib_exit_recursion" ]; then lib_callstack >&2 fi if [ $rc -ne $main_prevent_remove_lock_files_exit_code ]; then release_host_locks fi # to avoid recursion if [ -n "$lib_exit_recursion" ];then echo "lib_exit:recursion!!!" >&2 printf "\nstack:\n" >&2 lib_callstack >&2 exit $rc fi export lib_exit_recursion=1 eval $lib_general_checks_after_every_test_function if [ ${#main_error_recovery_functions[*]} -ge 0 ]; then local func args for func in "${!main_error_recovery_functions[@]}"; do args="${main_error_recovery_functions[$func]}" if [ -n "$args" ];then echo " calling error recovery $func" >&2 $func $args || exit 1 fi done fi exit $rc } ##################################################################### # helper to generate verbose messages function lib_vmsg { if (( main_verbose_script )); then echo "$(date +'%Y-%m-%d %H:%M:%S') [[$( for i in $(seq $((${#BASH_SOURCE[@]} - $main_min_stack_level)) -1 1); do printf '%s' $prefix$(basename ${BASH_SOURCE[$i]}):${BASH_LINENO[$(($i - 1))]} prefix='->' done )]]" $* fi } ##################################################################### # helper for prevention of script failures due to missing tools function check_installed { local check_list="$1" i for i in $check_list; do if ! which $i >/dev/null 2>&1; then echo "Sorry, program '$i' is not installed." exit -1 fi done } check_always_list="basename dirname which pwd mkdir rmdir rm cat ls sort ssh scp nice sed awk" check_installed "$check_always_list" ##################################################################### # helper for sourcing other config files (may reside in parents of cwd) function source_config { local name="$1" local setup_dir=$(pwd) local pwd=$(pwd) local limit=0 local setup until [ -r $setup_dir/$name.conf ]; do setup_dir="$(cd $setup_dir/..; pwd)" (( limit++ > 20 )) && { echo "config file $name.conf not found in parent directories of $pwd."; return 1; } done setup=$setup_dir/$name.conf echo "Sourcing config file $setup" shopt -u nullglob source $setup || exit $? return 0 } ##################################################################### # abstracting access to remote hosts function lib_remote_opt { local ssh_opt="$1" shift local host="$1" shift ssh $ssh_opt -n root@"$host" "$@" } function remote { lib_remote_opt "" "$@" } function lib_remote_all_idfile { lib_remote_all_opt "$main_ssh_idfile_opt" "$@" } function lib_remote_all_opt { local ssh_opt="$1" shift local host_all="$1" host shift local cmd="$@" for host in $host_all; do lib_remote_opt "$ssh_opt" "$host" "$cmd" \ || { rc=$?; echo " $cmd cmd failed on host $host" >&2; return $rc; } done } function remote_all { lib_remote_all_opt "" "$@" } function lib_remote_idfile { lib_remote_opt "$main_ssh_idfile_opt" "$@" } function remote_all_noreturn { local host_all="$1" host shift for host in $host_all; do remote "$host" "$@" done } function lib_check_access_to_remote_hosts { local ssh_opt="$1" shift local hostlist="$@" if (( main_verbose_script )); then echo " testing access as root to hosts $hostlist" fi lib_remote_all_opt "$ssh_opt" "$hostlist" hostname || lib_exit 1 } # The pid of the started program will be returned in the variable named by # $3. # The names of the script which is executed on the remote host will be returned # in the variable namend by $4 # The name of the (remote) outputfile of the script is the script name # extended with .out # stdout resp. stderr are kept in files named