#!/usr/bin/ksh # # Note: use "/usr/bin/ksh -i" if the signal handler do not work # # **** Note: The main code starts after the line containing "# main:" **** # The main code for your script should start after "# main - your code" # Function statt after the line containing "# functions: " # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2006-2014 Bernd Schemmer All rights reserved. # Use is subject to license terms. # # Notes: # # - use "execute_on_all_hosts.sh {-v} {-v} {-v} -h" to get the usage help # # - use "execute_on_all_hosts.sh -H 2>execute_on_all_hosts.sh.doc" to get the documentation # # - use "execute_on_all_hosts.sh -X 2>execute_on_all_hosts.sh.examples.doc" to get some usage examples # # - this is a Kornshell script - it may not function correctly in other shells # - the script was written and tested with ksh88 but should also work in ksh93 # The script should also work in bash -- but that is NOT completly tested # # ??? Add usage examples here; the lines should start with ##EXAMPLE## # ##EXAMPLE## ##EXAMPLE## ##EXAMPLE## # create the documentation for the script ##EXAMPLE## ##EXAMPLE## ./${__SCRIPTNAME} -H 2>./${__SCRIPTNAME}.doc ##EXAMPLE## ##EXAMPLE## # get the verbose usage for the script ##EXAMPLE## ##EXAMPLE## ./${__SCRIPTNAME} -v -v -h ##EXAMPLE## ##EXAMPLE## # write a config file for the script ##EXAMPLE## ##EXAMPLE## ./${__SCRIPTNAME} -C ##EXAMPLE## ##EXAMPLE## ##EXAMPLE## # use another config file ##EXAMPLE## ##EXAMPLE## CONFIG_FILE=myconfig.conf ./${__SCRIPTNAME} ##EXAMPLE## ##EXAMPLE## # use no config file at all ##EXAMPLE## ##EXAMPLE## CONFIG_FILE=none ./${__SCRIPTNAME} ##EXAMPLE## ##EXAMPLE## ##EXAMPLE## # write all output (STDOUT and STDERR) to the file ##EXAMPLE## # /var/tmp/mylog.txt ##EXAMPLE## ##EXAMPLE## __TEE_OUTPUT_FILE=/var/tmp/mylog.txt ./${__SCRIPTNAME} -T ##EXAMPLE## ##EXAMPLE## ##EXAMPLE## # create a dump of the environment variables in the files ##EXAMPLE## # /tmp/${__SCRIPTNAME}.envvars.\$\$ ##EXAMPLE## # /tmp/${__SCRIPTNAME}.exported_envvars.\$\$ ##EXAMPLE## # (\$\$ is the PID of the process running the script) ##EXAMPLE## ##EXAMPLE## __CREATE_DUMP=1 ./${__SCRIPTNAME} ##EXAMPLE## ##EXAMPLE## # create a dump of the environment variables in the files ##EXAMPLE## # /var/tmp/debug/${__SCRIPTNAME}.envvars.\$\$ ##EXAMPLE## # /var/tmp/debug/${__SCRIPTNAME}.exported_envvars.\##EXAMPLE## # (\$\$ is the PID of the process running the script) ##EXAMPLE## # (\$\$ is the PID of the process running the script) ##EXAMPLE## ##EXAMPLE## __CREATE_DUMP=/var/tmp/debug ./${__SCRIPTNAME} ##EXAMPLE## # # Note: The escape character in the command below is only for the usage of execute_on_all_hosts.sh with the "-X" parameter! # ##EXAMPLE## # use logger instead of echo to print the messages ##EXAMPLE## ##EXAMPLE## LOGMSG_FUNCTION=\"logger -s -p user.info execute_on_all_hosts.sh\" ./execute_on_all_hosts.sh ##EXAMPLE## # ----------------------------------------------------------------------------- #### #### execute_on_all_hosts.sh - copy a script to a list of hosts via scp and execute it on the hosts using ssh #### #### Author: Bernd Schemmer (Bernd.Schemmer@gmx.de) #### #### Version: see variable ${__SCRIPT_VERSION} below #### (see variable ${__SCRIPT_TEMPLATE_VERSION} for the template version used) #### #### Supported OS: Solaris and others #### #### #### Description #### ----------- #### #### copy a script to a list of hosts via scp and execute it on the hosts using ssh ##C# ##C# Configuration file ##C# ------------------ ##C# ##C# This script supports a configuration file called .conf. ##C# The configuration file is searched in the working directory, ##C# the home directory of the user executing this script and in /etc ##C# (in this order). ##C# ##C# The configuration file is read before the parameter are processed. ##C# ##C# To override the default config file search set the variable ##C# CONFIG_FILE to the name of the config file to use. ##C# ##C# e.g. CONFIG_FILE=/var/myconfigfile ./execute_on_all_hosts.sh ##C# ##C# To disable the use of a config file use ##C# ##C# CONFIG_FILE=none ./execute_on_all_hosts.sh ##C# ##C# See the variable __CONFIG_PARAMETER below for the possible entries ##C# in the config file. ##C# #### #### Predefined parameter #### -------------------- #### #### see the subroutines ShowShortUsage and ShowUsage #### #### Note: The current version of the script template can be found here: #### #### http://bnsmb.de/solaris/scriptt.html #### #### ##T# Troubleshooting support ##T# ----------------------- ##T# ##T# Use ##T# ##T# __CREATE_DUMP= ##T# ##T# to create a dump of the environment variables on program exit. ##T# ##T# e.g ##T# ##T# __CREATE_DUMP=1 ./execute_on_all_hosts.sh ##T# ##T# will create a dump of the environment variables in the files ##T# ##T# /tmp/execute_on_all_hosts.sh.envvars.$$ ##T# /tmp/execute_on_all_hosts.sh.exported_envvars.$$ ##T# ##T# before the script ends ##T# ##T# __CREATE_DUMP=/var/tmp/debug ./execute_on_all_hosts.sh ##T# ##T# will create a dump of the environment variables in the files ##T# ##T# /var/tmp/debug/execute_on_all_hosts.sh.envvars.$$ ##T# /var/tmp/debug/execute_on_all_hosts.sh.exported_envvars.$$ ##T# ##T# before the script ends (the target directory must already exist). ##T# ##T# Note that the dump files will always be created in case of a syntax ##T# error. To set the directory for these files use either ##T# ##T# export __DUMPDIR=/var/tmp/debug ##T# ./execute_on_all_hosts.sh ##T# ##T# or define __DUMPDIR in the script. ##T# ##T# To suppress creating the dump file in case of a syntax error add ##T# the statement ##T# ##T# __DUMP_ALREADY_CREATED=0 ##T# ##T# to your script ##T# ##T# Use ##T# ##T# CreateDump [filename_add] ##T# ##T# to manually create the dump files from within the script. ##T# ##T# e.g. ##T# ##T# CreateDump /var/debug ##T# ##T# will create the files ##T# ##T# /var/debug/execute_on_all_hosts.sh.envvars.$$ ##T# /var/debug/execute_on_all_hosts.sh.exported_envvars.$$ ##T# ##T# CreateDump /var/debug pass2. ##T# ##T# will create the files ##T# ##T# /var/debug/execute_on_all_hosts.sh.envvars.pass2.$$ ##T# /var/debug/execute_on_all_hosts.sh.exported_envvars.pass2.$$ ##T# #### Note: #### The default action for the signal handler USR1 is #### "Create an environment dump in /var/tmp" #### The filenames for the dumps are #### #### /var/tmp/.envvars.dump_no__ #### /var/tmp/.exported_envvars.dump_no__ #### #### where is a sequential number, is the PID of the #### process with the script, and is the name of the #### script without the path. #### #### #### User defined signal handler #### --------------------------- #### #### You can define various SIGNAL handlers to process signals received #### by the script. #### #### All SIGNAL handlers can use these variables: #### #### __TRAP_SIGNAL -- the catched trap signal #### INTERRUPTED_FUNCTION -- the function interrupted by the signal #### #### #### To define one signal handler for all signals do: #### #### __GENERAL_SIGNAL_FUNCTION= #### #### To define unique signal handler for the various signals do: #### #### __SIGNAL_SIGUSR1_FUNCTION= #### __SIGNAL_SIGUSR2_FUNCTION= #### __SIGNAL_SIGHUP_FUNCTION= #### __SIGNAL_SIGINT_FUNCTION= #### __SIGNAL_SIGQUIT_FUNCTION= #### __SIGNAL_SIGTERM_FUNCTION= #### #### If both type of signal handler are defined the script first #### executes the general signal handler. #### If this handler returns 0 the handler for the catched signal will #### also be executed (else not). #### If the unique handler for the signal ends with 0 the default signal #### handler for this signal will also be executed (else not) #### #### #### Credits #### ------- #### #### Hints regarding the code to create the lockfile #### wpollock (http://wikis.sun.com/display/~wpollock) #### #### Source for the function PrintWithTimeStamp (in version 2.x and newer): #### http://unix.stackexchange.com/questions/26728/prepending-a-timestamp-to-each-line-of-output-from-a-command #### #### Andreas Obermaier for a security issue in the lockfile routine #### (see history section 1.22.45 07.06.2012) #### #### The code used in executeCommandAndLog is from #### http://www.unix.com/unix-dummies-questions-answers/13018-exit-status-command-pipe-line.html#post47559 #### #### #### History: #### -------- ## 27.02.2008 v0.0.1 /bs ## initial release ## 28.02.2008 v0.0.2 /bs ## added parameter hostlist, scriptfile, outputfile, and user ## added the parameter -U ## the script now supports multiple hostlists ## 03.03.2008 v0.0.3 /bs ## added additional workarounds for CYGWIN ## added the parameter -I ## added a summary about failed hosts ## changed __ONLY_ONCE to ${__FALSE} ## added code to print a warning if ssh-agent is not running ## 04.03.2008 v0.0.4 /bs ## changed the default output filename to "/var/tmp/${__SCRIPTNAME##*/}.$$.log" ## added code to call dos2unix for the script file if running in CYGWIN ## 20.09.2008 v0.0.7 /bs ## added the option -K / --nostrictkeys ## 20.04.2010 v0.0.8 /bs ## added RCM support ## 22.12.2010 v0.0.9 /bs ## added an initial RCM access check ## 30.03.2011 v0.0.10 /bs ## added the parameter -b / --ssh_keyfile ## added the parameter -B / +B ## 27.05.2013 v1.0.0 /bs ## executeCommandAndLog rewritten using coprocesses (see also credits) ## Info update: executeCommandAndLog does now return the RC of the executed ## command even if a logfile is defined ## replaced the runtime system with scriptt.sh v2.0.0 ## the commands can now run in parallel in the background ## (parameter -d, -w, and -W) ## ## 06.06.2013 v1.1.0 /bs ## the parameter -W and now supports a syntax like -W /5 and the ## "/" can be replaced by "," ## the parameter -w and now supports a syntax like -w /5, -w /5/20, ## or -w //10. "/ "can be replaced by "," ## You can now use seconds, minutes, or hours for the time values ## of the parameter -w and -W can now ## ## 28.05.2014 v1.2.0 /bs ## use scriptt.sh v2.0.0.6 ## added the parameter -x (--excludehost) ## added the parameter -A (--includehost) ## enhanced support for binaries ## reworked the usage help ## replaced "which" whith "whence" ## ## 19.09.2014 v1.3.0 /bs ## the script now supports the format user@host ## ## 27.09.2014 v1.3.1 /bs ## added the keyword ignore_user_in_file for the parameter -D ## added the keyword do_not_sort_hostlist for the parameter -D ## added the keyword ssh_binary for the parameter -D ## added the keyword scp_binary for the parameter -D ## added the keyword dos2unix_binary for the parameter -D ## #### #### #### script template History #### ----------------------- #### 1.22.0 08.06.2006 /bs (BigAdmin Version 1) #### public release; starting history for the script template #### #### 1.22.1 12.06.2006 /bs #### added true/false to CheckYNParameter and ConvertToYesNo #### #### 1.22.2. 21.06.2006 /bs #### added the parameter -V #### added the use of environment variables #### added the variable __NO_TIME_STAMPS #### added the variable __NO_HEADERS #### corrected a bug in the function executeCommandAndLogSTDERR #### added missing return commands #### #### 1.22.3 24.06.2006 /bs #### added the function StartStop_LogAll_to_logfile #### added the variable __USE_TTY (used in AskUser) #### corrected an spelling error (dev/nul instead of /dev/null) #### #### 1.22.4 06.07.2006 /bs #### corrected a bug in the parameter error handling routine #### #### 1.22.5 27.07.2006 /bs #### corrected some minor bugs #### #### 1.22.6 09.08.2006 /bs #### corrected some minor bugs #### #### 1.22.7 17.08.2006 /bs #### add the CheckParameterCount function #### added the parameter -T #### added long parameter support (e.g --help) #### #### 1.22.8 07.09.2006 /bs #### added code to save the env variable LANG and set it temporary to C #### #### 1.22.9 20.09.2006 /bs #### corrected code to save the env variable LANG and set it temporary to C #### #### 1.22.10 21.09.2006 /bs #### cleanup comments #### the number of temporary files created automatically is now variable #### (see the variable __NO_OF_TEMPFILES) #### added code to install the trap handler in all functions #### #### 1.22.11 19.10.2006 /bs #### corrected a minor bug in AskUser (/c was not interpreted by echo) #### corrected a bug in the handling of the parameter -S (-S was ignored) #### #### 1.22.12 31.10.2006 /bs #### added the variable __REQUIRED_ZONE #### #### 1.22.13 13.11.2006 /bs #### the template now uses TMP or TEMP if set for the temporary files #### #### 1.22.14 14.11.2006 /bs #### corrected a bug in the function AskUser (the default was y not n) #### #### 1.22.15 21.11.2006 /bs #### added initial support for other Operating Systems #### #### 1.22.16 05.07.2007 /bs #### enhanced initial support for other Operating Systems #### Support for other OS is still not fully tested! #### #### 1.22.17 06.07.2007 /bs #### added the global variable __TRAP_SIGNAL #### #### 1.22.18 01.08.2007 /bs #### __OS_VERSION and __OS_RELEASE were not set - corrected #### #### 1.22.19 04.08.2007 /bs #### wrong function used to print "__TRAP_SIGNAL is \"${__TRAP_SIGNAL}\"" - fixed #### #### 1.22.20 12.09.2007 /bs #### the script now checks the ksh version if running on Solaris #### made some changes for compatibility with ksh93 #### #### 1.22.21 18.09.2007 /bs (BigAdmin Version 2) #### added the variable __FINISHROUTINES #### changed __REQUIRED_ZONE to __REQUIRED_ZONES #### added the variable __KSH_VERSION #### reworked the trap handling #### #### 1.22.22 23.09.2007 /bs #### added the signal handling for SIGUSR1 and SIGUSR2 (variables __SIGUSR1_FUNC and __SIGUSR2_FUNC) #### added user defined function for the signals HUP, BREAK, TERM, QUIT, EXIT, USR1 and USR2 #### added the variables __WARNING_PREFIX, __ERROR_PREFIX, __INFO_PREFIX, and __RUNTIME_INFO_PREFIX #### the parameter -T or --tee can now be on any position in the parameters #### the default output file if called with -T or --tee is now #### /var/tmp/${0##*/}.$$.tee.log #### #### 1.22.23 25.09.2007 /bs #### added the environment variables __INFO_PREFIX, __WARNING_PREFIX, #### __ERROR_PREFIX, and __RUNTIME_INFO_PREFIX #### added the environment variable __DEBUG_HISTFILE #### reworked the function to print the usage help : #### use "-h -v" to view the extented usage help and use "-h -v -v" to #### view the environment variables used also #### #### 1.22.24 05.10.2007 /bs #### another minor fix for ksh93 compatibility #### #### 1.22.25 08.10.2007 /bs #### only spelling errors corrected #### #### 1.22.26 19.11.2007 /bs #### only spelling errors corrected #### #### 1.22.27 29.12.2007 /bs #### improved the code to create the lockfile (thanks to wpollock for the info; see credits above) #### improved the code to create the temporary files (thanks to wpollock for the info; see credits above) #### added the function rand (thanks to wpollock for the info; see credits above) #### the script now uses the directory name saved in the variable $TMPDIR for temporary files #### if it's defined #### now the umask used for creating temporary files can be changed (via variable __TEMPFILE_UMASK) #### #### 1.22.28 12.01.2008 /bs #### corrected a syntax error in the show usage routine #### added the function PrintWithTimestamp (see credits above) #### #### 1.22.29 31.01.2008 /bs #### there was a bug in the new code to remove the lockfile which prevented #### the script from removing the lockfile at program end #### if the lockfile already exist the script printed not the correct error #### message #### #### 1.22.30 28.02.2008 /bs #### Info update: executeCommandAndLog does NOT return the RC of the executed #### command if a logfile is defined #### added inital support for CYGWIN #### (tested with CYGWIN_NT-5.1 v..1.5.20(0.156/4/2) #### Most of the internal functions are NOT tested yet in CYGWIN #### GetCurrentUID now supports UIDs greater than 254; the function now prints the UID to STDOUT #### Corrected bug in GetUserName (only a workaround, not the solution) #### now using printf in the AskUserRoutine #### #### 1.22.30 28.02.2008 /bs #### The lockfile is now also deleted if the script crashes because of a syntax error or something like this #### #### 1.22.31 18.03.2008 /bs #### added the version number to the start and end messages #### an existing config file is now removed (and not read) if the script is called with -C to create a config file #### #### 1.22.32 04.04.2008 /bs #### minor changes for zone support #### #### 1.22.33 12.02.2009 /bs #### disabled the usage of prtdiag due to the fact that prtdiag on newer Sun machines needs a long time to run #### (-> __MACHINE_SUBTYPE is now always empty for Solaris machines) #### added the variable __CONFIG_FILE_FOUND; this variable contains the name of the config file #### read if a config file was found #### added the variable __CONFIG_FILE_VERSION #### #### 1.22.34 28.02.2009 /bs #### added code to check for the max. line no for the debug handler #### (an array in ksh88 can only handle up to 4096 entries) #### added the variable __PIDFILE #### #### 1.22.35 06.04.2009 /bs #### added the variables #### __NO_CLEANUP #### __NO_EXIT_ROUTINES #### __NO_TEMPFILES_DELETE #### __NO_TEMPMOUNTS_UMOUNT #### __NO_TEMPDIR_DELETE #### __NO_FINISH_ROUTINES #### __CLEANUP_ON_ERROR #### CONFIG_FILE #### #### 1.22.36 11.04.2009 /bs #### corrected a cosmetic error in the messages (wrong: ${TEMPFILE#} correct: ${__TEMPFILE#}) #### #### 1.22.37 08.07.2011 /bs #### corrected a minor error with the QUIET parameter #### added code to dump the environment (env var __CREATE_DUMP, function CreateDump ) #### implemented work around for missing function whence in bash #### added the function LogIfNotVerbose #### #### 1.22.38 22.07.2011 /bs #### added code to make the trap handling also work in bash #### added a sample user defined trap handler (function USER_SIGNAL_HANDLER) #### added the function SetHousekeeping to enabe or disable house keeping #### scriptt.sh did not write all messages to the logfile if a relative filename was used - fixed #### added more help text for "-v -v -v -h" #### now user defined signal handler can have arguments #### the RBAC feature (__USE_RBAC) did not work as expected - fixed #### added new scriptt testsuite for testing the script template on other OS and/or shells #### added the function SaveEnvironmentVariables #### #### 1.22.39 24.07.2011 /bs #### __INIT_FUNCTION now enabled for cygwin also #### __SHELL did not work in all Unixes - fixed #### __OS_FULLNAME is now also set in Solaris and Linux #### #### 1.22.40 25.07.2011 /bs #### added some code for ksh93 (functions: substr) #### Note: set __USE_ONLY_KSH88_FEATURES to ${__TRUE} to suppress using the ksh93 features #### The default action for the signal handler USR1 is now "Create an env dump in /var/tmp" #### The filenames for the dumps are #### #### /var/tmp/.envvars.dump_no__ #### /var/tmp/.exported_envvars.dump_no__ #### #### where is a sequential number, is the PID of the process with the script, #### and is the name of the script without the path. #### #### 1.22.41 26.09.2011 /bs #### added the parameter -X #### disabled some ksh93 code because "ksh -x -n" using ksh88 does not like it #### #### 1.22.42 05.10.2011 /bs #### added the function PrintDotToSTDOUT #### #### 1.22.43 15.10.2011 /bs #### added support for disabling the config file feature with CONFIG_FILE=none ./scriptt.sh #### corrected a minor bug in SaveEnvironmentVariables #### corrected a bug in the function SaveEnvironmentVariables #### corrected a bug in getting the value for the variable ${__ABSOLUTE_SCRIPTDIR} #### #### 1.22.44 22.04.2012 /bs #### The script now uses nawk only if available (if not awk is used) #### variables are now supported in the usage examples (prefixed with ##EXAMPLE##) #### add a line with the current date and time to variable dumps, e.g. #### #### ### /var/tmp/scriptt.sh.exported_envvars.dump_no_0_20074 - exported environment variable dump created on Sun Apr 22 11:35:38 CEST 2012 #### #### ### /var/tmp/scriptt.sh.envvars.dump_no_0_20074 - environment variable dump created on Sun Apr 22 11:35:38 CEST 2012 #### #### added experimental interactive mode to the signal handler for USR2 #### replaced /usr/bin/echo with printf #### added the variable LOGMSG_FUNCTION #### #### 1.22.45 07.06.2012 /bs #### added code to check if the symbolic link for the lockfile already exists before creating #### the lock file #### #### 1.22.46 27.04.2013 /bs #### executeCommandAndLog rewritten using coprocesses (see also credits) #### Info update: executeCommandAndLog does now return the RC of the executed #### command even if a logfile is defined #### #### ------------------------------------------------------------------- #### #### 2.0.0.0 17.05.2013 /bs #### added the variable __GENERAL_SIGNAL_FUNCTION: This variable #### contains the name of a function that is called for all SIGNALs #### before the special SIGNAL handler is called #### removed the Debug Handler for single step execution (due to the #### length of the template it is not useful anymore; use the #### version 1.x of scriptt.sh if you still need the Debug Handler) #### function executeCommandAndLogSTDERR rewritten #### removed the function CheckParameterCount #### use lsb_release in Linux to retrieve OS infos if available #### minor fixes for code and comments #### replaced PrintWithTimeStamp with code that does not use awk #### isNumber replaced with code that does not use sed #### #### 2.0.0.1 06.08.2013 /bs #### added the variable __MACHINE_SUB_CLASS. Possible values #### for sun4v machines: either "GuestLDom" or "PrimaryLDom" #### #### 2.0.0.2 01.09.2013 /bs #### added the variables __SYSCMDS and __SYSCMDS_FILE #### #### 2.0.0.3 16.12.2013 /bs #### now the Log-* functions return ${__TRUE} if a message is printed #### and ${__FALSE} if not #### #### 2.0.0.4 01.01.2014 /bs #### the alias __settrap is renamed to settraps (with leading s) #### two new aliase are defined: __ingoretraps and __unsettraps #### whence function for non-ksh compatible shells rewritten #### without using ksh #### the switch -D is now used to toggle debug switches #### known debug switches: #### help -- print the usage help for -D #### msg -- log debug messages to /tmp/..debug #### trace -- activate tracing to the file /tmp/..trace #### AskUser now accepts also "yes" and "no" #### function IsFunctionDefined rewritten #### now __LOGON_USERID and __USERID are equal to $LOGNAME until I #### find a working solution #### (the code in the previous version did not work if STDIN is not a tty) #### #### 2.0.0.5 08.01.2014 /bs #### added the function executeFunctionIfDefined #### #### 2.0.0.6 17.01.2014 /bs #### added the function PrintLine #### added the debug options fn_to_stderr and fn_to_tty #### max. return value for a function is 255 and therefor #### the function for the stack and the functions pos and lastpo #### now abort the script if a value greater than 255 should be returned #### added the variables __HASHTAG, __SCRIPT_SHELL, and __SCRIPT_SHELL_OPTIONS #### #### ---------------- #### Version variables #### #### __SCRIPT_VERSION - the version of your script #### #### typeset -r __SCRIPT_VERSION="v1.3.1" #### #### __SCRIPT_TEMPLATE_VERSION - version of the script template #### typeset -r __SCRIPT_TEMPLATE_VERSION="2.0.0.6 17.01.2014" #### #### ---------------- #### ##R# Predefined return codes: ##R# ------------------------ ##R# ##R# 1 - show usage and exit ##R# 2 - invalid parameter found ##R# ##R# 210 - 233 reserved for the runtime system ##R# 234 - The return value is greater than 255 in function x ##R# 235 - Invalid debug switch found ##R# 236 - syntax error ##R# 237 - Can not write to the debug log file ##R# 238 - unsupported Operating system ##R# 239 - script runs in a not supported zone ##R# 240 - internal error ##R# 241 - a command ended with an error (set -e is necessary to activate this trap) ##R# 242 - the current user is not allowed to execute this script ##R# 243 - invalid machine architecture ##R# 244 - invalid processor type ##R# 245 - invalid machine platform ##R# 246 - error writing the config file ##R# 247 - include script not found ##R# 248 - unsupported OS version ##R# 249 - Script not executed by root ##R# 250 - Script is already running ##R# ##R# 251 - QUIT signal received ##R# 252 - User break ##R# 253 - TERM signal received ##R# 254 - unknown external signal received ##R# #### ---------------- #### Used environment variables #### # # The variable __USED_ENVIRONMENT_VARIABLES is used in the function ShowUsage # __USED_ENVIRONMENT_VARIABLES=" #### __DEBUG_CODE #### __RT_VERBOSE_LEVEL #### __QUIET_MODE #### __VERBOSE_MODE #### __VERBOSE_LEVEL #### __OVERWRITE_MODE #### __USER_BREAK_ALLOWED #### __NO_TIME_STAMPS #### __NO_HEADERS #### __USE_COLORS #### __USE_RBAC #### __RBAC_BINARY #### __TEE_OUTPUT_FILE #### __INFO_PREFIX #### __WARNING_PREFIX #### __ERROR_PREFIX #### __RUNTIME_INFO_PREFIX #### __NO_CLEANUP #### __NO_EXIT_ROUTINES #### __NO_TEMPFILES_DELETE #### __NO_TEMPMOUNTS_UMOUNT #### __NO_TEMPDIR_DELETE #### __NO_FINISH_ROUTINES #### __CLEANUP_ON_ERROR #### __CREATE_DUMP #### __DUMP_ALREADY_CREATED #### __DUMPDIR #### __USE_ONLY_KSH88_FEATURES #### CONFIG_FILE " #### # # binaries and scripts used in this script: # # awk basename cat cp cpio cut date dd dirname egrep expr find grep id ln ls nawk pwd # reboot rm sed sh tee touch tty umount uname who zonename # # /usr/bin/pfexec # /usr/ucb/whoami or $( whence whoami ) # /usr/openwin/bin/resize or $( whence resize ) # # AIX: oslevel # # Linux: lsb_release # # ----------------------------------------------------------------------------- # variables for the trap handler __FUNCTION="main" # alias to install the trap handler # # Note: The statement LINENO=${LINENO} is necessary to use the variable LINENO in the trap command # alias __settraps=" LINENO=\${LINENO} trap 'GENERAL_SIGNAL_HANDLER SIGHUP \${LINENO} \${__FUNCTION}' 1 trap 'GENERAL_SIGNAL_HANDLER SIGINT \${LINENO} \${__FUNCTION}' 2 trap 'GENERAL_SIGNAL_HANDLER SIGQUIT \${LINENO} \${__FUNCTION}' 3 trap 'GENERAL_SIGNAL_HANDLER SIGTERM \${LINENO} \${__FUNCTION}' 15 trap 'GENERAL_SIGNAL_HANDLER SIGUSR1 \${LINENO} \${__FUNCTION}' USR1 trap 'GENERAL_SIGNAL_HANDLER SIGUSR2 \${LINENO} \${__FUNCTION}' USR2 " # alias to ignore all traps # alias __ingoretraps=" LINENO=\${LINENO} trap '' 1 trap '' 2 trap '' 3 trap '' 15 trap '' USR1 trap '' USR2 " # alias to reset all traps to the defaults # alias __unsettraps=" LINENO=\${LINENO} trap 1 trap 2 trap 3 trap 15 trap USR1 trap USR2 " #### ---------------- #### ##### general hints #### #### Do not use variable names beginning with __ (these are reserved for #### internal use) #### # save the language setting and switch the language temporary to C # __SAVE_LANG="${LANG}" LANG=C export LANG # ----------------------------------------------------------------------------- #### ##### constants #### #### __TRUE - true (0) #### __FALSE - false (1) #### #### typeset -r __TRUE=0 typeset -r __FALSE=1 # ----------------------------------------------------------------------------- #### __KSH_VERSION - ksh version (either 88 or 93) #### If the script is not executed by ksh the shell is compatible to ### ksh version $__KSH_VERSION #### __KSH_VERSION=88 ; f() { typeset __KSH_VERSION=93 ; } ; f ; # use ksh93 features? # if [ "${__KSH_VERSION}"x = "93"x ] ; then __USE_ONLY_KSH88_FEATURES=${__USE_ONLY_KSH88_FEATURES:=${__FALSE}} else __USE_ONLY_KSH88_FEATURES=${__USE_ONLY_KSH88_FEATURES:=${__TRUE}} fi #### __OS - Operating system (e.g. SunOS) #### __OS="$( uname -s )" # ---------------------------------------------------------------------- # read the hash tag of the script # #### __HASHTAG - hash tag of the script #### __SCRIPT_SHELL - shell in the hash tag of the script #### __SCRIPT_SHELL_OPTIONS - shell options in the hash tag of the script #### #### __HASHTAG="$( head -1 $0 )" __SCRIPT_SHELL="${__HASHTAG#*!}" __SCRIPT_SHELL="${__SCRIPT_SHELL% *}" __SCRIPT_SHELL_OPTIONS="${__HASHTAG#* }" [ "${__SCRIPT_SHELL_OPTIONS}"x = "${__HASHTAG}"x ] && __SCRIPT_SHELL_OPTIONS="" # ----------------------------------------------------------------------------- # specific settings for the various operating systems and shells # # case ${__OS} in CYGWIN* ) set +o noclobber __SHELL_FIELD=9 ;; SunOS | AIX ) __SHELL_FIELD=9 ;; * ) __SHELL_FIELD=8 ;; esac # ----------------------------------------------------------------------------- # specific settings for various shells # #### __SHELL - name of the current shell executing this script #### __SHELL="$( ps -f -p $$ | grep -v PID | tr -s " " | cut -f${__SHELL_FIELD} -d " " )" __SHELL=${__SHELL##*/} : ${__SHELL:=ksh} case "${__SHELL}" in "bash" ) # set shell options for alias expanding if running in bash shopt -s expand_aliases ;; esac # ----------------------------------------------------------------------------- # define whence if necessary # # old definition for whence: # # whence whence 2>/dev/null 1>/dev/null || function whence { ksh whence -p $* ; } # new definition for whence: # whence whence 2>/dev/null 1>/dev/null || function whence { if typeset -f $1 1>/dev/null ; then echo $1 elif alias $1 2>/dev/null 1>/dev/null ; then echo $1 else which $1 2>/dev/null fi } #### -------------------------------------------------------------------------- #### internal variables # ----------------------------------------------------------------------------- #### #### __LOG_DEBUG_MESSAGES - log debug messages if set to true #### This can be activated with the parameter -D msg #### __LOG_DEBUG_MESSAGES=${__FALSE} # ----------------------------------------------------------------------------- #### __ACTIVATE_TRACE - log trace messages (set -x) if set to true #### This can be activated with the parameter -D trace ### __ACTIVATE_TRACE=${__FALSE} # ----------------------------------------------------------------------------- #### #### __TRAP_SIGNAL - current trap caught by the trap handler #### This is a global variable that can be used in the exit routines #### __TRAP_SIGNAL="" # ----------------------------------------------------------------------------- #### __USE_RBAC - set this variable to ${__TRUE} to execute this script #### with RBAC #### default is ${__FALSE} #### #### Note: You can also set this environment variable before starting the script #### : ${__USE_RBAC:=${__FALSE}} # ----------------------------------------------------------------------------- #### __RBAC_BINARY - pfexec binary #### #### default is /usr/bin/pfexec #### #### Note: You can also set this environment variable before starting the script #### : ${__RBAC_BINARY:=/usr/bin/pfexec} # ----------------------------------------------------------------------------- # # user executing this script (works only if using a ssh session with specific # ssh versions that export these variables!) # SCRIPT_USER="$( echo $SSH_ORIGINAL_USER | tr "=" " " | cut -f 5 -d " " )" SCRIPT_USER_MSG="${SCRIPT_USER}" # ----------------------------------------------------------------------------- #### __TEE_OUTPUT_FILE - name of the output file if called with the parameter -T #### default: /var/tmp/$( basename $0 ).$$.tee.log #### #### Note: You can also set this environment variable before starting the script #### : ${__TEE_OUTPUT_FILE:=/var/tmp/${0##*/}.$$.tee.log} # ----------------------------------------------------------------------------- # process the parameter -q or --quiet # if [[ \ $*\ == *\ -q* || \ $*\ == *\ --quiet\ * ]] ; then __NO_HEADERS=${__TRUE} __QUIET_MODE=${__TRUE} fi # ----------------------------------------------------------------------------- # config file found or not # __CONFIG_FILE_FOUND="" # ----------------------------------------------------------------------------- # use the parameter -T or --tee to automatically call the script and pipe # all output to tee if [ "${__PPID}"x = ""x ] ; then __PPID=$PPID ; export __PPID if [[ \ $*\ == *\ -T* || \ $*\ == *\ --tee\ * ]] ; then echo "Saving STDOUT and STDERR to \"${__TEE_OUTPUT_FILE}\" ..." exec $0 $@ 2>&1 | tee -a "${__TEE_OUTPUT_FILE}" __MAINRC=$? echo "STDOUT and STDERR saved in \"${__TEE_OUTPUT_FILE}\"." exit ${__MAINRC} fi fi : ${__PPID:=$PPID} ; export __PPID # ----------------------------------------------------------------------------- # # Set the variable ${__USE_RBAC} to ${__TRUE} to activate RBAC support # # Allow the use of RBAC to control who can access this script. Useful for # administrators without root permissions # if [ "${__USE_RBAC}" = "${__TRUE}" ] ; then if [ "$_" != "${__RBAC_BINARY}" -a -x "${__RBAC_BINARY}" ]; then __USE_RBAC=${__FALSE} "${__RBAC_BINARY}" $0 $* exit $? else echo "${0%%*/} ERROR: \"${__RBAC_BINARY}\" not found or not executable!" >&2 exit 238 fi fi # ----------------------------------------------------------------------------- #### #### ##### defined variables that may be changed #### #### __DEBUG_CODE - code executed at start of every sub routine #### Note: Use always "__DEBUG_CODE="eval ..." if you want to use variables or aliases #### Default debug code : none #### #### sample debug code: #### __DEBUG_CODE=" eval echo Entering the subroutine \${__FUNCTION} ... " #### #### Note: Use an include script for more complicated debug code, e.g. #### __DEBUG_CODE=" eval . /var/tmp/mydebugcode" #### __DEBUG_CODE="" #### __FUNCTION_INIT - code executed at start of every sub routine #### (see the hints for __DEBUG_CODE) #### Default init code : install the trap handlers #### # __FUNCTION_INIT=" eval __settraps; echo \"Now in function \${__FUNCTION}\" " __FUNCTION_INIT=" eval __settraps " ### variables for debugging ### ### __NO_CLEANUP - do not call the cleanup routine at all at script end if ${__TRUE} ### : ${__NO_CLEANUP:=${__FALSE}} #### __NO_EXIT_ROUTINES - do not execute the exit routines if ${__TRUE} #### : ${__NO_EXIT_ROUTINES:=${__FALSE}} #### __NO_TEMPFILES_DELETE - do not remove temporary files at script end if ${__TRUE} #### : ${__NO_TEMPFILES_DELETE:=${__FALSE}} #### __NO_TEMPMOUNTS_UMOUNT - do not umount temporary mount points at script end if ${__TRUE} #### : ${__NO_TEMPMOUNTS_UMOUNT:=${__FALSE}} #### __NO_TEMPDIR_DELETE - do not remove temporary directories at script end if ${__TRUE} #### : ${__NO_TEMPDIR_DELETE:=${__FALSE}} #### __NO_FINISH_ROUTINES - do not execute the finish routeins at script end if ${__TRUE} #### : ${__NO_FINISH_ROUTINES:=${__FALSE}} #### __CLEANUP_ON_ERROR - call cleanup if the script was aborted by a syntax error #### : ${__CLEANUP_ON_ERROR:=${__FALSE}} # default log file for debug messages # # This filename is already defined here to catch all debug log messages # The file will be deleted if the debug switch for writing this log # is missing. # To use this file enter the parameter "-D msg" # __DEBUG_LOGFILE="/tmp/${0##*/}.$$.debug" # default log file for trace output # To use this file enter the parameter "-D trace" # __TRACE_LOGFILE="/tmp/${0##*/}.$$.trace" #### __CONFIG_PARAMETER #### The variable __CONFIG_PARAMETER contains the configuration variables #### #### The defaults for these variables are defined here. You #### can use a config file to overwrite the defaults. #### #### Use the parameter -C to create a default configuration file #### #### Note: The config file is read and interpreted via ". configfile" #### therefore you can also add some code here #### __CONFIG_PARAMETER="__CONFIG_FILE_VERSION=\"${__SCRIPT_VERSION}\" "' # directory for temporary files in parallel mode if -U is not used # TMP_OUTPUT_DIR="" # extension for backup files # DEFAULT_BACKUP_EXTENSION=".$$.backup" # allow the debug shell in AskUser # __DEBUG_SHELL_IN_ASKUSER=${__TRUE} #### __DUMP_ALREADY_CREATED - do not automatically create another dump if #### this variable is ${__TRUE} #### # __DUMP_ALREADY_CREATED=${__TRUE} #### __CREATE_DUMP - create an environment dump if the scripts exits with #### error #### (replace with either 0 or the directory for #### the dumps) to always create a dump at script end #### # __CREATE_DUMP= #### DEFAULT_DUMPDIR - default directory for environment dumps #### DEFAULT_DUMP_DIR="${TMPDIR:-${TMP:-${TEMP:-/tmp}}}" # variables that can be changed via parameter # # default for the parameter -b DEFAULT_SSH_KEYFILE="" # default for the parameter -B DEFAULT_DO_NOT_COPY_FILE=${__FALSE} # default for the parameter -K DEFAULT_NOSTRICTKEYS=${__FALSE} # default for the parameter -i DEFAULT_HOSTFILE="" # default for the parameter -I DEFAULT_FILE_BASEDIR="" # default for the parameter -s DEFAULT_SCRIPTFILE="" # default for the parameter -o DEFAULT_OUTPUTFILE="/var/tmp/${__SCRIPTNAME##*/}.$$.cmds.log" # default for the parameter -u DEFAULT_SSHUSER="support" # default for the parameter -c DEFAULT_SHELL_TO_USE="/usr/bin/ksh" # default for the parameter -k DEFAULT_ADD_COMMENTS=${__TRUE} # default for the parameter -U DEFAULT_UNIQUE_LOGFILES=${__FALSE} # default for the parameter -P DEFAULT_SSH_OPTIONS="" # default for the parameter -p DEFAULT_SCP_OPTIONS="" # execute the command in parallel? -- default for the parameter -d DEFAULT_EXECUTE_PARALLEL=${__FALSE} # wait time in seconds for the background processes # -- 1st default for the parameter -W DEFAULT_MAX_RUN_WAIT_TIME=1h # wait intervall in seconds for the background processes # -- 2nd default for the parameter -W DEFAULT_RUN_WAIT_INTERVALL=2s # maximum number of background processes # -- 1st default for the parameter -w DEFAULT_MAX_NO_OF_BACKGROUND_PROCESSES=-1 # wait intervall for starting the background processes # -- 2nd default for the parameter -w DEFAULT_START_PROC_WAIT_INTERVALL=5s # timeout value for the start of the parallel background processes # -- 3rd default for the parameter -w DEFAULT_START_PROC_TIMEOUT=5m # hosts on the host exclude list -- default for the parameter -x DEFAULT_EXCLUDE_HOSTS="" # hosts on the host include list -- default for the parameter -A DEFAULT_INCLUDE_HOSTS="" # default for the RCM support DEFAULT_COPY_TABLE_BINARY=$( whence copy_table.pl ) [ "${DEFAULT_COPY_TABLE_BINARY}"x = ""x ] && DEFAULT_COPY_TABLE_BINARY=$( whence copy_table.pl ) [ "${DEFAULT_COPY_TABLE_BINARY}"x = "no"x ] && DEFAULT_COPY_TABLE_BINARY="" [ -x "${DEFAULT_COPY_TABLE_BINARY}" ] && DEFAULT_RCM_SUPPORT=${__TRUE} || DEFAULT_RCM_SUPPORT=${__FALSE} # ignore users from the hostlists (parameter -D ignore_user_in_file # DEFAULT_IGNORE_USER_IN_FILE=${__FALSE} # do not sort the host list (parameter -D do_not_sort_hostlist) # DEFAULT_DO_NOT_SORT_HOSTLIST=${__FALSE} # ssh binary to use (parameter -D ssh_binary) # DEFAULT_NEW_SSH_BINARY="" # scp binary to use (parameter -D scp_binary) # DEFAULT_NEW_SCP_BINARY="" # dos2unix binary to use (parameter -D dos2unix_binary) # DEFAULT_NEW_DOS2UNIX_BINARY="" # variables that can NOT be changed with parameter # binaries used DEFAULT_SSH_BINARY="ssh" DEFAULT_SCP_BINARY="scp" DEFAULT_DOS2UNIX_BINARY="$( whence dos2unix )" # only change the following variables if you know what you are doing # # no further internal variables defined yet # # Note you can redefine any variable that is initialized before calling # ReadConfigFile here! ' # end of config parameters #### __SHORT_DESC - short description (for help texts, etc) #### Change to your need #### typeset -r __SHORT_DESC="copy a script to a list of hosts via scp and execute it on the hosts using ssh" #### __LONG_USAGE_HELP - Additional help if the script is called with #### the parameter "-v -h" #### #### Note: To use variables in the help text use the variable name without #### an escape character, eg. ${OS_VERSION} #### __LONG_USAGE_HELP=' -i hostlist \"hostlist\" is the file with the list of hosts to process. Format: one hostname per line (use user@host to use an explicit user for a host); empty lines and lines beginning with a hash \"#\" are ignored. Use a comma \",\" to separate multiple hostlists or use the parameter \"-i\" more than one time. All hostlists are merged and sorted. Each host in the list(s) is only processed one time. Missing hostlist files are treated as error. To ignore a missing hostlist file add a leading \"?\" to the filename. Current Value: \"${HOSTFILE}\" Long format: --hostlist -x hostname exclude the host \"hostname\" from the execution This parameter can be used multiple times; regular expressions for \"hostname\" are allowed. Use \"-x none\" to clear the list of hosts to exclude. Use a relative or absolute filename for \"hostname\" to read the hosts to exclude from a file. Format of the file: one hostname per line; empty lines and lines beginning with \"#\" are ignored. The file must exist. Current Value: \"${EXCLUDE_HOSTS}\" Long format: --excludehost -A hostname add the host \"hostname\" to the list of hosts This parameter can be used multiple times; regular expressions for \"hostname\" are not allowed. Use \"-A none\" to clear the list of hosts to include. Current Value: \"${INCLUDE_HOSTS}\" Long format: --includehost -s scriptfile scriptfile is the script or executable to execute on all hosts; it will be copied to and executed on each host using scp/ssh with the user \"sshuser\". If \"scriptfile\" is a binary it will be executed directly; If \"scriptfile\" is not a binary it will be executed either by the default shell for \"sshuser\" or by the shell specified with the parameter \"-c\". If this script is running in a cygwin session and the binary dos2unix is available via the path the script will be converted to Unix style using dos2unix. If \"-B\" is used, the value for this parameter is a command to execute on the hosts without first copying it to the host. In this case the command is executed without calling a shell. Use \\; in this case to separate multiple commands to execute. e.g: -s \"uname -a \\; uptime \" Current value: \"${SCRIPTFILE}\" Long format: --scriptfile -u sshuser \"sshuser\" is the userid to use for ssh and scp on the target hosts Current value \"${SSHUSER}\" Long format: --sshuser -c shell_to_use \"shell_to_use\" is the shell to execute the script on the hosts Use \"none\" to execute the script with the default shell of the \"sshuser\". If \"-B\" is used or if the command to execute (parameter \"-s\") is a binary this parameter is ignored and the command is always executed by the default shell of the \"sshuser\". Current value \"${SHELL_TO_USE}\" Long format: --shell -I basedir \"basedir\" is the directory with the hostlist and the script files; if this parameter is found the script searches the hostlist files and the script files in this directory also Current value: \"${FILE_BASEDIR}\" Long format: --basedir -o outputfile \"outputfile\" is the name of the file for the output generated by the commands. If \"-U\" is also used the output for each host is logged into a separate file named \".\" Current value \"${OUTPUTFILE}\" Long format: --outputfile -p scpoptions \"scpoptions\" are additional options for scp, e.g -p \"-o StrictHostKeyChecking=no\" Current value \"${SCP_OPTIONS}\" Long format: --scpoptions -P sshoptions \"sshoptions\" are additional options for ssh Current value \"${SSH_OPTIONS}\" Long format: --sshoptions -K|+K use the option \"StrictHostKeyChecking=no\" for ssh and scp Current value: $( ConvertToYesNo ${NOSTRICTKEYS} ) Long format: --nostrictkeys -k|+k add comments to the output file Current value: $( ConvertToYesNo "${ADD_COMMENTS}" ) Long format: --nocomments -B|+B do not upload a script to the hosts In this case the value for the parameter \"-s\" is interpreted as command to execute and the value for the shell to use (parameter \"-c\") is ignored. Current value: $( ConvertToYesNo ${DO_NOT_COPY_FILE} ) Long format: --do_not_copy -b ssh_keyfile Use the ssh key file \"ssh_keyfile\" for ssh and scp. Default: Use the default ssh key files for the user \"sshuser\" for ssh/scp Current value: \"${SSH_KEYFILE}\" Long format: --ssh_keyfile -U|+U create unique log files (see parameter \"-o\") Current value: $( ConvertToYesNo "${UNIQUE_LOGFILES}" ) Long format: --uniquelogfiles -R|+R use RCM methods The default value depends on the existence of copy_table.pl in the PATH. Use the environment variables RCM_USERID and RCM_PASSWORD to set the RCM userid and password. If these variables are not set the script will prompt the user for them. Current value: $( ConvertToYesNo "${RCM_SUPPORT}" ) Long format: --rcm -d|+d execute the commands in parallel Current value: $( ConvertToYesNo "${EXECUTE_PARALLEL}" ) Long format: --parallel -W timeout[/intervall] \"timeout\" is the timeout for background processes and \"intervall\" is the wait intervall for background processes. Use \"-1\" or \"none\" for the timeout value to disable the timeout. Current values: Timeout: ${MAX_RUN_WAIT_TIME} (= $( CalculateSeconds ${MAX_RUN_WAIT_TIME} ) second(s) ) Intervall: ${RUN_WAIT_INTERVALL} (= $( CalculateSeconds ${RUN_WAIT_INTERVALL} ) second(s) ) Use a trailing \"m\" for times in minutes or a trailing \"h\" for times in hours; \"s\" is for seconds which is the default if neither \"m\" nor \"h\" is used. Use \"default\" for any value to use the default value. Use \" -W /intervall\" to only change the intervall. You can also use \",\" to separate the values. This parameter is only used if the commands are executed in parallel (parameter \"-d\") Long format: --timeout -w noOfBackgroundprocesses[/startIntervall[/maxStartTime]] \"noOfBackgroundprocesses\" is the max. number of background processes running at the same time, \"startIntervall\" is the wait intervall and \"maxStartTime\" is the timeout for starting the background processes. Use \"-1\" or \"none\" for an unlimited number of parallel background processes. Use \"-1\" or \"none\" for the timeout value to disable the timeout. Current values: Max. number of parallel running background processes: ${MAX_NO_OF_BACKGROUND_PROCESSES} Wait intervall: ${START_PROC_WAIT_INTERVALL} (= $( CalculateSeconds ${START_PROC_WAIT_INTERVALL} ) second(s) ) Timeout value: ${START_PROC_TIMEOUT} (= $( CalculateSeconds ${START_PROC_TIMEOUT} ) second(s) ) Use a trailing \"m\" for times in minutes or a trailing \"h\" for times in hours; \"s\" is for seconds which is the default if neither \"m\" nor \"h\" is used. Use \"default\" for any value to use the default value. Use \" -w /startIntervall\" to only change the start intervall. Use \" -w //maxStartTime\" to only change the timeout You can also use \",\" to separate the values. This parameter is only used if the commands are executed in parallel (parameter \"-d\") Long format: --noOfbackgroundProcesses ' #### __SHORT_USAGE_HELP - Additional help if the script is called with the parameter "-h" #### #### Note: To use variables in the help text use the variable name without an escape #### character, eg. ${OS_VERSION} #### __SHORT_USAGE_HELP=' [-i hostlist{,hostlist1{,...}] [-s scriptfile] [-o outputfile] [-u sshuser] [-I basedir] [-c shell] [-k] [-U] [-p scpoptions] [-P sshoptions] [-K] [-R] [-B|+B] [-b ssh_keyfile] [-x excludehost] [-A includehost] [-d|+d] [-W [timeout[/intervall]] [-w NoOfBackgroundProcs[/intervall[/timeout]]]] [hostlist [scriptfile [outputfile [sshuser]]]] The parameters scriptfile, outputfile, and sshuser overwrite the options; hostlist and scriptfile are mandatory either as parameter or as option. For optimal usage ssh login via public key should be enabled on the target hosts and the ssh agent should run on this host (the agent is currently ${SSH_AGENT_STATUS}). Use the parameter \"-v -h [-v]\" to view the detailed online help; use the parameter \"-X\" to view some usage examples. see also http://bnsmb.de/solaris/execute_on_all_hosts.html ' #### __MUST_BE_ROOT - run script only by root (def.: false) #### set to ${__TRUE} for scripts that must be executed by root only #### __MUST_BE_ROOT=${__FALSE} #### __REQUIRED_USERID - required userid to run this script (def.: none) #### use blanks to separate multiple userids #### e.g. "oracle dba sysdba" #### "" = no special userid required (see also the variable __MUST_BE_ROOT) #### __REQUIRED_USERID="" #### __REQUIRED_ZONES - required zones (either global, non-global or local #### or the names of the valid zones) #### This is a Solaris only feature! #### (def.: none) #### "" = no special zone required #### __REQUIRED_ZONES="" #### __ONLY_ONCE - run script only once at a time (def.: false) #### set to ${__TRUE} for scripts that can not run more than one instance at #### the same time #### __ONLY_ONCE=${__FALSE} #### __ REQUIRED_OS - required OS (uname -s) for the script (def.: none) #### use blanks to separate the OS names if the script runs under multiple OS #### e.g. "SunOS" #### __REQUIRED_OS="" #### __REQUIRED_OS_VERSION - required OS version for the script (def.: none) #### minimum OS version necessary, e.g. 5.10 #### "" = no special version necessary #### __REQUIRED_OS_VERSION="" #### __REQUIRED_MACHINE_PLATFORM - required machine platform for the script (def.: none) #### required machine platform (uname -i) , e.g "i86pc"; use blanks to separate #### the multiple machine types, e.g "Sun Fire 3800 i86pc" #### "" = no special machine type necessary #### __REQUIRED_MACHINE_PLATFORM="" #### __REQUIRED_MACHINE_CLASS - required machine class for the script (def.: none) #### required machine class (uname -m) , e.g "i86pc" ; use blanks to separate #### the multiple machine classes, e.g "sun4u i86pc" #### "" = no special machine class necessary #### __REQUIRED_MACHINE_CLASS="" #### __REQUIRED_MACHINE_ARC - required machine architecture for the script (def.: none) #### required machine architecture (uname -p) , e.g "i386" ; use blanks to separate #### the machine architectures if more than one entry, e.g "sparc i386" #### "" = no special machine architecture necessary #### __REQUIRED_MACHINE_ARC="" #### __VERBOSE_LEVEL - count of -v parameter (def.: 0) #### #### Note: You can also set this environment variable before starting the script #### typeset -i __VERBOSE_LEVEL=${__VERBOSE_LEVEL:=0} #### __RT_VERBOSE_LEVEL - level of -v for runtime messages (def.: 1) #### #### e.g. 1 = -v -v is necessary to print info messages of the runtime system #### 2 = -v -v -v is necessary to print info messages of the runtime system #### #### Note: You can also set this environment variable before starting the script #### typeset -i __RT_VERBOSE_LEVEL=${__RT_VERBOSE_LEVEL:=1} #### __QUIET_MODE - do not print messages to STDOUT (def.: false) #### use the parameter -q/+q to change this variable #### #### Note: You can also set this environment variable before starting the script #### : ${__QUIET_MODE:=${__FALSE}} #### __VERBOSE_MODE - print verbose messages (def.: false) #### use the parameter -v/+v to change this variable #### #### Note: You can also set this environment variable before starting the script #### : ${__VERBOSE_MODE:=${__FALSE}} #### __NO_TIME_STAMPS - Do not use time stamps in the messages (def.: false) #### #### Note: You can also set this environment variable before starting the script #### : ${__NO_TIME_STAMPS:=${__FALSE}} #### __NO_HEADERS - Do not print headers and footers (def.: false) #### #### Note: You can also set this environment variable before starting the script #### : ${__NO_HEADERS:=${__FALSE}} #### __FORCE - do the action anyway (def.: false) #### If this variable is set to ${__TRUE} the function "die" will return #### if called with an RC not zero (instead of aborting the script) #### use the parameter -f/+f to change this variable #### __FORCE=${__FALSE} #### __USE_COLORS - use colors (def.: false) #### use the parameter -a/+a to change this variable #### #### Note: You can also set this environment variable before starting the script #### : ${__USE_COLORS:=${__FALSE}} #### __USER_BREAK_ALLOWED - CTRL-C aborts the script or not (def.: true) #### (no parameter to change this variable) #### #### Note: You can also set this environment variable before starting the script #### : ${__USER_BREAK_ALLOWED:=${__TRUE}} #### __NOECHO - turn echo off while reading input from the user #### do not echo the user input in AskUser if __NOECHO is set to ${__TRUE} #### __NOECHO=${__FALSE} #### __USE_TTY - write prompts and read user input from /dev/tty (def.: false) #### If __USE_TTY is ${__TRUE} the function AskUser writes the prompt to /dev/tty #### and the reads the user input from /dev/tty . This is useful if STDOUT is #### redirected to a file. #### __USE_TTY=${__FALSE} #### __OVERWRITE mode - overwrite existing files or not (def.: false) #### use the parameter -O/+O to change this variable #### #### Note: You can also set this environment variable before starting the script #### : ${__OVERWRITE_MODE:=${__FALSE}} #### __TEMPDIR - directory for temporary files #### The default is $TMPDIR (if defined), or $TMP (if defined), #### or $TEMP (if defined) or /tmp if none of the variables is #### defined #### __TEMPDIR="${TMPDIR:-${TMP:-${TEMP:-/tmp}}}" #### __NO_OF_TEMPFILES #### number of automatically created tempfiles that are deleted at program end #### (def. 2) #### Note: The variable names for the tempfiles are __TEMPFILE1, __TEMPFILE2, etc. #### __NO_OF_TEMPFILES=2 #### __TEMPFILE_UMASK #### umask for creating temporary files (def.: 177) #### __TEMPFILE_UMASK=177 #### __LIST_OF_TMP_MOUNTS - list of mounts that should be umounted at program end #### __LIST_OF_TMP_MOUNTS="" #### __LIST_OF_TMP_DIRS - list of directories that should be removed at program end #### __LIST_OF_TMP_DIRS="" #### __LIST_OF_TMP_FILES - list of files that should be removed at program end #### __LIST_OF_TMP_FILES="" #### __SYSCMDS - list of commands execute via one of the execute... functions ### __SYSCMDS="" #### __SYSCMDS_FILE - write the list of executed commands via the execute function to #### this file at program end #### __SYSCMDS_FILE="" #### __EXITROUTINES - list of routines that should be executed before the script ends #### Note: These routines are called *before* temporary files, temporary #### directories, and temporary mounts are removed #### __EXITROUTINES="" #### __FINISHROUTINES - list of routines that should be executed before the script ends #### Note: These routines are called *after* temporary files, temporary #### directories, and temporary mounts are removed #### __FINISHROUTINES="" #### __GENERAL_SIGNAL_FUNCTION - name of the function to execute if a signal is received #### default signal handling: none #### #### This variable can be used to define a general user defined signal handler for #### all signals catched. If this signal handler is defined it will be called first #### for every signal. If the handler returns 0 the user defined signal handler for #### the signal will be called (if defined). If the handler returns a value other #### than 0 no other signal handler is called. #### #### see USER_SIGNAL_HANDLER for an example user signal handler #### __GENERAL_SIGNAL_FUNCTION="" #### __SIGNAL_SIGUSR1_FUNCTION - name of the function to execute if the signal SIGUSR1 is received #### default signal handling: create variable dump #### #### If a user defined function ends with a return code not equal zero the default #### action for the SIGUSR1 signal is not executed. #### #### see USER_SIGNAL_HANDLER for an example user signal handler #### __SIGNAL_SIGUSR1_FUNCTION="" #### __SIGNAL_SIGUSR2_FUNCTION - name of the function to execute if the signal SIGUSR2 is received #### default signal handling: call an interactive shell (experimental!) #### #### If a user defined function ends with a return code not equal zero the default #### action for the SIGUSR2 signal is not executed. #### #### see USER_SIGNAL_HANDLER for an example user signal handler #### __SIGNAL_SIGUSR2_FUNCTION="" #### __SIGNAL_SIGHUP_FUNCTION - name of the function to execute if the signal SIGHUP is received #### default signal handling: switch verbose mode on or off #### #### If a user defined function ends with a return code not equal zero the default #### action for the SIGHUP signal is not executed. #### #### see USER_SIGNAL_HANDLER for an example user signal handler #### __SIGNAL_SIGHUP_FUNCTION="" #### __SIGNAL_SIGINT_FUNCTION - name of the function to execute if the signal SIGINT is received #### default signal handling: end the script if ${__USER_BREAK_ALLOWED} is ${__TRUE} else ignore the signal #### #### If a user defined function ends with a return code not equal zero the default #### action for the SIGINT signal is not executed. #### #### see USER_SIGNAL_HANDLER for an example user signal handler #### __SIGNAL_SIGINT_FUNCTION="" #### __SIGNAL_SIGQUIT_FUNCTION - name of the function to execute if the signal SIGQUIT is received #### default signal handling: end the script #### #### If a user defined function ends with a return code not equal zero the default #### action for the SIGQUIT signal is not executed. #### #### see USER_SIGNAL_HANDLER for an example user signal handler #### __SIGNAL_SIGQUIT_FUNCTION="" #### __SIGNAL_SIGTERM_FUNCTION - name of the function to execute if the signal SIGTERM is received #### default signal handling: end the script #### #### If a user defined function ends with a return code not equal zero the default #### action for the SIGTERM signal is not executed. #### #### see USER_SIGNAL_HANDLER for an example user signal handler #### __SIGNAL_SIGTERM_FUNCTION="" #### __REBOOT_REQUIRED - set to true to reboot automatically at #### script end (def.: false) #### #### Note: #### To use this feature it must be enabled in the function RebootIfNecessary! #### __REBOOT_REQUIRED=${__FALSE} #### __REBOOT_PARAMETER - parameter for the reboot command (def.: none) #### __REBOOT_PARAMETER="" #### __INFO_PREFIX - prefix for INFO messages printed if __VERBOSE_MODE = ${__TRUE} #### default: "INFO: " #### : ${__INFO_PREFIX:=INFO: } #### __WARNING_PREFIX - prefix for WARNING messages #### default: "WARNING: " #### : ${__WARNING_PREFIX:=WARNING: } #### __ERROR_PREFIX - prefix for ERROR messages #### default: "ERROR: " #### : ${__ERROR_PREFIX:=ERROR: } #### __RUNTIME_INFO_PREFIX - prefix for INFO messages of the runtime system #### default: "RUNTIME INFO: " #### : ${__RUNTIME_INFO_PREFIX:=RUNTIME INFO: } #### __PRINT_LIST_OF_WARNINGS_MSGS - print the list of warning messages at program end (def.: false) #### __PRINT_LIST_OF_WARNINGS_MSGS=${__FALSE} #### __PRINT_LIST_OF_ERROR_MSGS - print the list of error messages at program end (def.: false) #### __PRINT_LIST_OF_ERROR_MSGS=${__FALSE} #### __PRINT_SUMMARIES - print error/warning msg summaries at script end #### #### print error and/or warning message summaries at program end #### known values: #### 0 = do not print summaries #### 1 = print error msgs #### 2 = print warning msgs #### 3 = print error and warning mgs #### use the parameter -S to change this variable #### __PRINT_SUMMARIES=0 #### __MAINRC - return code of the program #### __MAINRC=0 # ----------------------------------------------------------------------------- # # ----------------------------------------------------------------------------- # init the global variables # #### ##### defined variables that should not be changed #### # init the variable for the TRAP handlers # __INCLUDE_SCRIPT_RUNNING contains the name of the included script if # a sourced-in script is currently running # __INCLUDE_SCRIPT_RUNNING="" # # internal variables for push/pop # typeset -i __STACK_POINTER=0 __STACK[0]=${__STACK_POINTER} # variable used for input by the user # __USER_RESPONSE_IS="" # __STTY_SETTINGS # saved stty settings before switching off echo in AskUser # __STTY_SETTINGS="" #### __SCRIPTNAME - name of the script without the path #### typeset -r __SCRIPTNAME="${0##*/}" #### __SCRIPTDIR - path of the script (as entered by the user!) #### __SCRIPTDIR="${0%/*}" #### __REAL_SCRIPTDIR - path of the script (real path, maybe a link) #### __REAL_SCRIPTDIR=$( cd -P -- "$(dirname -- "$(command -v -- "$0")")" && pwd -P ) #### __CONFIG_FILE - name of the default config file #### (use ReadConfigFile to read the config file; #### use WriteConfigFile to write it) #### use none to disable the config file feature #### __CONFIG_FILE="${__SCRIPTNAME%.*}.conf" #### __PIDFILE - save the pid of the script in a file #### #### example usage: __PIDFILE="/tmp/${__SCRIPTNAME%.*}.pid" #### __PIDFILE="" #### __HOSTNAME - hostname #### __HOSTNAME="$( uname -n )" #### __NODENAME - nodename #### __NODENAME=${__HOSTNAME} [ -f /etc/nodename ] && __NODENAME="$( cat /etc/nodename )" #### __OS_FULLNAME - Operating system (e.g. CYGWIN_NT-5.1) #### __OS_FULLNAME="" #### __ZONENAME - name of the current zone if running in Solaris 10 or newer #### #### __OS_VERSION - Operating system version (e.g 5.8) #### #### __OS_RELEASE - Operating system release (e.g. Generic_112233-08) #### #### __MACHINE_CLASS - Machine class (e.g sun4u) #### #### __MACHINE_SUB_CLASS - Machine sub class #### either GuestLDom or PrimaryLDom for sun4v LDoms #### __MACHINE_SUB_CLASS="" #### __MACHINE_PLATFORM - hardware platform (e.g. SUNW,Ultra-4) #### #### __MACHINE_SUBTYPE - machine type (e.g Sun Fire 3800) #### #### __MACHINE_ARC - machine architecture (e.g. sparc) #### #### __RUNLEVEL - current runlevel #### # __RUNLEVEL="$( set -- $( who -r ) ; echo $7 )" case ${__OS} in "SunOS" ) [ -r /etc/release ] && __OS_FULLNAME="$( grep Solaris /etc/release | tr -s " " | cut -f2- -d " " )" __ZONENAME="$( zonename 2>/dev/null )" __OS_VERSION="$( uname -r )" __OS_RELEASE="$( uname -v )" __MACHINE_CLASS="$( uname -m )" if [ "${__MACHINE_CLASS}"x = "sun4v"x -a "${__ZONENAME}"x = "global"x ] ; then [ ! -d /dev/usb ] && __MACHINE_SUB_CLASS="GuestLDom" || __MACHINE_SUB_CLASS="PrimaryLDom" fi __MACHINE_PLATFORM="$( uname -i )" __MACHINE_SUBTYPE="" # if [ "${__ZONENAME}"x = ""x -o "${__ZONENAME}"x = "global"x ] ; then # [ -x /usr/platform/${__MACHINE_PLATFORM}/sbin/prtdiag ] && \ # ( set -- $( /usr/platform/${__MACHINE_PLATFORM}/sbin/prtdiag | grep "System Configuration" ) ; shift 5; echo $* ) 2>/dev/null | read __MACHINE_SUBTYPE # else # __MACHINE_SUBTYPE="" # fi __MACHINE_ARC="$( uname -p )" __RUNLEVEL=$( who -r 2>/dev/null | tr -s " " | cut -f8 -d " " ) ;; "AIX" ) __ZONENAME="" __MACHINE_PLATFORM="$( oslevel )" __OS_VERSION="$( oslevel -r )" __OS_RELEASE="$( uname -v )" __MACHINE_CLASS="$( uname -m )" __MACHINE_PLATFORM="$( uname -M )" __MACHINE_SUBTYPE="" __MACHINE_ARC="$( uname -p )" __RUNLEVEL=$( who -r 2>/dev/null | tr -s " " | cut -f8 -d " " ) ;; "Linux" ) __OS_FULLNAME="$( lsb_release -d -s 2>/dev/null )" [ "${__OS_FULLNAME}"x = ""x -a -r /etc/lsb-release ] && eval __OS_FULLNAME="$( grep DISTRIB_DESCRIPTION= /etc/lsb-release | cut -f2- -d "=" )" __ZONENAME="" __OS_VERSION="$( uname -r )" __OS_RELEASE="$( uname -v )" __MACHINE_CLASS="$( uname -m )" __MACHINE_PLATFORM="$( uname -i )" __MACHINE_SUBTYPE="" __MACHINE_ARC="$( uname -p )" __RUNLEVEL=$( who -r 2>/dev/null | tr -s " " | cut -f3 -d " " ) ;; CYGWIN* ) __OS_FULLNAME="$__OS" __OS="CYGWIN" __ZONENAME="" __OS_VERSION="$( uname -r )" __OS_RELEASE="$( uname -v )" __MACHINE_CLASS="$( uname -m )" __MACHINE_PLATFORM="$( uname -i )" __MACHINE_SUBTYPE="" __MACHINE_ARC="$( uname -p )" __RUNLEVEL=$( who -r 2>/dev/null ) ;; * ) __ZONENAME="" __MACHINE_PLATFORM="" __MACHINE_CLASS="" __MACHINE_PLATFORM="" __MACHINE_SUBTYPE="" __MACHINE_ARC="" __RUNLEVEL="?" ;; esac #### __START_DIR - working directory when starting the script #### __START_DIR="$( pwd )" #### __LOGFILE - fully qualified name of the logfile used #### use the parameter -l to change the logfile #### if [ -d /var/tmp ] ; then __DEF_LOGFILE="/var/tmp/${__SCRIPTNAME%.*}.LOG" else __DEF_LOGFILE="/tmp/${__SCRIPTNAME%.*}.LOG" fi __LOGFILE="${__DEF_LOGFILE}" #### LOGMSG_FUNCTION - function to write log messages #### default: use "echo " to write in log functions #### : ${LOGMSG_FUNCTION:=echo} # __GLOBAL_OUTPUT_REDIRECTION # status variable used by StartStop_LogAll_to_logfile # __GLOBAL_OUTPUT_REDIRECTION="" # lock file (used if ${__ONLY_ONCE} is ${__TRUE}) # Note: This is only a symbolic link # __LOCKFILE="/tmp/${__SCRIPTNAME}.lock" __LOCKFILE_CREATED=${__FALSE} #### __NO_OF_WARNINGS - Number of warnings found #### typeset -i __NO_OF_WARNINGS=0 #### __LIST_OF_WARNINGS - List of warning messages #### __LIST_OF_WARNINGS="" #### __NO_OF_ERRORS - Number of errors found #### typeset -i __NO_OF_ERRORS=0 #### __LIST_OF_ERRORS - List of error messages #### __LIST_OF_ERRORS="" #### __LOGON_USERID - ID of the user opening the session #### : ${__LOGIN_USERID:=${LOGNAME}} #### __USERID - ID of the user executing this script (e.g. xtrnaw7) #### : ${__USERID:=${LOGNAME}} # ----------------------------------------------------------------------------- # color variables #### Foreground Color variables: #### __COLOR_FG_BLACK, __COLOR_FG_RED, __COLOR_FG_GREEN, __COLOR_FG_YELLOW #### __COLOR_FG_BLUE, __COLOR_FG_MAGENTA, __COLOR_FG_CYAN, __COLOR_FG_WHITE #### #### Background Color variables: #### __COLOR_BG_BLACK, __COLOR_BG_RED, __COLOR_BG_GREEN, __COLOR_BG_YELLOW #### __COLOR_BG_BLUE, __COLOR_BG_MAGENTA, __COLOR_BG_CYAN, __COLOR_BG_WHITE #### if [ ${__USE_COLORS} = ${__TRUE} ] ; then __COLOR_FG_BLACK="\033[30m" __COLOR_FG_RED="\033[31m" __COLOR_FG_GREEN="\033[32m" __COLOR_FG_YELLOW="\033[33m" __COLOR_FG_BLUE="\033[34m" __COLOR_FG_MAGENTA="\033[35m" __COLOR_FG_CYAN="\033[36m" __COLOR_FG_WHITE="\033[37m" __COLOR_BG_BLACK="\033[40m" __COLOR_BG_RED="\033[41m" __COLOR_BG_GREEN="\033[42m" __COLOR_BG_YELLOW="\033[43m" __COLOR_BG_BLUE="\033[44m" __COLOR_BG_MAGENTA="\033[45m" __COLOR_BG_CYAN="\033[46m" __COLOR_BG_WHITE="\033[47m" #### #### Colorattributes: #### __COLOR_OFF, __COLOR_BOLD, __COLOR_NORMAL, - normal, __COLOR_UNDERLINE #### __COLOR_BLINK, __COLOR_REVERSE, __COLOR_INVISIBLE #### __COLOR_BOLD="\033[1m" __COLOR_NORMAL="\033[2m" __COLOR_UNDERLINE="\033[4m" __COLOR_BLINK="\033[5m" __COLOR_REVERSE="\033[7m" __COLOR_INVISIBLE="\033[8m" __COLOR_OFF="\033[0;m" fi # position cursor: ESC[row,colH or ESC[row;colf (1,1 = upper left corner) # Clear rest of line: ESC[K # Clear screen: ESC[2J # Save Cursor Pos ESC[s # Restore Cursor Pos ESC[u # Cursor Up # lines ESC{colsA # Cursor down # lines ESC{colsB # Cursor right # columns ESC{colsC # Cursor left # columns ESC{colsD # Get Cursor Pos ESC[6n # # ----------------------------------------------------------------------------- #### #### ##### defined sub routines #### #### -------------------------------------- #### ReadConfigFile #### #### read the config file #### #### usage: ReadConfigFile [configfile] #### #### where: configfile - name of the config file #### default: search ${__CONFIG_FILE} in the current directory, #### in the home directory, and in /etc (in this order) #### #### returns: ${__TRUE} - ok config read #### ${__FALSE} - error config file not found or not readable #### function ReadConfigFile { typeset __FUNCTION="ReadConfigFile"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset THIS_CONFIG="$1" typeset THISRC=${__FALSE} if [ "${THIS_CONFIG}"x = "none"x ] ; then LogInfo "The use of a config file is disabled." else if [ "${THIS_CONFIG}"x = ""x ] ; then THIS_CONFIG="$PWD/${__CONFIG_FILE}" [ ! -f "${THIS_CONFIG}" ] && THIS_CONFIG="${HOME}/${__CONFIG_FILE}" [ ! -f "${THIS_CONFIG}" ] && THIS_CONFIG="/etc/${__CONFIG_FILE}" fi if [ -f "${THIS_CONFIG}" ] ; then LogHeader "Reading the config file \"${THIS_CONFIG}\" ..." includeScript "${THIS_CONFIG}" __CONFIG_FILE_FOUND="${THIS_CONFIG}" THISRC=${__TRUE} else LogHeader "No config file (\"${__CONFIG_FILE}\") found (use -C to create a default config file)" fi fi return ${THISRC} } #### -------------------------------------- #### WriteConfigFile #### #### write the variable ${__CONFIG_PARAMETER} to the config file #### #### usage: WriteConfigFile [configfile] #### #### where: configfile - name of the config file #### default: write ${__CONFIG_FILE} in the current directory #### #### returns: ${__TRUE} - ok config file written #### ${__FALSE} - error writing the config file #### function WriteConfigFile { typeset __FUNCTION="WriteConfigFile" ; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset THIS_CONFIG_FILE="$1" typeset THISRC=${__FALSE} if [ "${THIS_CONFIG}"x = "none"x ] ; then LogInfo "The use of a config file is disabled." else [ "${THIS_CONFIG_FILE}"x = ""x ] && THIS_CONFIG_FILE="./${__CONFIG_FILE}" [ -f "${THIS_CONFIG_FILE}" ] && BackupFileIfNecessary "${THIS_CONFIG_FILE}" LogMsg "Writing the config file \"${THIS_CONFIG_FILE}\" ..." cat <"${THIS_CONFIG_FILE}" # config file for ${__SCRIPTNAME} ${__SCRIPT_VERSION}, created $( date ) ${__CONFIG_PARAMETER} EOT THISRC=$? fi return ${THISRC} } #### -------------------------------------- #### NoOfStackElements #### #### return the no. of stack elements #### #### usage: NoOfStackElements; var=$? #### #### returns: no. of elements on the stack #### #### Note: NoOfStackElements, FlushStack, push and pop use only one global stack! #### function NoOfStackElements { typeset __FUNCTION="NoOfStackElements"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} [ ${__STACK_POINTER} -gt 255 ] && die 234 "The return value is greater than 255 in function \"${__FUNCTION}\"" return ${__STACK_POINTER} } #### -------------------------------------- #### FlushStack #### #### flush the stack #### #### usage: FlushStack #### #### returns: no. of elements on the stack before flushing it #### #### Note: NoOfStackElements, FlushStack, push and pop use only one global stack! #### function FlushStack { typeset __FUNCTION="FlushStack"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset THISRC=${__STACK_POINTER} __STACK_POINTER=0 [ ${__STACK_POINTER} -gt 255 ] && die 234 "The return value is greater than 255 in function \"${__FUNCTION}\"" return ${THISRC} } #### -------------------------------------- #### push #### #### push one or more values on the stack #### #### usage: push value1 [...] [value#] #### #### returns: 0 #### #### Note: NoOfStackElements, FlushStack, push and pop use only one global stack! #### function push { typeset __FUNCTION="push"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} while [ $# -ne 0 ] ; do (( __STACK_POINTER=__STACK_POINTER+1 )) __STACK[${__STACK_POINTER}]="$1" shift done return 0 } #### -------------------------------------- #### pop #### #### pop one or more values from the stack #### #### usage: pop variable1 [...] [variable#] #### #### returns: 0 #### #### Note: NoOfStackElements, FlushStack, push and pop use only one global stack! #### function pop { typeset __FUNCTION="pop"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset NEWALUE="" while [ $# -ne 0 ] ; do if [ ${__STACK_POINTER} -eq 0 ] ; then NEWVALUE="" else NEWVALUE="${__STACK[${__STACK_POINTER}]}" (( __STACK_POINTER=__STACK_POINTER-1 )) fi eval $1="\"${NEWVALUE}\"" shift done return 0 } #### -------------------------------------- #### push_and_set #### #### push a variable to the stack and set the variable to a new value #### #### usage: push_and_set variable new_value #### #### returns: 0 #### #### Note: NoOfStackElements, FlushStack, push and pop use only one global stack! #### function push_and_set { typeset __FUNCTION="push_and_set"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} if [ $# -ne 0 ] ; then typeset VARNAME="$1" eval push \$${VARNAME} shift eval ${VARNAME}="\"$*\"" fi return 0 } #### -------------------------------------- #### CheckYNParameter #### #### check if a parameter is y, n, 0, or 1 #### #### usage: CheckYNParameter parameter #### #### returns: ${__TRUE} - the parameter is equal to yes #### ${__FALSE} - the parameter is equal to no #### function CheckYNParameter { typeset __FUNCTION="CheckYNParameter"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset THISRC=255 case $1 in "y" | "Y" | "yes" | "YES" | "true" | "TRUE" | 0 ) THISRC=${__TRUE} ;; "n" | "N" | "no" | "NO" | "false" | "FALSE" | 1 ) THISRC=${__FALSE} ;; * ) THISRC=255 ;; esac return ${THISRC} } #### -------------------------------------- #### ConvertToYesNo #### #### convert the value of a variable to y or n #### #### usage: ConvertToYesNo parameter #### #### returns: 0 #### prints y, n or ? to STDOUT #### function ConvertToYesNo { typeset __FUNCTION="ConvertToYesNo"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} case $1 in "y" | "Y" | "yes" | "YES" | "Yes" | "true" | "True" | "TRUE" | 0 ) echo "y" ;; "n" | "N" | "no" | "NO" | "No" | "false" | "False" | "FALSE" | 1 ) echo "n" ;; * ) echo "?" ;; esac return 0 } #### -------------------------------------- #### InvertSwitch #### #### invert a switch from true to false or vice versa #### #### usage: InvertSwitch variable #### #### returns 0 #### switch the variable "variable" from ${__TRUE} to #### ${__FALSE} or vice versa #### function InvertSwitch { typeset __FUNCTION="InvertSwitch"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} eval "[ \$$1 -eq ${__TRUE} ] && $1=${__FALSE} || $1=${__TRUE} " return 0 } #### -------------------------------------- #### CheckInputDevice #### #### check if the input device is a terminal #### #### usage: CheckInputDevice #### #### returns: 0 - the input device is a terminal (interactive) #### 1 - the input device is NOT a terminal #### function CheckInputDevice { typeset __FUNCTION="CheckInputDevice"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} tty -s return $? } #### -------------------------------------- #### GetProgramDirectory #### #### get the directory where a program resides #### #### usage: GetProgramDirectory [programpath/]programname [resultvar] #### #### returns: 0 #### the variable PRGDIR contains the directory with the program #### if the parameter resultvar is missing #### function GetProgramDirectory { typeset __FUNCTION="GetProgramDirectory"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset PRG="" typeset RESULTVAR=$2 if [ ! -L $1 ] ; then PRG=$( cd -P -- "$(dirname -- "$(command -v -- "$1")")" && pwd -P ) else # resolve links - $1 may be a softlink PRG="$1" while [ -h "$PRG" ] ; do ls=$(ls -ld "$PRG") link=$( expr "$ls" : '.*-> \(.*\)$' ) if expr "$link" : '.*/.*' > /dev/null; then PRG="$link" else PRG=$(dirname "$PRG")/"$link" fi done PRG="$(dirname ${PRG})" fi if [ "${RESULTVAR}"x != ""x ] ; then eval ${RESULTVAR}=\"${PRG}\" else PRGDIR="${PRG}" fi return 0 } #### -------------------------------------- #### substr #### #### get a substring of a string #### #### usage: variable=$( substr sourceStr pos length ) #### or substr sourceStr pos length resultVariable #### #### returns: 1 - parameter missing #### 0 - parameter okay #### function substr { typeset __FUNCTION="substr"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset resultstr="" typeset THISRC=1 if [ "$1"x != ""x ] ; then typeset s="$1" p="$2" l="$3" : ${l:=${#s}} : ${p:=1} resultstr="$( echo $s | cut -c${p}-$((${p}+${l}-1)) )" THISRC=0 else THISRC=1 resultstr="$1" fi if [ "$4"x != ""x ] ; then eval $4=\"${resultstr}\" else echo "${resultstr}" fi return ${THISRC} } #### -------------------------------------- #### replacestr #### #### replace a substring with another substring #### #### usage: variable=$( replacestr sourceStr oldsubStr newsubStr ) #### or replacestr sourceStr oldsubStr newsubStr resultVariable #### #### returns: 0 - substring replaced #### 1 - substring not found #### 3 - error, parameter missing #### #### writes the substr to STDOUT if resultvariable is missing #### function replacestr { typeset __FUNCTION="replacestr"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset THISRC=3 typeset sourcestring="$1" typeset oldsubStr="$2" typeset newsubStr="$3" if [ "${sourcestring}"x != ""x -a "${oldsubStr}"x != ""x ] ; then if [[ "${sourcestring}" == *${oldsubStr}* ]] ; then sourcestring="${sourcestring%%${oldsubStr}*}${newsubStr}${sourcestring#*${oldsubStr}}" THISRC=0 else THISRC=1 fi fi if [ "$4"x != ""x ] ; then eval $4=\"${sourcestring}\" else echo "${sourcestring}" fi return ${THISRC} } #### -------------------------------------- #### pos #### #### get the first position of a substring in a string #### #### usage: pos searchstring sourcestring #### #### returns: 0 - searchstring is not part of sourcestring #### else the position of searchstring in sourcestring #### function pos { typeset __FUNCTION="pos"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset searchstring="$1" typeset sourcestring="$2" typeset THISRC=0 if [[ "${sourcestring}" == *${searchstring}* ]] ; then typeset f="${sourcestring%%${searchstring}*}" THISRC=$(( ${#f}+1 )) fi [ ${THISRC} -gt 255 ] && die 234 "The return value is greater than 255 in function \"${__FUNCTION}\"" return ${THISRC} } #### -------------------------------------- #### lastpos #### #### get the last position of a substring in a string #### #### usage: lastpos searchstring sourcestring #### #### returns: 0 - searchstring is not part of sourcestring #### else the position of searchstring in sourcestring #### function lastpos { typeset __FUNCTION="lastpos"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset searchstring="$1" typeset sourcestring="$2" typeset THISRC=0 if [[ "${sourcestring}" == *${searchstring}* ]] ; then typeset f="${sourcestring%${searchstring}*}" THISRC=$(( ${#f}+1 )) fi [ ${THISRC} -gt 255 ] && die 234 "The return value is greater than 255 in function \"${__FUNCTION}\"" return ${THISRC} } #### -------------------------------------- #### isNumber #### #### check if a value is an integer #### #### usage: isNumber testValue #### #### returns: ${__TRUE} - testValue is a number else not #### function isNumber { typeset __FUNCTION="isNumber"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} # old code: # typeset TESTVAR="$(echo "$1" | sed 's/[0-9]*//g' )" # [ "${TESTVAR}"x = ""x ] && return ${__TRUE} || return ${__FALSE} [[ $1 == +([0-9]) ]] && return ${__TRUE} || return ${__FALSE} } #### -------------------------------------- #### ConvertToHex #### #### convert the value of a variable to a hex value #### #### usage: ConvertToHex value #### #### returns: 0 #### prints the value in hex to STDOUT #### function ConvertToHex { typeset __FUNCTION="ConvertToHex"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset -i16 HEXVAR HEXVAR="$1" echo ${HEXVAR##*#} return 0 } #### -------------------------------------- #### ConvertToOctal #### #### convert the value of a variable to a octal value #### #### usage: ConvertToOctal value #### #### returns: 0 #### prints the value in octal to STDOUT #### function ConvertToOctal { typeset __FUNCTION="ConvertToOctal"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset -i8 OCTVAR OCTVAR="$1" echo ${OCTVAR##*#} return 0 } #### -------------------------------------- #### ConvertToBinary #### #### convert the value of a variable to a binary value #### #### usage: ConvertToBinary value #### #### returns: 0 #### prints the value in binary to STDOUT #### function ConvertToBinary { typeset __FUNCTION="ConvertToBinary"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset -i2 BINVAR BINVAR="$1" echo ${BINVAR##*#} return 0 } #### -------------------------------------- #### toUppercase #### #### convert a string to uppercase #### #### usage: toUppercase sourceString | read resultVariable #### or targetString=$( toUppercase sourceString ) #### or toUppercase sourceString resultVariable #### #### returns: 0 #### writes the converted string to STDOUT if resultString is missing #### function toUppercase { typeset __FUNCTION="toUppercase"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset -u testvar="$1" if [ "$2"x != ""x ] ; then eval $2=\"${testvar}\" else echo "${testvar}" fi return 0 } #### -------------------------------------- #### toLowercase #### #### convert a string to lowercase #### #### usage: toLowercase sourceString | read resultVariable #### or targetString=$( toLowercase sourceString ) #### or toLowercase sourceString resultVariable #### #### returns: 0 #### writes the converted string to STDOUT if resultString is missing #### function toLowercase { typeset __FUNCTION="toLowercase"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset -l testvar="$1" if [ "$2"x != ""x ] ; then eval $2=\"${testvar}\" else echo "${testvar}" fi return 0 } #### -------------------------------------- #### StartStop_LogAll_to_logfile #### #### redirect STDOUT and STDERR into a file #### #### usage: StartStop_LogAll_to_logfile [start|stop] logfile #### #### returns: 0 - okay, redirection started / stopped #### 1 - error, can not write to the logfile #### 2 - invalid usage (to much or not enough parameter) #### 3 - invalid parameter #### 4 - tracing is enabled #### #### To explicitly write to STDOUT after calling this function with the #### parameter "start" use #### echo "This goes to STDOUT" >&3 #### #### To explicitly write to STDERR after calling this function with the #### parameter "start" use #### echo "This goes to STDERR" >&4 #### function StartStop_LogAll_to_logfile { typeset __FUNCTION="StartStop_LogAll_to_logfile"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset THISRC=0 if [ ${__ACTIVATE_TRACE} = ${__TRUE} ] ; then LogError "StartStop_LogAll_to_logfile can NOT be used if tracing is enabled (\"-D trace\")". return 4 fi if [ $# -ne 0 ] ; then case $1 in 'start' ) if [ $# -gt 1 ] ; then touch "$2" 2>/dev/null if [ $? -eq 0 ] ; then LogInfo "Logging STDOUT and STDERR to \"$2\" ... " exec 3>&1 exec 4>&2 if [ "${__OVERWRITE_MODE}" = "${__TRUE}" ] ; then exec 1>$2 2>&1 else exec 1>>$2 2>&1 fi __GLOBAL_OUTPUT_REDIRECTION="$2" else THISRC=1 fi else THISRC=2 fi ;; 'stop' ) if [ "${__GLOBAL_OUTPUT_REDIRECTION}"x != ""x ] ; then exec 2>&4 exec 1>&3 LogInfo "Stopping logging of STDOUT and STDERR to \"${__GLOBAL_OUTPUT_REDIRECTION}\"" __GLOBAL_OUTPUT_REDIRECTION="" fi ;; * ) THISRC=3 ;; esac else THISRC=2 fi return ${THISRC} } #### -------------------------------------- #### executeCommand #### #### execute a command #### #### usage: executeCommand command parameter #### #### returns: the RC of the executed command #### function executeCommand { typeset __FUNCTION="executeCommand"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset THISRC=0 __SYSCMDS="${__SYSCMDS} $@" set +e LogRuntimeInfo "Executing \"$@\" " eval "$@" THISRC=$? __SYSCMDS="${__SYSCMDS} # RC=${THISRC}" return ${THISRC} } #### -------------------------------------- #### executeCommandAndLog #### #### execute a command and write STDERR and STDOUT also to the logfile #### #### usage: executeCommandAndLog command parameter #### #### returns: the RC of the executed command (even if a logfile is used!) #### function executeCommandAndLog { typeset __FUNCTION="executeCommandAndLog"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} set +e typeset THISRC=0 __SYSCMDS="${__SYSCMDS} $@" LogRuntimeInfo "Executing \"$@\" " if [ "${__LOGFILE}"x != ""x -a -f "${__LOGFILE}" ] ; then # LogMsg "# "$* 1>&2 # The following trick is from # http://www.unix.com/unix-dummies-questions-answers/13018-exit-status-command-pipe-line.html#post47559 exec 5>&1 tee -a "${__LOGFILE}" >&5 |& exec >&p eval "$*" 2>&1 THISRC=$? exec >&- >&5 wait # alternative: # # THISRC=$( ( ( eval "$*" 2>&1; echo $? >&4 ) |tee "${__LOGFILE}" >&3 ) 4>&1 ) else eval "$@" THISRC=$? fi __SYSCMDS="${__SYSCMDS} # RC=${THISRC}" return ${THISRC} } #### -------------------------------------- #### executeCommandAndLogSTDERR #### #### execute a command and write STDERR also to the logfile #### #### usage: executeCommandAndLogSTDERR command parameter #### #### returns: the RC of the executed command #### function executeCommandAndLogSTDERR { typeset __FUNCTION="executeCommandAndLogSTDERR"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} set +e typeset THISRC=0 __SYSCMDS="${__SYSCMDS} $@" LogRuntimeInfo "Executing \"$@\" " if [ "${__LOGFILE}"x != ""x -a -f "${__LOGFILE}" ] ; then # The following trick is from # http://www.unix.com/unix-dummies-questions-answers/13018-exit-status-command-pipe-line.html#post47559 exec 5>&2 tee -a "${__LOGFILE}" >&5 |& exec 2>&p eval "$*" THISRC=$? exec 2>&5 wait else eval "$@" THISRC=$? fi __SYSCMDS="${__SYSCMDS} # RC=${THISRC}" return ${THISRC} } #### -------------------------------------- #### UserIsRoot #### #### validate the user id #### #### usage: UserIsRoot #### #### returns: ${__TRUE} - the user is root; else not #### function UserIsRoot { typeset __FUNCTION="UserIsRoot"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} [ "$( id | sed 's/uid=\([0-9]*\)(.*/\1/' )" = 0 ] && return ${__TRUE} || return ${__FALSE} } #### -------------------------------------- #### UserIs #### #### validate the user id #### #### usage: UserIs USERID #### #### where: USERID - userid (e.g oracle) #### #### returns: 0 - the user is this user #### 1 - the user is NOT this user #### 2 - the user does not exist on this machine #### 3 - missing parameter #### function UserIs { typeset __FUNCTION="UserIs"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset THISRC=3 typeset USERID="" if [ "$1"x != ""x ] ; then THISRC=2 USERID=$( grep "^$1:" /etc/passwd | cut -d: -f3 ) if [ "${USERID}"x != ""x ] ; then UID="$( id | sed 's/uid=\([0-9]*\)(.*/\1/' )" [ ${UID} = ${USERID} ] && THISRC=0 || THISRC=1 fi fi return ${THISRC} } #### -------------------------------------- #### GetCurrentUID #### #### get the UID of the current user #### #### usage: GetCurrentUID #### #### where: - #### #### returns: the function writes the UID to STDOUT #### function GetCurrentUID { typeset __FUNCTION="GetCurrentUID"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} echo "$(id | sed 's/uid=\([0-9]*\)(.*/\1/')" } #### -------------------------------------- #### GetUserName #### #### get the name of a user #### #### usage: GetUserName UID #### #### where: UID - userid (e.g 1686) #### #### returns: 0 #### __USERNAME contains the user name or "" if #### the userid does not exist on this machine #### function GetUserName { typeset __FUNCTION="GetUserName"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} [ "$1"x != ""x ] && __USERNAME=$( grep ":x:$1:" /etc/passwd | cut -d: -f1 ) || __USERNAME="" return 0 } #### -------------------------------------- #### GetUID #### #### get the UID for a username #### #### usage: GetUID username #### #### where: username - user name (e.g nobody) #### #### returns: 0 #### __USER_ID contains the UID or "" if #### the username does not exist on this machine #### function GetUID { typeset __FUNCTION="GetUID"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} [ "$1"x != ""x ] && __USER_ID=$( grep "^$1:" /etc/passwd | cut -d: -f3 ) || __USER_ID="" return 0 } # ====================================== #### -------------------------------------- #### PrintWithTimestamp #### #### print the output of a command to STDOUT with a timestamp #### #### usage: PrintWithTimestamp command_to_execute [parameter] #### #### returns: 0 #### #### Note: This function does not write to the log file! #### #### Source: in v2.x and newer #### http://unix.stackexchange.com/questions/26728/prepending-a-timestamp-to-each-line-of-output-from-a-command #### function PrintWithTimestamp { typeset COMMAND="$*" LogInfo "Executing \"${COMMAND}\" ..." ${COMMAND} | while IFS= read -r line; do printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$line"; done } #### -------------------------------------- #### LogMsg #### #### print a message to STDOUT and write it also to the logfile #### #### usage: LogMsg message #### #### returns: ${__TRUE} - message printed #### ${__FALSE} - message not printed #### #### Notes: Use "- message" to suppress the date stamp #### Use "-" to print a complete blank line #### function LogMsg { typeset __FUNCTION="LogMsg"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset THISRC=${__FALSE} if [ "$1"x = "-"x ] ; then shift typeset THISMSG="$*" elif [ "${__NO_TIME_STAMPS}"x = "${__TRUE}"x ] ; then typeset THISMSG="$*" else typeset THISMSG="[$(date +"%d.%m.%Y %H:%M:%S")] $*" fi if [ ${__QUIET_MODE} -ne ${__TRUE} ] ; then ${LOGMSG_FUNCTION} "${THISMSG} " THISRC=${__TRUE} fi [ "${__LOGFILE}"x != ""x ] && [ -f "${__LOGFILE}" ] && echo "${THISMSG}" >>"${__LOGFILE}" [ "${__DEBUG_LOGFILE}"x != ""x ] && [ -f "${__DEBUG_LOGFILE}" ] && echo "${THISMSG}" 2>/dev/null >>"${__DEBUG_LOGFILE}" return ${THISRC} } #### -------------------------------------- #### LogOnly #### #### write a message to the logfile #### #### usage: LogOnly message #### #### returns: ${__TRUE} - message printed #### ${__FALSE} - message not printed #### function LogOnly { typeset __FUNCTION="LogOnly"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset THISRC=${__FALSE} typeset THISMSG="[$(date +"%d.%m.%Y %H:%M:%S")] $*" if [ "${__LOGFILE}"x != ""x ] ; then if [ -f "${__LOGFILE}" ] ; then echo "${THISMSG}" >>"${__LOGFILE}" THISRC=${__TRUE} fi fi [ "${__DEBUG_LOGFILE}"x != ""x ] && [ -f "${__DEBUG_LOGFILE}" ] && echo "${THISMSG}" 2>/dev/null >>"${__DEBUG_LOGFILE}" return ${THISRC} } #### -------------------------------------- #### LogIfNotVerbose #### #### write a message to stdout and the logfile if we are not in verbose mode #### #### usage: LogIfNotVerbose message #### #### returns: ${__TRUE} - message printed #### ${__FALSE} - message not printed #### function LogIfNotVerbose { typeset __FUNCTION="LogIfNotVerbose"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset THISRC=${__FALSE} if [ "${__VERBOSE_LEVEL}"x = "0"x ] ; then LogMsg "$*" THISRC=$? fi return ${THISRC} } #### -------------------------------------- #### PrintDotToSTDOUT #### #### write a message to stdout only if we are not in verbose mode #### #### usage: PrintDotToSTDOUT [msg] #### #### default for msg is "." without a LF; use "\n" to print a LF #### #### returns: ${__TRUE} - message printed #### ${__FALSE} - message not printed #### function PrintDotToSTDOUT { typeset __FUNCTION="PrintDotToSTDOUT"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset THISRC=$? typeset THISMSG=".\c" [ $# -ne 0 ] && THISMSG="$*" if [ "${__VERBOSE_LEVEL}"x = "0"x ] ; then printf "${THISMSG}" THISRC=${__TRUE} fi return ${THISRC} } #### -------------------------------------- #### LogInfo #### #### print a message to STDOUT and write it also to the logfile #### only if in verbose mode #### #### usage: LogInfo [loglevel] message #### #### returns: ${__TRUE} - message printed #### ${__FALSE} - message not printed #### #### Notes: Output goes to STDERR, default loglevel is 0 #### function LogInfo { typeset __FUNCTION="LogInfo"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} # [ ${__VERBOSE_MODE} -eq ${__TRUE} ] && LogMsg "INFO: $*" typeset THIS_TIMESTAMP="[$(date +"%d.%m.%Y %H:%M:%S")] " typeset THISLEVEL=0 typeset THISRC=1 if [ $# -gt 1 ] ; then isNumber $1 if [ $? -eq ${__TRUE} ] ; then THISLEVEL=$1 shift fi fi if [ "${__VERBOSE_MODE}" = "${__TRUE}" ] ; then if [ ${__VERBOSE_LEVEL} -gt ${THISLEVEL} ] ; then LogMsg "${__INFO_PREFIX}$*" >&2 THISRC=$? fi fi [ ${THISRC} = 1 -a "${__DEBUG_LOGFILE}"x != ""x ] && echo "${THIS_TIMESTAMP}${__INFO_PREFIX}$*" 2>/dev/null >>"${__DEBUG_LOGFILE}" return ${THISRC} } # internal sub routine for info messages from the runtime system # # returns: ${__TRUE} - message printed # ${__FALSE} - message not printed # function LogRuntimeInfo { typeset __FUNCTION="LogRuntimeInfo"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset THISRC=${__FALSE} ( __INFO_PREFIX="${__RUNTIME_INFO_PREFIX}" LogInfo "${__RT_VERBOSE_LEVEL}" "$*" ) && THISRC=$? return ${THISRC} } # internal sub routine for header messages # # returns: ${__TRUE} - message printed # ${__FALSE} - message not printed # function LogHeader { typeset THISRC=${__FALSE} if [ "${__NO_HEADERS}"x != "${__TRUE}"x ] ; then LogMsg "$*" THISRC=${__TRUE} else [ "${__DEBUG_LOGFILE}"x != ""x ] && [ -f "${__DEBUG_LOGFILE}" ] && echo "$*" 2>/dev/null >>"${__DEBUG_LOGFILE}" fi return ${THISRC} } #### -------------------------------------- #### LogWarning #### #### print a warning to STDERR and write it also to the logfile #### #### usage: LogWarning message #### #### returns: ${__TRUE} - message printed #### ${__FALSE} - message not printed #### #### Notes: Output goes to STDERR #### function LogWarning { typeset __FUNCTION="LogWarning"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset THISRC=${__FALSE} LogMsg "${__WARNING_PREFIX}$*" >&2 THISRC=$? (( __NO_OF_WARNINGS = __NO_OF_WARNINGS +1 )) __LIST_OF_WARNINGS="${__LIST_OF_WARNINGS} ${__WARNING_PREFIX}$*" return ${THISRC} } #### -------------------------------------- #### LogError #### #### print an error message to STDERR and write it also to the logfile #### #### usage: LogError message #### #### returns: ${__TRUE} - message printed #### ${__FALSE} - message not printed #### #### Notes: Output goes to STDERR #### function LogError { typeset __FUNCTION="LogError"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset THISRC=$? if [ ${__ACTIVATE_TRACE} = ${__TRUE} ] ; then LogMsg "${__ERROR_PREFIX}$*" >&3 THISRC=$? else LogMsg "${__ERROR_PREFIX}$*" >&2 THISRC=$? fi (( __NO_OF_ERRORS=__NO_OF_ERRORS + 1 )) __LIST_OF_ERRORS="${__LIST_OF_ERRORS} ${__ERROR_PREFIX}$*" return ${THISRC} } #### --------------------------------------- #### BackupFileIfNecessary #### #### create a backup of a file if ${__OVERWRITE_MODE} is set to ${__FALSE} #### #### usage: BackupFileIfNecessary [file1} ... {filen} #### #### returns: 0 - done; else error #### function BackupFileIfNecessary { typeset __FUNCTION="BackupFileIfNecessary"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} : ${BACKUP_EXTENSION:=".$$"} typeset FILES_TO_BACKUP="$*" typeset CURFILE="" typeset CUR_BKP_FILE="" typeset THISRC=0 if [ ${__OVERWRITE_MODE} -eq ${__FALSE} ] ; then for CURFILE in ${FILES_TO_BACKUP} ; do [ ! -f "${CURFILE}" ] && continue CUR_BKP_FILE="${CURFILE}${BACKUP_EXTENSION}" LogMsg "Creating a backup of \"${CURFILE}\" in \"${CUR_BKP_FILE}\" ..." cp "${CURFILE}" "${CUR_BKP_FILE}" THISRC=$? if [ ${THISRC} -ne 0 ] ; then LogError "Error creating the backup of the file \"${CURFILE}\"" break fi done fi return ${THISRC} } #### --------------------------------------- #### CopyDirectory #### #### copy a directory #### #### usage: CopyDirectory sourcedir targetDir #### #### returns: 0 - done; #### else error #### function CopyDirectory { typeset __FUNCTION="CopyDirectory"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset THISRC=1 if [ "$1"x != ""x -a "$2"x != ""x ] ; then if [ -d "$1" -a -d "$2" ] ; then LogMsg "Copying all files from \"$1\" to \"$2\" ..." cd "$1" && find . -depth -print | cpio -pdumv "$2" THISRC=$? cd "${OLDPWD}" fi fi return ${THISRC} } #### -------------------------------------- #### DebugShell #### #### Open a simple debug shell #### #### Usage: DebugShell #### #### returns: ${__TRUE} #### #### Input is always read from /dev/tty; output always goes to /dev/tty #### function DebugShell { typeset THISRC=${__TRUE} typeset USER_INPUT="" while true ; do printf "\n ------------------------------------------------------------------------------- \n" printf "${__SCRIPTNAME} - debug shell - enter a command to execute (\"exit\" to leave the shell)\n" printf ">> " read USER_INPUT case "${USER_INPUT}" in "exit" ) break; ;; "functions" | "func" | "funcs" ) typeset -f | grep "\{$" ;; "" ) : ;; * ) eval ${USER_INPUT} ;; esac done /dev/tty "return" ${THISRC} } #### -------------------------------------- #### AskUser #### #### Ask the user (or use defaults depending on the parameter -n and -y) #### #### Usage: AskUser "message" #### #### returns: ${__TRUE} - user input is yes #### ${__FALSE} - user input is no #### USER_INPUT contains the user input #### #### Notes: "all" is interpreted as yes for this and all other questions #### "none" is interpreted as no for this and all other questions #### #### If __NOECHO is ${__TRUE} the user input is not written to STDOUT #### __NOECHO is set to ${__FALSE} again in this function #### #### If __USE_TTY is ${__TRUE} the prompt is written to /dev/tty and the #### user input is read from /dev/tty . This is useful if STDOUT is redirected #### to a file. #### function AskUser { typeset __FUNCTION="AskUser"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset THISRC="" if [ "${__USE_TTY}"x = "${__TRUE}"x ] ; then typeset mySTDIN=" /dev/null ) stty ${__STTY_SETTINGS} __STTY_SETTINGS="" trap 2 3 return 0 } #### -------------------------------------- #### RebootIfNecessary #### #### Check if a reboot is necessary #### #### Usage: RebootIfNecessary #### #### Notes #### The routine asks the user if neither the parameter -y nor the #### parameter -n is used #### Before using this routine uncomment the reboot command! #### function RebootIfNecessary { typeset __FUNCTION="RebootIfNecessary"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} if [ ${__REBOOT_REQUIRED} -eq 0 ] ; then LogMsg "The changes made to the system require a reboot" AskUser "Do you want to reboot now (y/n, default is NO)?" if [ $? -eq ${__TRUE} ] ; then LogMsg "Rebooting now ..." echo "???" reboot ${__REBOOT_PARAMETER} fi fi return 0 } #### --------------------------------------- #### die #### #### print a message and end the program #### #### usage: die returncode {message} #### #### returns: $1 (if it returns) #### #### Notes: #### #### This routine #### - calls cleanup #### - prints an error message if any (if returncode is not zero) #### or the message if any (if returncode is zero) #### - prints all warning messages again if ${__PRINT_LIST_OF_WARNING_MSGS} #### is ${__TRUE} #### - prints all error messages again if ${__PRINT_LIST_OF_ERROR_MSGS} #### is ${__TRUE} #### - prints a program end message and the program return code #### and #### - and ends the program or reboots the machine if requested #### #### If the variable ${__FORCE} is ${__TRUE} and the return code is NOT zero #### die() will only print the error message and return #### function die { typeset __FUNCTION="die"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} [ "${__TRAP_SIGNAL}"x != ""x ] && LogRuntimeInfo "__TRAP_SIGNAL is \"${__TRAP_SIGNAL}\"" typeset THISRC=$1 [ $# -ne 0 ] && shift if [ "$*"x != ""x ] ; then [ ${THISRC} = 0 ] && LogMsg "$*" || LogError "$*" fi [ ${__FORCE} = ${__TRUE} -a ${THISRC}x != 0x ] && return if [ "${__NO_CLEANUP}"x != ${__TRUE}x ] ; then cleanup else LogInfo "__NO_CLEANUP set -- skipping the cleanup at script end at all" fi if [ "${__NO_OF_WARNINGS}" != "0" -a ${__PRINT_LIST_OF_WARNINGS_MSGS} -eq ${__TRUE} ] ; then LogMsg "*** CAUTION: One or more WARNINGS found ***" LogMsg "*** please check the logfile ***" LogMsg "Summary of warnings: ${__LIST_OF_WARNINGS} " fi if [ "${__NO_OF_ERRORS}" != "0" -a ${__PRINT_LIST_OF_ERROR_MSGS} -eq ${__TRUE} ] ; then LogMsg "*** CAUTION: One or more ERRORS found ***" LogMsg "*** please check the logfile ***" LogMsg "Summary of error messages ${__LIST_OF_ERRORS} " fi [[ -n "${__LOGFILE}" ]] && LogHeader "The log file used was \"${__LOGFILE}\" " [[ ${__LOG_DEBUG_MESSAGES} = ${__TRUE} ]] && LogHeader "The debug messages are logged to \"${__DEBUG_LOGFILE}\" " [[ ${__ACTIVATE_TRACE} = ${__TRUE} ]] && LogHeader "The trace messages are logged to \"${__TRACE_LOGFILE}\" " # __QUIET_MODE=${__FALSE} __END_TIME="$( date )" LogHeader "${__SCRIPTNAME} ${__SCRIPT_VERSION} started at ${__START_TIME} and ended at ${__END_TIME}." LogHeader "The RC is ${THISRC}." __EXIT_VIA_DIE=${__TRUE} if [ "${__GLOBAL_OUTPUT_REDIRECTION}"x != ""x ] ; then StartStop_LogAll_to_logfile "stop" fi RemoveLockFile RebootIfNecessary exit ${THISRC} } #### --------------------------------------- #### includeScript #### #### include a script via . [scriptname] #### #### usage: includeScript [scriptname] #### #### returns: 0 #### #### notes: #### function includeScript { typeset __FUNCTION="includeScript"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} if [ $# -ne 0 ] ; then LogRuntimeInfo "Including the script \"$*\" ..." # set the variable for the TRAP handlers [ ! -f "$1" ] && die 247 "Include script \"$1\" not found" __INCLUDE_SCRIPT_RUNNING="$1" # include the script . $* # reset the variable for the TRAP handlers __INCLUDE_SCRIPT_RUNNING="" fi } #### --------------------------------------- #### executeFunctionIfDefined #### #### execute a function if it's defined #### #### usage: executeFunctionIfDefined [function_name] {function_parameter} #### #### returns: the RC of the function [function_name] or 255 if the function #### is not defined #### #### notes: #### function executeFunctionIfDefined { typeset __FUNCTION="executeFunctionIfDefined"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset THISRC=255 if [ $# -ne 0 ] ; then typeset THIS_FUNCTION="$1" shift LogRuntimeInfo "Searching the function \"${THIS_FUNCTION}\" ..." IsFunctionDefined "${THIS_FUNCTION}" if [ $? -eq ${__TRUE} ] ; then LogRuntimeInfo "The function \"${THIS_FUNCTION}\" is defined; now calling wit \"${THIS_FUNCTION} $@\" ..." ${THIS_FUNCTION} "$@" THISRC=$? fi fi return ${THISRC} } #### -------------------------------------- #### rand #### #### print a random number to STDOUT #### #### usage: rand #### #### returns: ${__TRUE} - random number printed to STDOUT #### ${__FALSE} - can not create a random number #### #### #### notes: #### #### This function prints the contents of the environment variable RANDOM #### to STDOUT. If that variable is not defined, it uses nawk to create #### a random number. If nawk is not available the function prints nothng to #### STDOUT #### function rand { typeset __THISRC=${__FALSE} if [ "${RANDOM}"x != ""x ] ; then echo ${RANDOM} __THISRC=${__TRUE} elif whence nawk >/dev/null ; then nawk 'BEGIN { srand(); printf "%d\n", (rand() * 10^8); }' __THISRC=${__TRUE} fi return ${__THISRC} } # ====================================== #### #### ##### defined internal sub routines (do NOT use; these routines are called #### by the runtime system!) #### # -------------------------------------- #### PrintLockFileErrorMsg # # Print the lockfile already exist error message to STDERR # # usage: PrintLockFileErrorMsg # # returns: 250 # function PrintLockFileErrorMsg { cat >&2 </dev/null LN_RC=$? else __INSIDE_CREATE_LOCKFILE=${__TRUE} # improved code from wpollock (see credits) if [ -L "${__LOCKFILE}" ] ; then LN_RC=1 else set -C # or: set -o noclobber : > "${__LOCKFILE}" 2>/dev/null LN_RC=$? fi __INSIDE_CREATE_LOCKFILE=${__FALSE} fi if [ ${LN_RC} = 0 ] ; then __LOCKFILE_CREATED=${__TRUE} return 0 else return 1 fi } # -------------------------------------- #### RemoveLockFile # # Remove the lock file if possible # # usage: RemoveLockFile # # returns: 0 - lock file removed # 1 - lock file does not exist # 2 - error removing the lock file # function RemoveLockFile { typeset __FUNCTION="RemoveLockFile"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} [ ! -L "${__LOCKFILE}" -a ! -f "${__LOCKFILE}" ] && return 1 if [ ${__LOCKFILE_CREATED} -eq ${__TRUE} ] ; then LogRuntimeInfo "Removing the lock semaphore ..." rm "${__LOCKFILE}" 1>/dev/null 2>/dev/null [ $? -eq 0 ] && return 0 fi return 2 } # ====================================== # -------------------------------------- #### CreateTemporaryFiles # # create the temporary files # # usage: CreateTemporaryFiles # # returns: 0 # # notes: # The variables with the tempfiles are called # __TEMPFILE1, __TEMPFILE2, ..., __TEMPFILE# # function CreateTemporaryFiles { typeset __FUNCTION="CreateTemporaryFiles"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset CURFILE= typeset i=1 # for compatibilty reasons the old code can still be activated if necessary typeset __USE_OLD_CODE=${__FALSE} __TEMPFILE_CREATED=${__TRUE} # save the current umask and set the temporary umask __ORIGINAL_UMASK=$( umask ) umask ${__TEMPFILE_UMASK} LogRuntimeInfo "Creating the temporary files ..." while [ ${i} -le ${__NO_OF_TEMPFILES} ] ; do if [ ${__USE_OLD_CODE} = ${__TRUE} ] ; then eval __TEMPFILE${i}="${__TEMPDIR}/${__SCRIPTNAME}.$$.TEMP${i}" eval CURFILE="\$__TEMPFILE${i}" LogRuntimeInfo "Creating the temporary file \"${CURFILE}\"; the variable is \"\${__TEMPFILE${i}}" echo >"${CURFILE}" || return $? else # improved code from wpollock (see credits) set -C # turn on noclobber shell option while : ; do eval __TEMPFILE${i}="${__TEMPDIR}/${__SCRIPTNAME}.$$.$( rand ).TEMP${i}" eval CURFILE="\$__TEMPFILE${i}" LogRuntimeInfo "Creating the temporary file \"${CURFILE}\"; the variable is \"\${__TEMPFILE${i}}" : > ${CURFILE} && break done fi eval __LIST_OF_TMP_FILES=\"${__LIST_OF_TMP_FILES} \${__TEMPFILE${i}}\" (( i = i +1 )) done # restore the umask umask ${__ORIGINAL_UMASK} __ORIGINAL_UMASK="" return 0 } # ====================================== # ====================================== #### #### --------------------------------------- #### cleanup #### #### house keeping at program end #### #### usage: [called by the runtime system] #### #### returns: 0 #### #### notes: #### execution order is #### - write executed commands to ${__SYSCMDS_FILE} if requested #### - call exit routines from ${__EXITROUTINES} #### - remove files from ${__LIST_OF_TMP_FILES} #### - umount mount points ${__LIST_OF_TMP_MOUNTS} #### - remove directories ${__LIST_OF_TMP_DIRS} #### - call finish routines from ${__FINISHROUTINES} #### function cleanup { typeset __FUNCTION="cleanup"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset EXIT_ROUTINE= typeset OLDPWD="$( pwd )" cd /tmp # write __SYSCMDS if [ "${__SYSCMDS_FILE}"x != ""x -a "${__SYSCMDS}"x != ""x ] ; then LogRuntimeInfo "Writing the list of executed commands to the file \"${__SYSCMDS_FILE}\" ..." echo "${__SYSCMDS}" >>"${__SYSCMDS_FILE}" fi # restore the umask if necessary if [ "${__ORIGINAL_UMASK}"x != ""x ] ; then umask ${__ORIGINAL_UMASK} __ORIGINAL_UMASK="" fi # reset tty settings if necessary if [ "${__STTY_SETTINGS}"x != ""x ] ; then stty ${__STTY_SETTINGS} __STTY_SETTINGS="" fi # call the defined exit routines if [ "${__NO_EXIT_ROUTINES}"x != "${__TRUE}"x ] ; then LogRuntimeInfo "Executing the exit routines \"${__EXITROUTINES}\" ..." if [ "${__EXITROUTINES}"x != ""x ] ; then for EXIT_ROUTINE in ${__EXITROUTINES} ; do typeset +f | grep "^${EXIT_ROUTINE}" >/dev/null if [ $? -eq 0 ] ; then LogRuntimeInfo "Now calling the exit routine \"${EXIT_ROUTINE}\" ..." eval ${EXIT_ROUTINE} else LogError "Exit routine \"${EXIT_ROUTINE}\" is NOT defined!" fi done fi else LogInfo "__NO_EXIT_ROUTINES is set -- skipping executing the exit routines" fi # remove temporary files if [ "${__NO_TEMPFILES_DELETE}"x != "${__TRUE}"x ] ; then LogRuntimeInfo "Removing temporary files ..." for CURENTRY in ${__LIST_OF_TMP_FILES} ; do LogRuntimeInfo "Removing the file \"${CURENTRY}\" ..." if [ -f "${CURENTRY}" ] ; then rm "${CURENTRY}" [ $? -ne 0 ] && LogWarning "Error removing the file \"${CURENTRY}\" " fi done else LogInfo "__NO_TEMPFILES_DELETE is set -- skipping removing temporary files" fi # remove temporary mounts if [ "${__NO_TEMPMOUNTS_UMOUNT}"x != "${__TRUE}"x ] ; then LogRuntimeInfo "Removing temporary mounts ..." typeset CURENTRY for CURENTRY in ${__LIST_OF_TMP_MOUNTS} ; do mount | grep "^${CURENTRY} " 1>/dev/null 2>/dev/null if [ $? -eq 0 ] ; then LogRuntimeInfo "Umounting \"${CURENTRY}\" ..." umount "${CURENTRY}" [ $? -ne 0 ] && LogWarning "Error umounting \"${CURENTRY}\" " fi done else LogInfo "__NO_TEMPMOUNTS_UMOUNT is set -- skipping umounting temporary mounts" fi # remove temporary directories if [ "${__NO_TEMPDIR_DELETE}"x != "${__TRUE}"x ] ; then LogRuntimeInfo "Removing temporary directories ..." for CURENTRY in ${__LIST_OF_TMP_DIRS} ; do LogRuntimeInfo "Removing the directory \"${CURENTRY}\" ..." if [ -d "${CURENTRY}" ] ; then rm -r "${CURENTRY}" 2>/dev/null [ $? -ne 0 ] && LogWarning "Error removing the directory \"${CURENTRY}\" " fi done else LogInfo "__NO_TEMPDIR_DELETE is set -- skipping removing temporary directories" fi # call the defined finish routines if [ "${__NO_FINISH_ROUTINES}"x != "${__TRUE}"x ] ; then LogRuntimeInfo "Executing the finish routines \"${__FINISHROUTINES}\" ..." if [ "${__FINISHROUTINES}"x != ""x ] ; then for FINISH_ROUTINE in ${__FINISHROUTINES} ; do typeset +f | grep "^${FINISH_ROUTINE}" >/dev/null if [ $? -eq 0 ] ; then LogRuntimeInfo "Now calling the finish routine \"${FINISH_ROUTINE}\" ..." eval ${FINISH_ROUTINE} else LogError "Finish routine \"${FINISH_ROUTINE}\" is NOT defined!" fi done fi else LogInfo "__NO_FINISH_ROUTINES is set -- skipping executing the finish routines" fi [ -d "${OLDPWD}" ] && cd "${OLDPWD}" return 0 } #### -------------------------------------- #### CreateDump #### #### save the current environment of the script #### #### usage: CreateDump [targetdir] [filename_add] #### #### returns: ${__TRUE} - ok, dump created (or dump was already created) #### ${__FALSE} - error creating the dump #### #### function CreateDump { typeset __FUNCTION="CreateDump"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} # typeset __FUNCTION="CreateDump"; ${__DEBUG_CODE} # init the return code typeset THISRC=${__FALSE} typeset __DUMPDIR=""${__DUMPDIR:=${DEFAULT_DUMP_DIR}}"" typeset TMPFILE="" typeset THISPARAM1="$1" typeset THISPARAM2="$2" if [ "${THISPARAM1}"x != ""x ] ; then __DUMPDIR="${THISPARAM1}" else if [ "${__DUMP_ALREADY_CREATED}"x = "${__TRUE}"x ] ; then LogRuntimeInfo "Dump of the current script environment already created." return ${__TRUE} fi __DUMP_ALREADY_CREATED=${__TRUE} [ -d "${__CREATE_DUMP}" ] && __DUMPDIR="${__CREATE_DUMP}" || LogWarning "Dumpdir \"${__CREATE_DUMP}\" is no existing directory, using ${__DUMPDIR}" fi if [ "${__DUMPDIR}"x != ""x ] ; then LogMsg "Saving the current script environment to \"${__DUMPDIR}\" ..." LogMsg "The PID used for the filenames is $$" TMPFILE="${__DUMPDIR}/${__SCRIPTNAME}.envvars.${THISPARAM2}$$" LogMsg "Saving the current environment variables in the file \"${TMPFILE}\" ..." echo "### ${TMPFILE} - environment variable dump created on $( date)" >"${TMPFILE}" set >>"${TMPFILE}" TMPFILE="${__DUMPDIR}/${__SCRIPTNAME}.exported_envvars.${THISPARAM2}$$" LogMsg "Saving the current exported environment variables in the file \"${TMPFILE}\" ..." echo "### ${TMPFILE} - exported environment variable dump created on $( date)" >"${TMPFILE}" env >>"${TMPFILE}" THISRC=${__TRUE} fi return ${THISRC} } #### #### ##### defined trap handler (you may change them) #### #### --------------------------------------- #### IsFunctiondefined #### #### check if a function is defined in this script #### #### usage: IsFunctionDefined name_of_the_function #### #### returns: ${__TRUE} - the function is defined #### ${__FALSE} - the function is not defined #### #### function IsFunctionDefined { typeset __FUNCTION="IsFunctionDefined"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset THISRC=${__FALSE} [ $# -eq 1 ] && typeset -f $1 >/dev/null && THISRC=${__TRUE} return ${THISRC} } #### --------------------------------------- #### GENERAL_SIGNAL_HANDLER #### #### general trap handler #### #### usage: called automatically; #### parameter: $1 = signal number #### $2 = LineNumber #### $3 = function name #### #### returns: - #### #### function GENERAL_SIGNAL_HANDLER { typeset __RC=$? __TRAP_SIGNAL=$1 __LINENO=$2 INTERRUPTED_FUNCTION=$3 LogRuntimeInfo "GENERAL_SIGNAL_HANDLER: TRAP \"${__TRAP_SIGNAL}\" occured in the function \"${INTERRUPTED_FUNCTION}\", Line No \"${__LINENO}\" " LogRuntimeInfo "__EXIT_VIA_DIE=\"${__EXIT_VIA_DIE}\" " LogRuntimeInfo "Parameter for the trap routine are: \"$*\"; the RC is $?" typeset __FUNCTION="GENERAL_SIGNAL_HANDLER"; ${__DEBUG_CODE} # get the name of a user defined trap routine typeset __USER_DEFINED_FUNCTION="" eval __USER_DEFINED_FUNCTION="\$__SIGNAL_${__TRAP_SIGNAL}_FUNCTION" if [ "${__EXIT_VIA_DIE}"x != "${__TRUE}"x -a ${__TRAP_SIGNAL} != "exit" ] ; then LogRuntimeInfo "Trap \"${__TRAP_SIGNAL}\" caught" [ "${__INCLUDE_SCRIPT_RUNNING}"x != ""x ] && LogMsg "Trap occurred inside of the include script \"${__INCLUDE_SCRIPT_RUNNING}\" " LogRuntimeInfo "Signal ${__TRAP_SIGNAL} received: Line: ${__LINENO} in function: ${INTERRUPTED_FUNCTION}" fi case ${__TRAP_SIGNAL} in 0 ) __TRAP_SIGNAL="EXIT" ;; 1 ) __TRAP_SIGNAL="SIGHUP" ;; 2 ) __TRAP_SIGNAL="SIGINT" ;; 3 ) __TRAP_SIGNAL="SIGQUIT" ;; 15 ) __TRAP_SIGNAL="SIGTERM" esac if [ "${__GENERAL_SIGNAL_FUNCTION}"x != ""x ] ; then LogRuntimeInfo "General user defined signal handler is declared: \"${__GENERAL_SIGNAL_FUNCTION}\" " IsFunctionDefined "${__GENERAL_SIGNAL_FUNCTION}" if [ $? -ne ${__TRUE} ] ; then LogRuntimeInfo "The general user defined signal handler is declared but not defined" else LogRuntimeInfo "Calling the general user defined signal handler now ..." ${__GENERAL_SIGNAL_FUNCTION} if [ $? -ne 0 ] ; then LogRuntimeInfo "General user defined signal handler \"${__GENERAL_SIGNAL_FUNCTION}\" ended with RC=$? -> not executing the other signal handler" return else LogRuntimeInfo "General user defined signal handler \"${__GENERAL_SIGNAL_FUNCTION}\" ended with RC=$? -> executing the other signal handler now" fi fi else LogRuntimeInfo "No general user defined signal handler defined." fi typeset __DEFAULT_ACTION_OK=${__TRUE} if [ "${__USER_DEFINED_FUNCTION}"x = ""x ] ; then LogRuntimeInfo "No user defined function for signal \"${__TRAP_SIGNAL}\" declared" else LogRuntimeInfo "The user defined function for signal \"${__TRAP_SIGNAL}\" is \"${__USER_DEFINED_FUNCTION}\"" IsFunctionDefined "${__USER_DEFINED_FUNCTION}" if [ $? -ne ${__TRUE} ] ; then LogRuntimeInfo "Function \"${__USER_DEFINED_FUNCTION}\" is declared but not defined " __USER_DEFINED_FUNCTION="" else LogRuntimeInfo "Executing the user defined function for signal \"${__TRAP_SIGNAL}\" \"${__USER_DEFINED_FUNCTION}\" ..." ${__USER_DEFINED_FUNCTION} __USER_DEFINED_FUNCTION_RC=$? LogRuntimeInfo "The return code of the user defined signal function is ${__USER_DEFINED_FUNCTION_RC}" if [ ${__USER_DEFINED_FUNCTION_RC} -ne 0 ] ; then LogRuntimeInfo " -->> Will not execute the default action for this signal" __DEFAULT_ACTION_OK=${__FALSE} fi fi fi if [ ${__DEFAULT_ACTION_OK} = ${__TRUE} ] ; then case ${__TRAP_SIGNAL} in 1 | "SIGHUP" ) LogWarning "SIGHUP signal received" InvertSwitch __VERBOSE_MODE LogMsg "Switching verbose mode to $( ConvertToYesNo ${__VERBOSE_MODE} )" ;; 2 | "SIGINT" ) if [ ${__USER_BREAK_ALLOWED} -eq ${__TRUE} ] ; then LogMsg "-" die 252 "Script aborted by the user via signal BREAK (CTRL-C)" else LogRuntimeInfo "Break signal (CTRL-C) received and ignored (Break is disabled)" fi ;; 3 | "SIGQUIT" ) die 251 "QUIT signal received" ;; 15 | "SIGTERM" ) die 253 "Script aborted by the external signal SIGTERM" ;; "SIGUSR1" ) (( __SIGUSR1_DUMP_NO = ${__SIGUSR1_DUMP_NO:=-1} +1 )) CreateDump "/var/tmp" "dump_no_${__SIGUSR1_DUMP_NO}_" ;; "SIGUSR2" ) CheckInputDevice if [ $? -eq 0 ] ; then printf "*** Entering interactive mode ***\n" while [ 0 = 0 ] ; do printf "Enter command to execute (exit to leave interactive mode): " printf "\n" read __USERINPUT [ "${__USERINPUT}"x = "exit"x ] && break eval ${__USERINPUT} done printf "*** Leaving interactive mode ***\n" else LogWarning "SIGUSR2: Input device is not a terminal" fi ;; "ERR" ) LogMsg "A command ended with an error; the RC is ${__RC}" ;; "exit" | "EXIT" | 0 ) if [ "${__INSIDE_CREATE_LOCKFILE}"x = "${__TRUE}"x ]; then PrintLockFileErrorMsg elif [ "${__EXIT_VIA_DIE}"x != "${__TRUE}"x ] ; then LogError "EXIT signal received; the RC is ${__RC}" [ "${__INCLUDE_SCRIPT_RUNNING}"x != ""x ] && LogMsg "exit occurred inside of the include script \"${__INCLUDE_SCRIPT_RUNNING}\" " RemoveLockFile if [ "${__CLEANUP_ON_ERROR}"x = "${__TRUE}"x ] ; then LogMsg "__CLEANUP_ON_ERROR set -- calling the function die anyway" die 236 "You should use the function \"die\" to end the program" else LogWarning "You should use the function \"die\" to end the program" fi [ "${__CREATE_DUMP}"x = ""x ] && __CREATE_DUMP="${__DUMPDIR:=${DEFAULT_DUMP_DIR}}" CreateDump else [ "${__CREATE_DUMP}"x != ""x ] && CreateDump fi ;; * ) die 254 "Unknown signal caught: ${__TRAP_SIGNAL}" ;; esac fi } # ====================================== #### --------------------------------------- #### InitScript #### #### init the script runtime #### #### usage: [called by the runtime system] #### #### returns: 0 #### function InitScript { typeset __FUNCTION="InitScript"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} # use a temporary log file until we know the real log file __TEMPFILE_CREATED=${__FALSE} __MAIN_LOGFILE=${__LOGFILE} __LOGFILE="/tmp/${__SCRIPTNAME}.$$.TEMP" echo >${__LOGFILE} if [ "${__DEBUG_LOGFILE}"x != ""x ] ; then echo 2>/dev/null >"${__DEBUG_LOGFILE}" fi __START_TIME="$( date )" LogHeader "${__SCRIPTNAME} ${__SCRIPT_VERSION} started at ${__START_TIME}." LogInfo "Script template used is \"${__SCRIPT_TEMPLATE_VERSION}\" ." __WRITE_CONFIG_AND_EXIT=${__FALSE} # init the variables eval "${__CONFIG_PARAMETER}" if [[ ! \ $*\ == *\ -C* ]] ; then # read the config file [ "${CONFIG_FILE}"x != ""x ] && LogInfo "User defined config file is \"${CONFIG_FILE}\" " ReadConfigFile ${CONFIG_FILE} fi return 0 } #### --------------------------------------- #### SetEnvironment #### #### set and check the environment #### #### usage: [called by the runtime system] #### #### returns: 0 #### function SetEnvironment { typeset __FUNCTION="SetEnvironment"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} # copy the temporary log file to the real log file if [ "${__NEW_LOGFILE}"x = "nul"x ] ; then LogHeader "Running without a log file" __MAIN_LOGFILE="" # delete the temporary logfile rm "${__LOGFILE}" 2>/dev/null __LOGFILE="" else [ "${__NEW_LOGFILE}"x != ""x ] && __MAIN_LOGFILE="${__NEW_LOGFILE}" LogRuntimeInfo "Initializing the log file\"${__MAIN_LOGFILE}\" " touch "${__MAIN_LOGFILE}" 2>/dev/null cat "${__LOGFILE}" >>"${__MAIN_LOGFILE}" 2>/dev/null if [ $? -ne 0 ] ; then LogWarning "Error writing to the logfile \"${__MAIN_LOGFILE}\"." LogWarning "Using the log file \"${__LOGFILE}\" " else rm "${__LOGFILE}" 2>/dev/null __LOGFILE="${__MAIN_LOGFILE}" fi LogHeader "Using the log file \"${__LOGFILE}\" " fi if [ "${__REQUIRED_OS}"x != ""x ] ; then pos " ${__OS} " " ${__REQUIRED_OS} " && \ die 238 "This script can not run on this operating system (${__OS}); known Operating systems are \"${__REQUIRED_OS}\"" fi if [ "${__REQUIRED_OS_VERSION}"x != ""x ] ; then LogRuntimeInfo "Current OS version is \"${__OS_VERSION}\"; required OS version is \"${__REQUIRED_OS_VERSION}\"" __OS_VERSION_OKAY=${__TRUE} __CUR_MAJOR_VER="${__OS_VERSION%.*}" __CUR_MINOR_VER="${__OS_VERSION#*.}" __REQ_MAJOR_VER="${__REQUIRED_OS_VERSION%.*}" __REQ_MINOR_VER="${__REQUIRED_OS_VERSION#*.}" [ "${__CUR_MAJOR_VER}" -lt "${__REQ_MAJOR_VER}" ] && __OS_VERSION_OKAY=${__FALSE} [ "${__CUR_MAJOR_VER}" -eq "${__REQ_MAJOR_VER}" -a "${__CUR_MINOR_VER}" -lt "${__REQ_MINOR_VER}" ] && __OS_VERSION_OKAY=${__FALSE} [ ${__OS_VERSION_OKAY} = ${__FALSE} ] && die 248 "Unsupported OS Version: ${__OS_VERSION}; necessary OS version is ${__REQUIRED_OS_VERSION}" fi if [ "${__REQUIRED_MACHINE_PLATFORM}"x != ""x ] ; then pos " ${__MACHINE_PLATFORM} " " ${__REQUIRED_MACHINE_PLATFORM} " && \ die 245 "This script can not run on this platform (${__MACHINE_PLATFORM}); necessary platforms are \"${__REQUIRED_MACHINE_PLATFORM}\"" fi if [ "${__REQUIRED_MACHINE_CLASS}"x != ""x ] ; then pos " ${__MACHINE_CLASS} " " ${__REQUIRED_MACHINE_CLASS} " && \ die 244 "This script can not run on this machine class (${__MACHINE_CLASS}); necessary machine classes are \"${__REQUIRED_MACHINE_CLASS}\"" fi if [ "${__REQUIRED_MACHINE_ARC}"x != ""x ] ; then pos " ${__MACHINE_ARC} " " ${__REQUIRED_MACHINE_ARC} " && \ die 243 "This script can not run on this machine architecture (${__MACHINE_ARC}); necessary machine architectures are \"${__REQUIRED_MACHINE_ARC}\"" fi if [ "${__ZONENAME}"x != ""x -a "${__OS}"x = "SunOS"x ] ; then case "${__REQUIRED_ZONES}" in "global" ) [ "${__ZONENAME}"x != "global"x ] && \ die 239 "This script must run in the global zone; the current zone is \"${__ZONENAME}\"" ;; "non-global" | "local" ) [ "${__ZONENAME}"x = "global"x ] && \ die 239 "This script can not run in the global zone" ;; "" ) : ;; * ) pos " ${__ZONENAME} " " ${__REQUIRED_ZONES} " && \ die 239 "This script must run in one of the zones \"${__REQUIRED_ZONES}\"; the current zone is \"${__ZONENAME}\" " ;; esac fi if [ ${__MUST_BE_ROOT} -eq ${__TRUE} ] ; then UserIsRoot || die 249 "You must be root to execute this script" fi if [ "${__REQUIRED_USERID}"x != ""x ] ; then pos " ${__USERID} " " ${__REQUIRED_USERID} " && \ die 242 "This script can only be executed by one of the users: ${__REQUIRED_USERID}" fi if [ ${__ONLY_ONCE} -eq ${__TRUE} ] ; then CreateLockFile if [ $? -ne 0 ] ; then PrintLockFileErrorMsg die 250 fi # remove the lock file at program end __EXITROUTINES="${__EXITROUTINES}" fi # __ABSOLUTE_SCRIPTDIR real absolute directory (no link) # GetProgramDirectory "${__SCRIPTDIR}/${__SCRIPTNAME}" __ABSOLUTE_SCRIPTDIR # create temporary files CreateTemporaryFiles # check for the parameter -C if [ "${__WRITE_CONFIG_AND_EXIT}" = ${__TRUE} ] ; then NEW_CONFIG_FILE="${__CONFIG_FILE}" LogMsg "Creating the config file \"${NEW_CONFIG_FILE}\" ..." WriteConfigFile "${NEW_CONFIG_FILE}" [ $? -ne 0 ] && die 246 "Error writing the config file \"${NEW_CONFIG_FILE}\"" die 0 "Configfile \"${NEW_CONFIG_FILE}\" successfully written." fi } #### #### ##### defined sub routines #### #### --------------------------------------- #### ShowShortUsage #### #### print the (short) usage help #### #### usage: ShowShortUsage #### #### returns: 0 #### function ShowShortUsage { typeset __FUNCTION="ShowShortUsage"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} eval "__SHORT_USAGE_HELP=\"${__SHORT_USAGE_HELP}\"" cat <&2 return 0 } # ----------------------------------------------------------------------------- #### -------------------------------------- #### SetHousekeeping #### #### do or do not house keeping (remove tmp files/directories; execute exit routines/finish routines) at script end #### #### usage: SetHousekeeping [${__TRUE}|${__FALSE}] #### #### parameter: ${__TRUE} | all - do house keeping #### ${__FALSE} | none - no house keeping #### nodelete - do all house keeping except removing temporary files and directories #### #### returns: 0 - okay #### 1 - invalid usage #### #### function SetHousekeeping { typeset __FUNCTION="SetHousekeeping"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset THISRC=0 case ${1} in ${__TRUE} | "all" ) LogRuntimeInfo "Switching cleanup at script end on" __NO_CLEANUP=${__FALSE} __NO_EXIT_ROUTINES=${__FALSE} __NO_TEMPFILES_DELETE=${__FALSE} __NO_TEMPMOUNTS_UMOUNT=${__FALSE} __NO_TEMPDIR_DELETE=${__FALSE} __NO_FINISH_ROUTINES=${__FALSE} ;; ${__FALSE} | "none" ) LogRuntimeInfo "Switching cleanup at script end off" __NO_CLEANUP=${__TRUE} __NO_EXIT_ROUTINES=${__TRUE} __NO_TEMPFILES_DELETE=${__TRUE} __NO_TEMPMOUNTS_UMOUNT=${__TRUE} __NO_TEMPDIR_DELETE=${__TRUE} __NO_FINISH_ROUTINES=${__TRUE} ;; "nodelete" ) LogRuntimeInfo "Switching cleanup at script end to do-not-delete-files" __NO_CLEANUP=${__FALSE} __NO_EXIT_ROUTINES=${__FALSE} __NO_TEMPFILES_DELETE=${__TRUE} __NO_TEMPMOUNTS_UMOUNT=${__FALSE} __NO_TEMPDIR_DELETE=${__TRUE} __NO_FINISH_ROUTINES=${__FALSE} ;; * ) LogError "Internal Error: SetHousekeeping called with an invalid parameter: \"${1}\" " THISRC=1 ;; esac return ${THISRC} } #### -------------------------------------- #### PrintRuntimeVariables #### #### print the values of the runtime variables #### #### usage: PrintRuntimeVariables #### #### returns: ${__TRUE} - ok #### ${__FALSE} - error #### else - invalid usage #### #### function PrintRuntimeVariables { typeset __FUNCTION="PrintRuntimeVariables"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} typeset CURVAR CURVALUE typeset __RUNTIME_VARIABLES=" __KSH_VERSION __SAVE_LANG __SCRIPTNAME __REAL_SCRIPTDIR __CONFIG_FILE __HOSTNAME __NODENAME __OS __OS_VERSION __ZONENAME __OS_RELEASE __MACHINE_CLASS __MACHINE_SUB_CLASS __START_DIR __MACHINE_PLATFORM __MACHINE_SUBTYPE __MACHINE_ARC __LOGFILE __LOGIN_USERID __USERID __RUNLEVEL " # init the return code THISRC=255 if [ $# -eq 0 ] ; then THISRC=${_TRUE} for CURVAR in ${__RUNTIME_VARIABLES} ; do eval CURVALUE="\$${CURVAR}" LogMsg "Variable \"${CURVAR}\" is \"${CURVALUE}\" " done fi return ${THISRC} } #### #### other subroutines that can be used in your code #### -------------------------------------- #### GetOtherDate #### #### get the date for today +/- n ( 1 <= n <= 6) #### #### usage: GetOtherDate [+|-]no_of_days [format] #### #### where #### +/-no_of_days - relative date (e.g -1, -2, etc) #### format - format for the date (def.: %Y-%m-%d) #### #### returns: writes the date to STDOUT #### #### notes: #### - = date in the future #### + = date in the past #### max. date difference : +/- 6 days #### #### This function was only tested successfull in Solaris! #### function GetOtherDate { typeset __FUNCTION="GetOtherDate"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} # typeset __FUNCTION="GetOtherDate"; ${__DEBUG_CODE} # init the return code typeset THISRC=${__FALSE} typeset FORMAT_STRING="%Y-%m-%d" if [ $# -ge 1 ] ; then [ "$2"x != ""x ] && FORMAT_STRING=$2 (( TIME_DIFF= $1 * 24 )) TZ=$TZ${TIME_DIFF} date "+${FORMAT_STRING}" THISRC=${__TRUE} fi return ${THISRC} } #### -------------------------------------- #### SaveEnvironmentVariables #### #### save selected environment variables to a file #### #### usage: SaveEnvironmentVariables filename [[pattern1]...[pattern#]] #### #### where: filename - name of the file for the environment variables #### pattern# - egrep pattern to select the environment variables to save #### #### returns: ${__TRUE} - ok #### ${__FALSE} - error #### #### Notes: #### To reuse the file later use the function includeScript #### function SaveEnvironmentVariables { typeset __FUNCTION="SaveEnvironmentVariables"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} # typeset __FUNCTION="SaveEnvironmentVariables"; ${__DEBUG_CODE} # init the return code THISRC=${__FALSE} if [ $# -ne 0 ] ; then typeset THIS_FILE="$1" LogMsg "Writing the selected environment variables to \"${THIS_FILE}\" ..." shift BackupFileIfNecessary "${THIS_FILE}" touch "${THIS_FILE}" 2>/dev/null if [ $? -ne 0 ] ; then LogError "SaveEnvironmentVariables: Error $? writing to the file \"${THIS_FILE}\" " else typeset OUTPUT="" typeset NEW_OUTPUT="" if [ $# -eq 0 ] ; then OUTPUT="$( set )" else for i in $* ; do CUR_PATTERN="$i" LogRuntimeInfo "Processing the pattern \"$i\" ..." NEW_OUTPUT="$( set | egrep "$i" )" LogRuntimeInfo " The result of this pattern is: ${NEW_OUTPUT} " OUTPUT="${OUTPUT} ${NEW_OUTPUT}" done fi LogRuntimeInfo "Writing the file \"${THIS_FILE}\" ..." echo "${OUTPUT}" | sort | uniq | grep -v "^$" >"${THIS_FILE}" if [ $? -ne 0 ] ; then LogError "SaveEnvironmentVariables: Error $? writing to the file \"${THIS_FILE}\" " else THISRC=${__TRUE} fi fi fi return ${THISRC} } #### -------------------------------------- #### PrintLine #### #### print a line with n times the character c #### #### usage: PrintLine [n] {c} #### #### returns: ${__TRUE} - ok #### ${__FALSE} - error #### #### function PrintLine { typeset __FUNCTION="PrintLine"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} # init the return code typeset THISRC=${__FALSE} if [ $# -ge 1 ] ; then typeset n=$1 typeset c=$2 typeset c=${c:=-} eval printf \'%0.1s\' "$c"\{1..$n\} typeset THISRC=${__TRUE} fi return ${THISRC} } # ----------------------------------------------------------------------------- # functions: # #### -------------------------------------- #### CalculateSeconds #### #### convert a string like nnX where #### X is s for seconds, m for minutes, and h for hours #### to the approbiate number of seconds #### #### usage: CalculateSeconds timeValue [resultVar] #### #### returns: ${__TRUE} - ok, if the parameter resultVar is found #### resultVar contains the number of seconds else the #### number of seconds is written to STDOUT. #### ${__FALSE} - error, invalid format #### #### function CalculateSeconds { typeset __FUNCTION="CalculateSeconds"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} # init the return code typeset THISRC=${__TRUE} typeset TIME_VALUE="$1" typeset RESULT_VAR="$2" typeset TIME_CHAR="$( echo ${TIME_VALUE} | cut -c${#TIME_VALUE} )" typeset TIME_IN_SECONDS="" case ${TIME_CHAR} in "h" | "H" ) (( TIME_IN_SECONDS = ${TIME_VALUE%${TIME_CHAR}} * 60 * 60 )) ;; "m" | "M" ) (( TIME_IN_SECONDS = ${TIME_VALUE%${TIME_CHAR}} * 60 )) ;; "s" | "S") (( TIME_IN_SECONDS = ${TIME_VALUE%${TIME_CHAR}} )) ;; "1" | "2"| "3"| "4"| "5"| "6"| "7"| "8"| "9"| "0" ) TIME_IN_SECONDS=${TIME_VALUE} ;; * ) TIME_IN_SECONDS="" THISRC=${__FALSE} ;; esac if [ ${THISRC} = ${__TRUE} ] ; then if [ "${RESULT_VAR}"x != ""x ] ; then eval ${RESULT_VAR}="${TIME_IN_SECONDS}" else echo "${TIME_IN_SECONDS}" fi fi return ${THISRC} } #### -------------------------------------- #### check_SSH_agent_status #### #### check if the ssh agent is running #### #### usage: check_SSH_agent_statuscheck_SSH_agent_status #### #### returns: ${__TRUE} - ssh agent is running, SSH_AGENT_RUNNING is ${__TRUE} #### ${__FALSE} - ssh agent is not running, SSH_AGENT_RUNNING is ${__FALSE} #### #### function check_SSH_agent_status { typeset __FUNCTION="check_SSH_agent_status"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} SSH_AGENT_RUNNING=${__FALSE} if [ "${SSH_AUTH_SOCK}"x != ""x ] ; then [ -S "${SSH_AUTH_SOCK}" ] && SSH_AGENT_RUNNING=${__TRUE} fi return ${SSH_AGENT_RUNNING} } #### -------------------------------------- #### GetNumberOfRunningProcesses #### #### get the number of still running processes #### #### usage: GetNumberOfRunningProcesses {list_of_pids} #### #### returns: writes the number of still running processes to STDOUT #### #### function GetNumberOfRunningProcesses { typeset __FUNCTION="GetNumberOfRunningProcesses"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} # init the return code typeset THISRC=${__FALSE} typeset BACKGROUND_PIDS=$* typeset NO_OF_RUNNING_PIDS=0 if [ "${BACKGROUND_PIDS}"x != ""x ] ; then if [[ "${__OS}"x == CYGWIN* ]] ; then typeset i NO_OF_RUNNING_PIDS=0 for i in ${BACKGROUND_PIDS} ; do ps -p $i >/dev/null && (( NO_OF_RUNNING_PIDS = NO_OF_RUNNING_PIDS + 1 )) done else set -- $( ps -o pid= -p "${BACKGROUND_PIDS}" ) NO_OF_RUNNING_PIDS=$# fi THISRC=${__TRUE} fi echo ${NO_OF_RUNNING_PIDS} return ${THISRC} } #### -------------------------------------- #### get_curhost_interace #### #### get the admin interface for a host #### #### usage: get_curhost_interace hostid #### #### returns: CUR_HOST_INTERFACE contains the ip address of the admin interface #### or the hostid if no admin interface was found #### #### function get_curhost_interace { typeset __FUNCTION="get_curhost_interace"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} # typeset __FUNCTION="get_curhost_interace"; ${__DEBUG_CODE} # init the return code THISRC=${__FALSE} typeset TEMPVAR="" typeset CURHOSTID="$1" CUR_HOST_INTERFACE="${CURHOSTID}" if [ $# -eq 1 ] ; then if [ ${RCM_SUPPORT} = ${__FALSE} ] ; then THISRC=${__TRUE} else LogInfo "Retrieving the admin interface for \"${CURHOSTID}\" from the RCM ..." TEMPVAR=$( ${COPY_TABLE_BINARY} ${COPY_TABLE_PARAMETER} -t RCM.HOST_IF_PURPOSE -q "HOSTID=\"${CURHOSTID}\" AND purpose=\"Admin access\" " | grep hostname | cut -f2 -d '"' ) if [ "${TEMPVAR}"x != ""x ] ; then LogInfo "The admin interface for \"${CURHOSTID}\" is \"${TEMPVAR}\" " CUR_HOST_INTERFACE=${TEMPVAR} THISRC=${__TRUE} else LogWarning "No admin interface for \"${CURHOSTID}\" configured in the RCM" fi fi fi return ${THISRC} } #### -------------------------------------- #### mycleanup #### #### Housekeeping: #### write the summaries #### cleanup the temporary #### kill still running background processes #### #### usage: mycleanup #### #### returns: nothing #### function mycleanup { typeset __FUNCTION="mycleanup"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} if [ "${PROCESSING_STARTED}"x = "${__TRUE}"x ] ; then typeset STILL_RUNNING_PIDS="" typeset KEEP_LOGFILES=${__FALSE} typeset CLEANUP_OUTPUT="" typeset CUR_PID LogMsg "" if [ ${UNIQUE_LOGFILES} = ${__FALSE} ] ; then LogMsg "The output of the commands is logged in the file" LogMsg " ${OUTPUTFILE}" else LogMsg "The output of the commands is logged in the files" LogMsg " ${OUTPUTFILE}." fi LogMsg "" if [ "${INVALID_HOSTS_LIST}"x != ""x ] ; then LogMsg "The following hosts could NOT be processed due to an error:" for CURHOST in ${INVALID_HOSTS_LIST} ; do LogMsg " ${CURHOST}" done fi LogMsg "" # kill still running background processes for CUR_PID in ${BACKGROUND_PIDS} ; do CUR_OUTPUT="$( ps -fp ${CUR_PID} )" if [ $? -eq 0 ] ; then LogMsg "Process ${CUR_PID} is still running: " LogMsg "${CUR_OUTPUT}" LogMsg "Killing the process ${CUR_PID} now ..." kill ${CUR_PID} fi done for CUR_PID in ${BACKGROUND_PIDS} ; do CUR_OUTPUT="$( ps -fp ${CUR_PID} )" if [ $? -eq 0 ] ; then LogMsg "Process ${CUR_PID} is still running: " LogMsg "${CUR_OUTPUT}" LogMsg "Killing the process ${CUR_PID} now with -9 ..." kill ${CUR_PID} fi done for CUR_PID in ${BACKGROUND_PIDS} ; do ps -p ${CUR_PID} >/dev/null && STILL_RUNNING_PIDS="${STILL_RUNNING_PIDS} ${CUR_PID}" done if [ "${STILL_RUNNING_PIDS}"x != ""x ] ; then LogError "There are still running background processes (kill -9 did not work): ${STILL_RUNNING_PIDS}" ps -p ${STILL_RUNNING_PIDS} KEEP_LOGFILES=${__TRUE} fi if [ "${TMP_OUTPUT_DIR}"x != ""x ] ; then if [ -d "${TMP_OUTPUT_DIR}" ] ; then if [ "${__TRAP_SIGNAL}"x != ""x -o "${KEEP_LOGFILES}" = "${__TRUE}" ] ; then LogWarning "Script ended with an error -- will not remove the temporary directory \"${TMP_OUTPUT_DIR}\"!" else __LIST_OF_TMP_DIRS="${__LIST_OF_TMP_DIRS} ${TMP_OUTPUT_DIR}" fi fi fi fi } #### -------------------------------------- #### USER_SIGNAL_HANDLER #### #### template for a user defined trap handler #### #### usage: #### to define one signal handler for all signals do: #### #### __GENERAL_SIGNAL_FUNCTION=USER_SIGNAL_HANDLER #### #### to define unique signal handler for the various signals do: #### #### __SIGNAL__FUNCTION="USER_SIGNAL_HANDLER" #### #### e.g.: #### #### __SIGNAL_SIGUSR1_FUNCTION=USER_SIGNAL_HANDLER #### __SIGNAL_SIGUSR2_FUNCTION=USER_SIGNAL_HANDLER #### __SIGNAL_SIGHUP_FUNCTION=USER_SIGNAL_HANDLER #### __SIGNAL_SIGINT_FUNCTION=USER_SIGNAL_HANDLER #### __SIGNAL_SIGQUIT_FUNCTION=USER_SIGNAL_HANDLER #### __SIGNAL_SIGTERM_FUNCTION=USER_SIGNAL_HANDLER #### #### returns: 0 - execute the next action for this signal #### else - do not execute the next action for this signal #### #### Notes: #### Depending on the return code of the signal handler the other #### signal handler are called (RC=0) or not (RC<>0) #### #### The call order is #### - general user defined signal handler (if defined) #### - signal specific user defined signal handler (if defined) #### - default specific signal handler #### function USER_SIGNAL_HANDLER { typeset THISRC=0 LogMsg "***" LogMsg "User defined signal handler called" LogMsg "" LogMsg "Trap signal is \"${__TRAP_SIGNAL}\" " LogMsg "Interrupted function: \"${INTERRUPTED_FUNCTION}\", Line No: \"${__LINENO}\" " LogMsg "***" return ${THISRC} } #### -------------------------------------- #### host_on_the_exclude_list #### #### check if a host is on the host exclude list #### #### usage: YourRoutine #### #### returns: ${__TRUE} - yes #### ${__FALSE} - no #### #### function host_on_the_exclude_list { typeset __FUNCTION="host_on_the_exclude_list"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} # parameter typeset CUR_HOST="$1" # local variables # typeset HOST_EXCLUDE_MASK="" # init the return code typeset THISRC=${__FALSE} if [ "$1"x != ""x ] ; then for HOST_EXCLUDE_MASK in ${EXCLUDE_HOSTS} ; do if [[ ${CUR_HOST} == ${HOST_EXCLUDE_MASK} ]] ; then HOSTS_EXCLUDED="${HOSTS_EXCLUDED} ${CUR_HOST}" THISRC=${__TRUE} break fi done fi return ${THISRC} } #### template for a new user function #### #### -------------------------------------- #### YourRoutine #### #### template for a user defined function #### #### usage: YourRoutine #### #### returns: ${__TRUE} - ok #### ${__FALSE} - error #### #### function YourRoutine { typeset __FUNCTION="YourRoutine"; ${__FUNCTION_INIT} ; ${__DEBUG_CODE} # init the return code typeset THISRC=${__FALSE} # add code here [ ${THISRC} -gt 255 ] && die 234 "The return value is greater than 255 in function \"${__FUNCTION}\"" return ${THISRC} } # ----------------------------------------------------------------------------- # main: # # trace main routine # if [ 1 = 0 ] ; then set -x PS4='LineNo: $LINENO (sec: $SECONDS): >> ' fi # Note: This statement seems to be necessary to use ${LINENO} in the trap statement # LINENO=${LINENO} # install trap handler __settraps trap 'GENERAL_SIGNAL_HANDLER EXIT ${LINENO} ${__FUNCTION}' exit # trace also all function defined before this line (!) # # typeset -ft $( typeset +f ) InitScript $* # init variables with the defaults # # format var=${DEFAULT_var} # # to process all variables beginning with DEFAULT_ use # for CURVAR in $( set | grep "^DEFAULT_" | cut -f1 -d"=" ) ; do P1="${CURVAR%%=*}" P2="${P1#DEFAULT_*}" # for debugging (no parameter are processed until now) # if [ 1 = 0 ] ; then push_and_set __VERBOSE_MODE ${__TRUE} push_and_set __VERBOSE_LEVEL ${__RT_VERBOSE_LEVEL} LogInfo 0 "Setting variable $P2 to \"$( eval "echo \"\$$P1\"")\" " pop __VERBOSE_MODE pop __VERBOSE_LEVEL fi eval "$P2="\"\$$P1\""" done # --- variables for the cleanup routine: # # add mounts that should be automatically be unmounted at script end to this variable # # __LIST_OF_TMP_MOUNTS="${__LIST_OF_TMP_MOUNTS} " # add directories that should be automatically removed at script end to this variable # # __LIST_OF_TMP_DIRS="${__LIST_OF_TMP_DIRS} " # add files that should be automatically removed at script end to this variable # __LIST_OF_TMP_FILES="${__LIST_OF_TMP_FILES} " # add functions that should be called automatically at program end # before removing temporary files, directories, and mounts # to this variable # # __EXITROUTINES="${__EXITROUTINES} " BACKGROUND_PIDS="" __EXITROUTINES="${__EXITROUTINES} mycleanup" # add functions that should be called automatically at program end # after removing temporary files, directories, and mounts # to this variable # # __FINISHROUTINES="${__FINISHROUTINES} " check_SSH_agent_status && SSH_AGENT_STATUS="running" || SSH_AGENT_STATUS="not running" # variables used by getopts: # OPTIND = index of the current argument # OPTARG = current function character # THIS_PARAMETER="$*" INVALID_PARAMETER_FOUND=${__FALSE} __PRINT_USAGE=${__FALSE} CUR_SWITCH="" OPTARG="" set -o noglob # [ "${__OS}"x = "Linux" ] && GETOPT_COMPATIBLE="0" __GETOPTS="+:ynvqhHD:fl:aOS:CVTXi:o:s:u:c:kUI:p:P:KRb:BdW:w:x:A:" if [ "${__OS}"x = "SunOS"x -a "${__SHELL}"x = "ksh"x ] ; then if [ "${__OS_VERSION}"x = "5.10"x -o "${__OS_VERSION}"x = "5.11"x ] ; then __GETOPTS="+:y(yes)n(no)v(verbose)q(quiet)h(help)H(doc)D:(debug)f(force)l:(logfile)\ a(color)O(overwrite)S:(summaries)C(writeconfigfile)V(version)T(tee)X(view_examples)\ i:(hostlist)o:(outputfile)s:(scriptfile)u:(sshuser)c:(shell)k(nocomments)U(uniquelogfiles)\ I:(basedir)p:(scpoptions)P:(sshoptions)K(nostrictkeys)R(rcm)b:(ssh_keyfile)B(do_not_copy)\ d(parallel)W:(timeout)w:(noOfbackgroundProcesses)x:(excludehost)A:(includehost)" fi fi while getopts ${__GETOPTS} CUR_SWITCH ; do # for debugging only # # ----------------------------------------------------------------------------- # Debug Hint # # Use # # __PRINT_ARGUMENTS=0 [scriptname] # # to debug the parameter handling # # ----------------------------------------------------------------------------- if [ "${__PRINT_ARGUMENTS}" = "${__TRUE}" ] ; then LogMsg "CUR_SWITCH is $CUR_SWITCH" LogMsg "OPTIND = $OPTIND" LogMsg "OPTARG = $OPTARG" LogMsg "\$* is \"$*\" " fi if [ "${CUR_SWITCH}" = ":" ] ; then CUR_SWITCH=${OPTARG} OPTARG="" fi case ${CUR_SWITCH} in "C" ) __WRITE_CONFIG_AND_EXIT=${__TRUE} ;; "D" ) __DEBUG_SWITCHES="${__DEBUG_SWITCHES} ${OPTARG}" ;; "+D" ) [ "${OPTARG}"x != "none"x ] && DEBUG_SWITCHES="${OPTARG}" || DEBUG_SWITCHES="" ;; "+v" ) __VERBOSE_MODE=${__FALSE} ;; "v" ) __VERBOSE_MODE=${__TRUE} ; (( __VERBOSE_LEVEL=__VERBOSE_LEVEL+1 )) ;; "+q" ) __QUIET_MODE=${__FALSE} ;; "q" ) __QUIET_MODE=${__TRUE} ;; "+a" ) __USE_COLORS=${__FALSE} ;; "a" ) __USE_COLORS=${__TRUE} ;; "+O" ) __OVERWRITE_MODE=${__FALSE} ;; "O" ) __OVERWRITE_MODE=${__TRUE} ;; "f" ) __FORCE=${__TRUE} ;; "+f" ) __FORCE=${__FALSE} ;; "l" ) __NEW_LOGFILE="${OPTARG:=nul}" [ "$( substr ${__NEW_LOGFILE} 1 1 )"x != "/"x ] && __NEW_LOGFILE="$PWD/${__NEW_LOGFILE}" ;; "+l" ) __NEW_LOGFILE="nul" ;; "+h" ) __VERBOSE_MODE=${__TRUE} __PRINT_USAGE=${__TRUE} ;; "h" ) __PRINT_USAGE=${__TRUE} ;; "T" ) : # parameter already processed ;; "H" ) echo " -----------------------------------------------------------------------------------------------------" >&2 echo " ${__SCRIPTNAME} ${__SCRIPT_VERSION} (Scripttemplate: ${__SCRIPT_TEMPLATE_VERSION}) ">&2 echo " Documentation" >&2 echo " -----------------------------------------------------------------------------------------------------" >&2 grep "^##" "$0" | grep -v "##EXAMPLE##" | cut -c5- 1>&2 die 0 ;; "X" ) echo " -----------------------------------------------------------------------------------------------------" >&2 echo " ${__SCRIPTNAME} ${__SCRIPT_VERSION} ">&2 echo " Documentation" - Examples>&2 echo " -----------------------------------------------------------------------------------------------------" >&2 T=$( grep "^##EXAMPLE##" "$0" | cut -c12- ) eval T1="\"$T\"" echo "$T1" 1>&2 die 0 ;; "V" ) LogMsg "Script version: ${__SCRIPT_VERSION}" if [ ${__VERBOSE_MODE} = ${__TRUE} ] ; then LogMsg "Script template version: ${__SCRIPT_TEMPLATE_VERSION}" if [ "${__CONFIG_FILE_FOUND}"x != ""x ] ; then LogMsg "Script config file: \"${__CONFIG_FILE_FOUND}\"" LogMsg "Script config file version : ${__CONFIG_FILE_VERSION}" fi fi die 0 ;; "+y" ) __USER_RESPONSE_IS="" ;; "y" ) __USER_RESPONSE_IS="y" ;; "+n" ) __USER_RESPONSE_IS="" ;; "n" ) __USER_RESPONSE_IS="n" ;; "S" ) case ${OPTARG} in 0 | 1 | 2 | 3 ) __PRINT_SUMMARIES=${OPTARG} ;; * ) LogError "Unknown value for -S found: \"${OPTARG}\"" INVALID_PARAMETER_FOUND=${__TRUE} ;; esac ;; "K" ) NOSTRICTKEYS=${__TRUE} ;; "+K" ) NOSTRICTKEYS=${__FALSE} ;; "R" ) RCM_SUPPORT=${__TRUE} ;; "+R" ) RCM_SUPPORT=${__FALSE} ;; "i" ) HOSTFILE="${HOSTFILE},${OPTARG}" ;; "+i" ) HOSTFILE="${OPTARG}" ;; "s" ) SCRIPTFILE="${OPTARG}" ;; "o" ) OUTPUTFILE="${OPTARG}" [ "${OUTPUTFILE}"x = "none"x ] && OUTPUTFILE="" ;; "u" ) SSHUSER="${OPTARG}" ;; "c" ) case ${OPTARG} in "default" | "DEFAULT" ) SHELL_TO_USE="${DEFAULT_SHELL_TO_USE}" ;; "none" | "NONE" ) SHELL_TO_USE="" ;; *) SHELL_TO_USE="${OPTARG}" ;; esac ;; "k" ) ADD_COMMENTS=${__FALSE} ;; "+k" ) ADD_COMMENTS=${__TRUE} ;; "U" ) UNIQUE_LOGFILES=${__TRUE} ;; "+U" ) UNIQUE_LOGFILES=${__FALSE} ;; "B" ) DO_NOT_COPY_FILE=${__TRUE} SHELL_TO_USE="" ;; "+B" ) DO_NOT_COPY_FILE=${__FALSE} ;; "b" ) case ${OPTARG} in default | none ) SSH_KEYFILE="" ;; * ) SSH_KEYFILE="${OPTARG}" ;; esac ;; "I" ) FILE_BASEDIR="${OPTARG}" ;; "p" ) SCP_OPTIONS="${SCP_OPTIONS} ${OPTARG}" ;; "P" ) SSH_OPTIONS="${SSH_OPTIONS} ${OPTARG}" ;; "+p" ) SCP_OPTIONS="${OPTARG}" ;; "+P" ) SSH_OPTIONS="${OPTARG}" ;; "d" ) EXECUTE_PARALLEL=${__TRUE} ;; "+d" ) EXECUTE_PARALLEL=${__FALSE} ;; "W" ) TIMEOUT_PARAMETER="${OPTARG}" ;; "w" ) START_TIMEOUT_PARAMETER="${OPTARG}" ;; "A" ) if [ "${OPTARG}"x = "none"x ] ; then INLCUDE_HOSTS="" continue fi INCLUDE_HOSTS="${INCLUDE_HOSTS},${OPTARG}" ;; "x" ) if [ "${OPTARG}"x = "none"x ] ; then EXLCUDE_HOSTS="" continue fi pos "/" "${OPTARG}" if [ $? -ne 0 ] ; then if [ ! -r "${OPTARG}" ] ; then LogError "Can NOT read the file \"${OPTARG}\" " INVALID_PARAMETER_FOUND=${__TRUE} else EXCLUDE_HOSTS="${EXCLUDE_HOSTS}, $( egrep -v "^$|^#" "${OPTARG}" )" fi else EXCLUDE_HOSTS="${EXCLUDE_HOSTS},${OPTARG}" fi ;; \? ) LogError "Unknown parameter found: \"${OPTARG}\" " INVALID_PARAMETER_FOUND=${__TRUE} break ;; * ) LogError "Unknown parameter found: \"${CUR_SWITCH}\"" INVALID_PARAMETER_FOUND=${__TRUE} break ;; esac done case ${__PRINT_SUMMARIES} in 0 ) __PRINT_LIST_OF_WARNINGS_MSGS=${__FALSE} __PRINT_LIST_OF_ERROR_MSGS=${__FALSE} ;; 1 ) __PRINT_LIST_OF_WARNINGS_MSGS=${__FALSE} __PRINT_LIST_OF_ERROR_MSGS=${__TRUE} ;; 2 ) __PRINT_LIST_OF_WARNINGS_MSGS=${__TRUE} __PRINT_LIST_OF_ERROR_MSGS=${__FALSE} ;; 3 ) __PRINT_LIST_OF_WARNINGS_MSGS=${__TRUE} __PRINT_LIST_OF_ERROR_MSGS=${__TRUE} ;; * ) : this should never happen but who knows ... __PRINT_LIST_OF_WARNINGS_MSGS=${__FALSE} __PRINT_LIST_OF_ERROR_MSGS=${__FALSE} esac LogRuntimeInfo "Parameter after processing the default parameter are: " "\"$*\" " if [ ${__PRINT_USAGE} = ${__TRUE} ] ; then if [ ${__VERBOSE_MODE} -eq ${__TRUE} ] ; then ShowUsage __VERBOSE_MODE=${__FALSE} else ShowShortUsage LogMsg "Use \"-v -h\", \"-v -v -h\", \"-v -v -v -h\" or \"+h\" for a long help text" fi die 1 ; fi shift $(( OPTIND - 1 )) NOT_PROCESSED_PARAMETER="$*" LogRuntimeInfo "Not processed parameter: \"${NOT_PROCESSED_PARAMETER}\"" if [ "${NOT_PROCESSED_PARAMETER}"x != ""x ] ; then if [ $# -ne 0 ] ; then HOSTFILE="$1" shift fi if [ $# -ne 0 ] ; then SCRIPTFILE="$1" shift fi if [ $# -ne 0 ] ; then OUTPUTFILE="$1" shift fi if [ $# -ne 0 ] ; then SSHUSER="$1" shift fi fi # ----------------------------------------------------------------------------- # process the debug switches if [ "${__DEBUG_SWITCHES}"x != ""x ] ; then __DEBUG_SWITCHES=$( IFS=, ; printf "%s " ${__DEBUG_SWITCHES} ) for __CUR_DEBUG_SWITCH in ${__DEBUG_SWITCHES} ; do case ${__CUR_DEBUG_SWITCH} in "help" ) cat <&2 exec 2>"${__TRACE_LOGFILE}" typeset -ft $( typeset +f ) set -x PS4='LineNo: $LINENO (sec: $SECONDS): >> ' LogMsg "Tracing enabled; the output goes to the file \"${__TRACE_LOGFILE}\". " LogMsg "WARNING: All output to STDERR now goes into the file \"${__TRACE_LOGFILE}\"; use \">&3\" to print to real STDERR." ;; * ) die 235 "Invalid debug switch found: \"${__CUR_DEBUG_SWITCH}\" -- use \"-d help\" to list the known debug switches" ;; esac done fi if [ ${__LOG_DEBUG_MESSAGES} != ${__TRUE} ] ; then rm "${__DEBUG_LOGFILE}" 2>/dev/null 1>/dev/null __DEBUG_LOGFILE="" else echo 2>/dev/null >>"${__DEBUG_LOGFILE}" || \ die 237 "Can not write to the debug log file \"${__DEBUG_LOGFILE}\" " fi # # set INVALID_PARAMETER_FOUND to ${__TRUE} if the script # should abort due to an invalid parameter # if [ "${NOT_PROCESSED_PARAMETER}"x != ""x ] ; then LogError "Unknown parameter: \"${NOT_PROCESSED_PARAMETER}\" " INVALID_PARAMETER_FOUND=${__TRUE} fi if [ "${START_TIMEOUT_PARAMETER}"x != ""x ] ; then oIFS="${IFS}" ; IFS="," ; set -- $( echo "${START_TIMEOUT_PARAMETER}" | tr "/" "," ) ; V1="$1" ; V2="$2"; V3="$3"; IFS="${oIFS}" MAX_NO_OF_BACKGROUND_PROCESSES=${V1:=${MAX_NO_OF_BACKGROUND_PROCESSES}} START_PROC_WAIT_INTERVALL=${V2:=${START_PROC_WAIT_INTERVALL}} START_PROC_TIMEOUT=${V3:=${START_PROC_TIMEOUT}} [ "${MAX_NO_OF_BACKGROUND_PROCESSES}"x = "default"x ] && MAX_NO_OF_BACKGROUND_PROCESSES="${DEFAULT_MAX_NO_OF_BACKGROUND_PROCESSES}" [ "${START_PROC_WAIT_INTERVALL}"x = "default"x ] && START_PROC_WAIT_INTERVALL="${DEFAULT_START_PROC_WAIT_INTERVALL}" [ "${START_PROC_TIMEOUT}"x = "default"x ] && START_PROC_TIMEOUT="${DEFAULT_START_PROC_TIMEOUT}" [ "${MAX_NO_OF_BACKGROUND_PROCESSES}"x = "none"x ] && MAX_NO_OF_BACKGROUND_PROCESSES="-1" [ "${START_PROC_TIMEOUT}"x = "none"x ] && START_PROC_TIMEOUT="-1" if [ "${MAX_NO_OF_BACKGROUND_PROCESSES}"x != "-1"x ] ; then isNumber "${MAX_NO_OF_BACKGROUND_PROCESSES}" if [ $? -ne 0 ] ; then LogError "Invalid parameter found: The value for the number of parallel background processes (${MAX_NO_OF_BACKGROUND_PROCESSES}) is not a number" LogError "This is the 1st value for the parameter -w" INVALID_PARAMETER_FOUND=${__TRUE} fi fi CalculateSeconds "${START_PROC_WAIT_INTERVALL}" START_PROC_WAIT_INTERVALL_IN_SEC if [ $? -ne 0 ] ; then LogError "Invalid parameter found: The value for wait intervall (${START_PROC_WAIT_INTERVALL}) for starting the background processes is not a number" LogError "This is the 2nd value for the parameter -w" INVALID_PARAMETER_FOUND=${__TRUE} fi if [ "${START_PROC_TIMEOUT}"x != "-1"x ] ; then CalculateSeconds "${START_PROC_TIMEOUT}" START_PROC_TIMEOUT_IN_SEC if [ $? -ne 0 ] ; then LogError "Invalid parameter found: The value for the timeout for starting the parallel background processes (${START_PROC_TIMEOUT}) is not a number" LogError "This is the 3rd value for the parameter -w" INVALID_PARAMETER_FOUND=${__TRUE} fi fi fi if [ "${TIMEOUT_PARAMETER}"x != ""x ] ; then oIFS="${IFS}" ; IFS="," ; set -- $( echo "${TIMEOUT_PARAMETER}" | tr "/" "," ) ; V1="$1" ; V2="$2"; IFS="${oIFS}" MAX_RUN_WAIT_TIME=${V1:=${MAX_RUN_WAIT_TIME}} RUN_WAIT_INTERVALL=${V2:=${RUN_WAIT_INTERVALL}} [ "${MAX_RUN_WAIT_TIME}"x = "default"x ] && MAX_RUN_WAIT_TIME="${DEFAULT_MAX_RUN_WAIT_TIME}" [ "${RUN_WAIT_INTERVALL}"x = "default"x ] && RUN_WAIT_INTERVALL="${DEFAULT_RUN_WAIT_INTERVALL}" [ "${MAX_RUN_WAIT_TIME}"x = "none"x ] && MAX_RUN_WAIT_TIME="-1" if [ "${MAX_RUN_WAIT_TIME}"x != "-1"x ] ; then CalculateSeconds "${MAX_RUN_WAIT_TIME}" MAX_RUN_WAIT_TIME_IN_SEC if [ $? -ne 0 ] ; then LogError "Invalid parameter found: The value for timeout (${MAX_RUN_WAIT_TIME}) is not a number" LogError "This is the 1st value for the parameter -W" INVALID_PARAMETER_FOUND=${__TRUE} fi fi CalculateSeconds "${RUN_WAIT_INTERVALL}" RUN_WAIT_INTERVALL_IN_SEC if [ $? -ne 0 ] ; then LogError "Invalid parameter found: The value for timeout (${RUN_WAIT_INTERVALL}) is not a number" LogError "This is the 2nd value for the parameter -W" INVALID_PARAMETER_FOUND=${__TRUE} fi fi # use defaults if necessary [ "${START_PROC_WAIT_INTERVALL_IN_SEC}"x = ""x ] && CalculateSeconds ${START_PROC_WAIT_INTERVALL} START_PROC_WAIT_INTERVALL_IN_SEC [ "${START_PROC_TIMEOUT_IN_SEC}"x = ""x ] && CalculateSeconds ${START_PROC_TIMEOUT} START_PROC_TIMEOUT_IN_SEC [ "${MAX_RUN_WAIT_TIME_IN_SEC}"x = ""x ] && CalculateSeconds ${MAX_RUN_WAIT_TIME} MAX_RUN_WAIT_TIME_IN_SEC [ "${RUN_WAIT_INTERVALL_IN_SEC}"x = ""x ] && CalculateSeconds ${RUN_WAIT_INTERVALL} RUN_WAIT_INTERVALL_IN_SEC # exit the program if there are one or more invalid parameter # if [ ${INVALID_PARAMETER_FOUND} -eq ${__TRUE} ] ; then LogError "One or more invalid parameters found" ShowShortUsage die 2 fi SetEnvironment # create the PID file # if [ "${__PIDFILE}"x != ""x ] ; then LogRuntimeInfo "Writing the PID $$ to the PID file \"${__PIDFILE}\" ..." echo $$>"${__PIDFILE}" && __LIST_OF_TMP_FILES="${__LIST_OF_TMP_FILES} ${__PIDFILE}" || \ LogWarning "Can not write the pid to the PID file \"${__PIDFILE}\" " fi # restore the language setting # LANG=${__SAVE_LANG} export LANG # ----------------------------------------------------------------------------- # check for RCM support if [ ${RCM_SUPPORT} = ${__TRUE} ] ; then COPY_TABLE_PARAMETER="" [ ! -x "${COPY_TABLE_BINARY}" ] && die 3 "RCM support requested but copy_table.pl was not found" if [ "${RCM_USERID}"x = ""x ] ; then AskUser "Please enter the RCM userid: " RCM_USERID="${USER_INPUT}" fi if [ "${RCM_PASSWORD}"x = ""x ] ; then push __NOECHO __NOECHO=${__TRUE} AskUser "Please enter the RCM password: " RCM_PASSWORD="${USER_INPUT}" pop __NOECHO echo "" fi [ "${RCM_USERID}"x != ""x ] && COPY_TABLE_PARAMETER="${COPY_TABLE_PARAMETER} -u ${RCM_USERID} " [ "${RCM_PASSWORD}"x != ""x ] && COPY_TABLE_PARAMETER="${COPY_TABLE_PARAMETER} -p ${RCM_PASSWORD} " LogMsg "Checking RCM access ...." TEMPVAR=$( ${COPY_TABLE_BINARY} ${COPY_TABLE_PARAMETER} -t RCM.USER_VW -q "USERID=\"${RCM_USERID}\" " ) [ "${TEMPVAR}"x = ""x ] && die 5 "Error accessing the RCM!" fi # ----------------------------------------------------------------------------- # test / debug code -- remove in your script # print some of the runtime variables # # PrintRuntimeVariables LogInfo "Config file version is: \"${__CONFIG_FILE_VERSION}\" " # print all internal variables # if [ 1 = 0 ] ; then for i in $( set | grep "^__" | cut -f1 -d"=" ) ; do if [[ $i != __COLOR* ]] ; then echo "$i : \"$( eval echo \"\$$i\" )\" " else echo "$i is set " fi done fi # " # ----------------------------------------------------------------------------- # print script environment if [ ${__VERBOSE_MODE} = ${__TRUE} ] ; then LogMsg "-" LogMsg "----------------------------------------------------------------------" LogMsg "Scriptname is \"${__SCRIPTNAME}\" " LogMsg "Scriptversion is \"${__SCRIPT_VERSION}\" " LogMsg "Script template version is \"${__SCRIPT_TEMPLATE_VERSION}\" " LogMsg " " LogMsg "OS is \"${__OS}\" (Fullname: \"${__OS_FULLNAME}\") " LogMsg "OS Version is \"${__OS_VERSION}\" " LogMsg "OS Release is \"${__OS_RELEASE}\" " LogMsg "The current shell is \"${__SHELL}\"; this shell is compatible to ksh${__KSH_VERSION}" LogMsg "The userid running this script is \"${__USERID}\"" LogMsg "" LogMsg "The PID of this process is $$" LogMsg "" LogMsg "The script hashtag is \"${__HASHTAG}\"" LogMsg "The shell in the hashtag is \"${__SCRIPT_SHELL}\" " LogMsg "The shell options in the hashtag are \"${__SCRIPT_SHELL_OPTIONS}\" " LogMsg "----------------------------------------------------------------------" LogMsg "" fi # ----------------------------------------------------------------------------- # defined Log routines: # # LogMsg # LogInfo # LogWarning # LogError # LogOnly # LogIfNotVerbose # PrintDotToSTDOUT PARAMETER_OKAY=${__TRUE} HOSTFILE_LIST="" INVALID_HOSTS_LIST="" if [ "${HOSTFILE}"x = ""x ] ; then PARAMETER_OKAY=${__FALSE} LogError "Parameter for hostlist not specified" else for CURFILE in $( echo ${HOSTFILE} | tr -s "," " " ) ; do if [ "${CURFILE#*\?}"x != "${CURFILE}"x ] ; then CURFILE="${CURFILE#*?}" IGONRE_MISSING_FILE=${__TRUE} else IGONRE_MISSING_FILE=${__FALSE} fi if [ ! -r "${CURFILE}" ] ; then if [ "${FILE_BASEDIR}" != ""x -a ! -r "${FILE_BASEDIR}/${CURFILE}" ] ; then if [ ${IGONRE_MISSING_FILE} = ${__FALSE} ] ; then LogError "Can not read the file \"${CURFILE}\" " PARAMETER_OKAY=${__FALSE} else LogWarning "Hostlist \"${CURFILE}\" not found or not readable" fi else HOSTFILE_LIST="${HOSTFILE_LIST} ${FILE_BASEDIR}/${CURFILE}" fi else HOSTFILE_LIST="${HOSTFILE_LIST} ${CURFILE}" fi done fi LogInfo "Hostlist files found are: \"${HOSTFILE_LIST}\"" if [ "${HOSTFILE_LIST}"x = ""x ] ; then PARAMETER_OKAY=${__FALSE} LogError "No hostlist file found" fi EXCLUDE_HOSTS="$( echo "${EXCLUDE_HOSTS}" | tr "," " " )" HOSTS_EXCLUDED="" if [[ ${INCLUDE_HOSTS} == *\** || ${INCLUDE_HOSTS} == *\?* ]] ; then PARAMETER_OKAY=${__FALSE} LogError "Regular expressions for the parameter -i are NOT allowed." else INCLUDE_HOSTS="$( echo "${INCLUDE_HOSTS}" | tr "," " " | tr " " "\n" )" fi if [ "${SCRIPTFILE}"x = ""x ] ; then PARAMETER_OKAY=${__FALSE} LogError "Scriptfile not specified" elif [ ${DO_NOT_COPY_FILE} = ${__FALSE} ] ; then if [ ! -r "${SCRIPTFILE}" ] ; then if [ "${FILE_BASEDIR}" != ""x -a ! -r "${FILE_BASEDIR}/${SCRIPTFILE}" ] ; then PARAMETER_OKAY=${__FALSE} LogError "Scriptfile \"${SCRIPTFILE}\" not found or not readable" else SCRIPTFILE="${FILE_BASEDIR}/${SCRIPTFILE}" fi fi fi if [ "${NEW_SSH_BINARY}"x != ""x ] ; then if [ ! -x "${NEW_SSH_BINARY}" ] ; then LogError "The ssh binary \"${NEW_SSH_BINARY}\" does not exist or is not executable." PARAMETER_OKAY=${__FALSE} else SSH_BINARY="${NEW_SSH_BINARY}" fi fi if [ "${NEW_SCP_BINARY}"x != ""x ] ; then if [ ! -x "${NEW_SCP_BINARY}" ] ; then LogError "The scp binary \"${NEW_SCP_BINARY}\" does not exist or is not executable." PARAMETER_OKAY=${__FALSE} else SCP_BINARY="${NEW_SCP_BINARY}" fi fi if [ "${NEW_DOS2UNIX_BINARY}"x != ""x ] ; then if [ ! -x "${NEW_DOS2UNIX_BINARY}" ] ; then LogError "The ssh binary \"${NEW_DOS2UNIX_BINARY}\" does not exist or is not executable." PARAMETER_OKAY=${__FALSE} else DOS2UNIX_BINARY="${NEW_DOS2UNIX_BINARY}" fi fi # do not use a shell for binaries # if [ "${SCRIPTFILE}"x != ""x ] ; then if [ -r "${SCRIPTFILE}" ] ; then file "${SCRIPTFILE}" | egrep " LSB | MSB " >/dev/null && SHELL_TO_USE="" fi fi # do not use a shell if -B is used # if [ ${DO_NOT_COPY_FILE} = ${__TRUE} ] ; then SHELL_TO_USE="" fi # convert the file using dos2unix if running in a cygwin session # if [[ ${__OS} == CYGWIN* ]] ; then if [ "${DO_NOT_COPY_FILE}" = ${__FALSE} -a ${IS_SCRIPT_FILE} = ${__TRUE} ] ; then if [ "${DOS2UNIX_BINARY}"x != ""x ] ; then LogMsg "Calling dos2unix for the script file \"${SCRIPTFILE}\" " ${DOS2UNIX_BINARY} "${SCRIPTFILE}" else LogWarning "This script is running in a cygwin session but dos2unix is not found in the PATH - can not convert the script file" fi fi fi if [ "${SSH_KEYFILE}"x != ""x ] ; then if [ ! -r "${SSH_KEYFILE}" ] ; then PARAMETER_OKAY=${__FALSE} LogError "ssh keyfile \"${SSH_KEYFILE}\" not found or not readable" fi fi if [ "${OUTPUTFILE}"x = ""x ] ; then OUTPUTFILE="${__SCRIPTNAME}.$$.log" elif [ -d "${OUTPUTFILE}" ] ; then OUTPUTFILE="${OUTPUTFILE}/${__SCRIPTNAME}.$$.log" fi [ "${OUTPUTFILE%/*}"x = "${OUTPUTFILE}"x ] && OUTPUTFILE="./${OUTPUTFILE}" OUTPUTFILE="$( cd "${OUTPUTFILE%/*}" ; pwd )/${OUTPUTFILE##*/}" if [ -r "${OUTPUTFILE}" -a ! -f "${OUTPUTFILE}" ] ; then PARAMETER_OKAY=${__FALSE} LogError "The outputfile \"${OUTPUTFILE}\" (parameter -o) is not a file" fi if [ "${SSHUSER}"x = ""x ] ; then PARAMETER_OKAY=${__FALSE} LogError "ssh user not specified and no default value found" fi [ ${PARAMETER_OKAY} != ${__TRUE} ] && die 5 "Errors found - exiting." if [ ${NOSTRICTKEYS} = ${__TRUE} ] ; then SCP_OPTIONS="${SCP_OPTIONS} -o StrictHostKeyChecking=no" SSH_OPTIONS="${SSH_OPTIONS} -o StrictHostKeyChecking=no" fi LogMsg "" [ "${SHELL_TO_USE}"x = ""x ] && MSG1="executable" || MSG1="script" if [ "${DO_NOT_COPY_FILE}" = ${__FALSE} ] ; then TARGET_COMMAND="/tmp/tmp_$$_$( basename $0 )" LogMsg "Executing the ${MSG1} " LogMsg " ${SCRIPTFILE}" else TARGET_COMMAND="${SCRIPTFILE}" LogMsg "Executing the command " LogMsg " ${SCRIPTFILE}" fi LogMsg "as ssh user " LogMsg " ${SSHUSER}" LogMsg "on every host listed in the file(s) " for CUR_HOSTFILE in ${HOSTFILE_LIST} ; do LogMsg " ${CUR_HOSTFILE}" done if [ "${INCLUDE_HOSTS}"x != ""x ] ; then LogMsg "and on each of these hosts:" for CUR_HOST in ${INCLUDE_HOSTS} ; do LogMsg " ${CUR_HOST}" done fi if [ "${EXCLUDE_HOSTS}"x != ""x ] ; then LogMsg "" LogMsg "Hosts to exclude are: " for CUR_HOST in ${EXCLUDE_HOSTS} ; do LogMsg " ${CUR_HOST}" done fi if [ ${DO_NOT_SORT_HOSTLIST} = ${__TRUE} ] ; then LogMsg "The list of hosts will be used without modifications" fi if [ ${IGNORE_USER_IN_FILE} = ${__TRUE} ] ] ; then LogMsg "The users from the hostlists will be ignored." fi if [ "${SHELL_TO_USE}"x != ""x ] ; then LogMsg "" LogMsg "The shell to execute the command is " LogMsg " ${SHELL_TO_USE}" LogMsg "" else LogMsg "" LogMsg "The shell to execute the command is " LogMsg " the default shell of the user \"${SSHUSER}\" " LogMsg "" fi LogMsg "Using the ssh binary \"${SSH_BINARY}\"." LogMsg "Using the scp binary \"${SCP_BINARY}\"." if [[ ${__OS} == CYGWIN* ]] ; then LogMsg "Using the dos2unix binary \"${DOS2UNIX_BINARY}\"." fi if [ "${SCP_OPTIONS}"x != ""x ] ; then LogMsg "The additional options for scp are:" LogMsg " ${SCP_OPTIONS}" fi if [ "${SSH_OPTIONS}"x != ""x ] ; then LogMsg "The additional options for ssh are:" LogMsg " ${SSH_OPTIONS}" fi if [ "${SSH_KEYFILE}"x != ""x ] ; then LogMsg "Using the ssh keyfile " LogMsg " ${SSH_KEYFILE}" fi if [ ${UNIQUE_LOGFILES} = ${__FALSE} ] ; then LogMsg "The output of the commands will be logged in the file" LogMsg " ${OUTPUTFILE}" else LogMsg "The output of the commands will be logged in the files" LogMsg " ${OUTPUTFILE}." fi LogMsg "" if [ ${RCM_SUPPORT} = ${__TRUE} ] ; then LogMsg "RCM support is used (The RCM Userid is \"${RCM_USERID}\")" else LogMsg "RCM support is not used" fi if [ ${EXECUTE_PARALLEL} = ${__TRUE} ] ; then LogMsg "" LogMsg "The scp/ssh processes will run parallel in the background." LogMsg "" LogMsg "The maximum number of parallel background processes is ${MAX_NO_OF_BACKGROUND_PROCESSES} (Parameter -w ${MAX_NO_OF_BACKGROUND_PROCESSES},x,x -1 = not limited)." LogMsg " The wait intervall for starting the background processes is ${START_PROC_WAIT_INTERVALL_IN_SEC} second(s) (Parameter -w x,${START_PROC_WAIT_INTERVALL},x); " LogMsg " the timeout for starting the background processes is ${START_PROC_TIMEOUT_IN_SEC} second(s) (Parameter -w x,x,${START_PROC_TIMEOUT} -1 = not limited)." LogMsg "" LogMsg "Waiting up to ${MAX_RUN_WAIT_TIME_IN_SEC} second(s) for the background processes to finish (Parameter -W ${MAX_RUN_WAIT_TIME},x, -1 = not limited)." LogMsg " The wait intervall for waiting for the background processes to finish is ${RUN_WAIT_INTERVALL_IN_SEC} second(s) (Parameter -W x,${RUN_WAIT_INTERVALL} )" LogMsg "" else LogMsg "" LogMsg "The scp/ssh processes will run sequential one after the other." LogMsg "" fi check_SSH_agent_status if [ "${SSH_AGENT_RUNNING}" != "${__TRUE}" ] ; then LogMsg "" LogWarning "ssh-agent seems not to run or not to be configured" LogMsg "" fi if [ "${DO_NOT_COPY_FILE}" = ${__FALSE} ] ; then LogMsg "" LogInfo "The temporary file on the hosts is \"${TARGET_COMMAND}\" " fi TEMP_LIST="" for CUR_HOSTFILE in ${HOSTFILE_LIST} ; do TEMP_LIST="${TEMP_LIST} $( cat "${CUR_HOSTFILE}" | tr -d "\r" | tr -s " " | grep -v "^#" | grep -v "^$" ) " done if [ ${DO_NOT_SORT_HOSTLIST} = ${__TRUE} ] ; then LIST_OF_HOSTS_TO_PROCESS="$( echo "${TEMP_LIST}" "${INCLUDE_HOSTS}" )" else LIST_OF_HOSTS_TO_PROCESS="$( echo "${TEMP_LIST}" "${INCLUDE_HOSTS}" | sort | uniq )" fi NO_OF_HOSTS="$( echo "${LIST_OF_HOSTS_TO_PROCESS}" | wc -l | tr -d " " )" LogMsg "There are ${NO_OF_HOSTS} hosts to process" LogMsg "" AskUser "Okay (y/N)?" if [ $? -eq ${__FALSE} ] ; then __FORCE=${__FALSE} die 10 "Script aborted by the user" fi if [ ${UNIQUE_LOGFILES} = ${__FALSE} ] ; then BackupFileIfNecessary "${OUTPUTFILE}" set +o noclobber if [ ${__OVERWRITE_MODE} = ${__TRUE} ] ; then echo >"${OUTPUTFILE}" || die 15 "Can not write to the output file \"${OUTPUTFILE}\" " fi fi if [ ${DO_NOT_COPY_FILE} = ${__FALSE} ] ; then LogInfo "Setting the read permissions for the script \"${SCRIPTFILE}\" ..." chmod +r "${SCRIPTFILE}" || \ LogWarning "Error $? calling \"chmod +r\" for the file \"${SCRIPTFILE}\" " fi if [ "${SSH_KEYFILE}"x != ""x ] ; then SSH_KEY_PARM="-i ${SSH_KEYFILE}" else SSH_KEY_PARM="" fi PROCESSING_STARTED=${__TRUE} typeset -i COUNT=0 LogMsg "Starting processing ..." if [ ${EXECUTE_PARALLEL} = ${__TRUE} ] ; then # --------- execute the script in parallel STOP_STARTING=${__FALSE} if [ ${UNIQUE_LOGFILES} = ${__FALSE} ] ; then TMP_OUTPUT_DIR="${__TEMPDIR}/${__SCRIPTNAME}.$$.TEMPDIR" mkdir -p "${TMP_OUTPUT_DIR}" || die 55 "Can not create the temporary output directory \"${TMP_OUTPUT_DIR}\" " LogMsg "The directory for the temporary output files is \"${TMP_OUTPUT_DIR}\" " fi PROCS="" BACKGROUND_PIDS="" typeset -i NO_OF_PROCS_STARTED=0 typeset -i OVERALL_START_TIME=0 typeset -i MINUTES typeset -i SECONDS typeset -i HOURS for THIS_HOST in ${LIST_OF_HOSTS_TO_PROCESS} ; do CUR_USER=${THIS_HOST%@*} CUR_HOST=${THIS_HOST#*@} if [ "${CUR_USER}"x = "${CUR_HOST}"x ] ; then CUR_USER="${SSHUSER}" else if [ ${IGNORE_USER_IN_FILE} = ${__TRUE} ] ; then CUR_USER="${SSHUSER}" LogMsg "++++ The user from the hostlist \"${CUR_USER}\" for this host will be ignored." fi fi host_on_the_exclude_list "${CUR_HOST}" if [ $? -eq ${__TRUE} ] ; then LogMsg "++++ The host \"${CUR_HOST}\" is on the exclude list. Ignoring this host." continue fi NO_OF_RUNNING_PIDS=$( GetNumberOfRunningProcesses ${BACKGROUND_PIDS} ) LogMsg " Number of running processes are: ${NO_OF_RUNNING_PIDS}" if [ "${MAX_NO_OF_BACKGROUND_PROCESSES}"x != "-1"x ] ; then typeset -i START_WAIT_TIME=0 while [ ${NO_OF_RUNNING_PIDS} -ge ${MAX_NO_OF_BACKGROUND_PROCESSES} ] ; do if [ "${START_PROC_TIMEOUT_IN_SEC}"x != "-1"x ] ; then if [ ${START_WAIT_TIME} -gt ${START_PROC_TIMEOUT_IN_SEC} ] ; then LogWarning "Maximum startup time (${START_PROC_TIMEOUT_IN_SEC} seconds) reached - will NOT start the processes for the other hosts!" INVALID_HOSTS_LIST="${INVALID_HOSTS_LIST} ${LIST_OF_HOSTS_TO_PROCESS#*${CUR_HOST}}" STOP_STARTING=${__TRUE} break fi fi LogMsg " Maximum number of background processes (${MAX_NO_OF_BACKGROUND_PROCESSES}) reached." if [ "${START_PROC_TIMEOUT_IN_SEC}"x != "-1"x ] ; then (( REMAINING_WAIT_TIME = ${START_PROC_TIMEOUT_IN_SEC} - ${START_WAIT_TIME} )) LogMsg "Waiting for ${START_PROC_WAIT_INTERVALL_IN_SEC} second(s) now (total wait time until now: ${START_WAIT_TIME} seconds; max. timeout is ${START_PROC_TIMEOUT_IN_SEC} seconds ; remaining wait time is ${REMAINING_WAIT_TIME} seconds) ..." else LogMsg "Waiting for ${START_PROC_WAIT_INTERVALL_IN_SEC} second(s) now (total wait time until now: ${START_WAIT_TIME} seconds)" fi sleep ${START_PROC_WAIT_INTERVALL_IN_SEC} (( START_WAIT_TIME = START_WAIT_TIME + START_PROC_WAIT_INTERVALL_IN_SEC )) (( OVERALL_START_TIME = OVERALL_START_TIME + START_PROC_WAIT_INTERVALL_IN_SEC )) LogMsg " Resuming starting further processes ..." NO_OF_RUNNING_PIDS=$( GetNumberOfRunningProcesses ${BACKGROUND_PIDS} ) done [ ${STOP_STARTING} = ${__TRUE} ] && break fi (( COUNT = COUNT + 1 )) LogMsg " ---- Processing \"${CUR_HOST}\" (User is \"${CUR_USER}\") ... ( ${COUNT} from ${NO_OF_HOSTS}; ${NO_OF_PROCS_STARTED} already started) " if [ ${UNIQUE_LOGFILES} = ${__FALSE} ] ; then CUR_OUTPUTFILE="${TMP_OUTPUT_DIR}/${CUR_HOST}.log" echo >"${CUR_OUTPUTFILE}" ; THISRC=$? if [ ${THISRC} -ne 0 ] ; then LogError "Can not write to the logfile \"${CUR_OUTPUTFILE}\" -- skipping the host \"${CUR_HOST}\" " INVALID_HOSTS_LIST="${INVALID_HOSTS_LIST} ${CUR_HOST}" continue fi else CUR_OUTPUTFILE="${OUTPUTFILE}.${CUR_HOST}" BackupFileIfNecessary "${CUR_OUTPUTFILE}" if [ ${__OVERWRITE_MODE} = ${__TRUE} ] ; then echo >"${CUR_OUTPUTFILE}" ; THISRC=$? else touch "${CUR_OUTPUTFILE}" ; THISRC=$? fi if [ ${THISRC} -ne 0 ] ; then LogError "Can not write to the logfile \"${CUR_OUTPUTFILE}\" -- skipping the host \"${CUR_HOST}\" " INVALID_HOSTS_LIST="${INVALID_HOSTS_LIST} ${CUR_HOST}" continue fi fi get_curhost_interace "${CUR_HOST}" if [ ${DO_NOT_COPY_FILE} = ${__FALSE} ] ; then ( [ ${ADD_COMMENTS} = ${__TRUE} ] && echo "# ### ---- Log of the script \"${SCRIPTFILE}\" executed on host \"${CUR_HOST}\" as user \"${CUR_USER}\" at $( date )--- start ---" ; \ "${SCP_BINARY}" ${SCP_OPTIONS} ${SSH_KEY_PARM} "${SCRIPTFILE}" "${CUR_USER}@${CUR_HOST_INTERFACE}:${TARGET_COMMAND}" && \ "${SSH_BINARY}" ${SSH_OPTIONS} ${SSH_KEY_PARM} -l "${CUR_USER}" "${CUR_HOST_INTERFACE}" ${SHELL_TO_USE} ${TARGET_COMMAND} ; \ [ ${ADD_COMMENTS} = ${__TRUE} ] && echo "# ### ---- Log of the script executed on host \"${CUR_HOST}\" as user \"${CUR_USER}\" at $( date ) --- end ---" ) >>"${CUR_OUTPUTFILE}" 2>&1 & else ( [ ${ADD_COMMENTS} = ${__TRUE} ] && echo "# ### ---- Log of the command \"${SCRIPTFILE}\" executed on host \"${CUR_HOST}\" as user \"${CUR_USER}\" at $( date ) --- start ---" ; \ "${SSH_BINARY}" ${SSH_OPTIONS} ${SSH_KEY_PARM} -l "${CUR_USER}" "${CUR_HOST_INTERFACE}" ${SHELL_TO_USE} ${TARGET_COMMAND} ; \ [ ${ADD_COMMENTS} = ${__TRUE} ] && echo "# ### ---- Log of the command executed on host \"${CUR_HOST}\" as user \"${CUR_USER}\" at $( date ) --- end ---" ) >>"${CUR_OUTPUTFILE}" 2>&1 & fi (( NO_OF_PROCS_STARTED = NO_OF_PROCS_STARTED + 1 )) [ "${PROCS}"x = ""x ] && PROCS="${CUR_HOST}#${!}#${CUR_OUTPUTFILE}" || PROCS="${CUR_HOST}#${!}#${CUR_OUTPUTFILE};${PROCS}" LogInfo " command started via ssh on ${CUR_HOST}; the process PID=$! started at $( date )" [ "${BACKGROUND_PIDS}"x = ""x ] && BACKGROUND_PIDS="$!" || BACKGROUND_PIDS="${BACKGROUND_PIDS} $!" done (( SECONDS = OVERALL_START_TIME % 60 )) (( MINUTES = OVERALL_START_TIME / 60 )) if [ ${MINUTES} -gt 59 ] ; then (( HOURS = MINUTES / 60 )) (( MINUTES = MINUTES % 60 )) else HOURS=0 fi LogMsg "The loop to start the ${NO_OF_PROCS_STARTED} background processes ended at $( date ), the runtime is $( printf "%d:%.2d:%.2d" ${HOURS} ${MINUTES} ${SECONDS} )." LogInfo "Starting the wait loop with PROCS=\"$PROCS\" " # now wait for the ssh processes to finish # LogMsg "" LogMsg "Starting the loop to wait for the background processes at $( date ) ..." LogMsg " Waiting up to ${MAX_RUN_WAIT_TIME_IN_SEC} seconds for the background processes to finish ..." typeset -i RUN_WAIT_TIME=0 typeset PROC_LOG_FILES="" while true ; do if [ "${MAX_RUN_WAIT_TIME_IN_SEC}"x != "-1"x ] ; then [ ${RUN_WAIT_TIME} -ge ${MAX_RUN_WAIT_TIME_IN_SEC} ] && break fi [ "${PROCS}"x = ""x ] && break LogInfo " PROCS loop starts here ..." STILL_RUNNING_PROCS="" NO_OF_STILL_RUNNING_PROCS=0 NO_OF_RUNNING_PIDS=$( GetNumberOfRunningProcesses ${BACKGROUND_PIDS} ) case ${NO_OF_RUNNING_PIDS} in 0 ) LogInfo "All processes finished at loop start." ;; 1 ) LogInfo "There is still ${NO_OF_RUNNING_PIDS} process running at loop start:" ;; * ) LogInfo "There are still ${NO_OF_RUNNING_PIDS} processes running at loop start:" ;; esac while [ "${PROCS}"x != ""x ]; do CUR_PROC_LINE="${PROCS%%;*}" PROCS="${PROCS#*;}" [ "${PROCS}"x = "${CUR_PROC_LINE}"x -o "${PROCS}"x = ";"x ] && PROCS="" CUR_HOST="${CUR_PROC_LINE%%#*}" CUR_OUTPUT_FILE="${CUR_PROC_LINE##*#}" CUR_PID=${CUR_PROC_LINE#*#} ; CUR_PID=${CUR_PID%%#*} LogInfo " PROCS: \"${PROCS}\" " LogInfo " CUR_PROC_LINE: \"${CUR_PROC_LINE}\" " LogInfo " CUR_OUTPUT_FILE: \"${CUR_OUTPUT_FILE}\" " LogInfo " CUR_HOST: \"${CUR_HOST}\" " LogInfo " CUR_PID: \"${CUR_PID}\" " PS_P_OUTPUT="$( ps -p ${CUR_PID} 2>&1 )" if [ $? -eq 0 ] ; then [ "${STILL_RUNNING_PROCS}"x = ""x ] && STILL_RUNNING_PROCS="${CUR_PROC_LINE}" || STILL_RUNNING_PROCS="${STILL_RUNNING_PROCS};${CUR_PROC_LINE}" LogMsg " Process \"${CUR_PID}\" for ${CUR_HOST} is still running" (( NO_OF_STILL_RUNNING_PROCS = NO_OF_STILL_RUNNING_PROCS + 1 )) continue else LogMsg " Process \"${CUR_PID}\" for ${CUR_HOST} finished" PROC_LOG_FILES="${PROC_LOG_FILES} ${CUR_OUTPUT_FILE}" fi done PROCS="${STILL_RUNNING_PROCS}" if [ "${PROCS}"x != ""x ] ; then [ ${NO_OF_STILL_RUNNING_PROCS} = 1 ] && \ LogMsg " ${NO_OF_STILL_RUNNING_PROCS} background process (from ${NO_OF_PROCS_STARTED}) is still running" || \ LogMsg " ${NO_OF_STILL_RUNNING_PROCS} background processes (from ${NO_OF_PROCS_STARTED}) are still running" if [ "${MAX_RUN_WAIT_TIME_IN_SEC}x" != "-1"x ] ; then (( REMAINING_WAIT_TIME = ${MAX_RUN_WAIT_TIME_IN_SEC} - ${RUN_WAIT_TIME} )) LogMsg " Waiting for ${RUN_WAIT_INTERVALL_IN_SEC} second(s) now (total wait time until now: ${RUN_WAIT_TIME} seconds; max. timeout is ${MAX_RUN_WAIT_TIME_IN_SEC} seconds ; remaining wait time is ${REMAINING_WAIT_TIME} seconds) ..." else LogMsg " Waiting for ${RUN_WAIT_INTERVALL_IN_SEC} second(s) now (total wait time until now: ${RUN_WAIT_TIME} seconds)" fi sleep ${RUN_WAIT_INTERVALL_IN_SEC} (( RUN_WAIT_TIME = RUN_WAIT_TIME + RUN_WAIT_INTERVALL_IN_SEC )) fi done (( SECONDS = RUN_WAIT_TIME % 60 )) (( MINUTES = RUN_WAIT_TIME / 60 )) if [ ${MINUTES} -gt 59 ] ; then (( HOURS = MINUTES / 60 )) (( MINUTES = MINUTES % 60 )) else HOURS=0 fi LogMsg "The loop to wait for the background processes ended at $( date ), the runtime is $( printf "%d:%.2d:%.2d" ${HOURS} ${MINUTES} ${SECONDS} )." LogMsg "" if [ ${UNIQUE_LOGFILES} = ${__FALSE} ] ; then LogMsg "Collecting the result logs ..." for CUR_LOG_FILE in ${PROC_LOG_FILES} ; do LogMsg " Processing \"${CUR_LOG_FILE}\" ..." if [ -r "${CUR_LOG_FILE}" ] ; then executeCommandAndLog cat "${CUR_LOG_FILE}" >>"${OUTPUTFILE}" else LogError "Logfile \"${CUR_LOG_FILE}\" not found or not readable" fi done fi else # --------- execute the script sequential typeset -i COUNT=0 for THIS_HOST in ${LIST_OF_HOSTS_TO_PROCESS} ; do CUR_USER=${THIS_HOST%@*} CUR_HOST=${THIS_HOST#*@} if [ "${CUR_USER}"x = "${CUR_HOST}"x ] ; then CUR_USER="${SSHUSER}" else if [ ${IGNORE_USER_IN_FILE} = ${__TRUE} ] ; then CUR_USER="${SSHUSER}" LogMsg "++++ The user from the hostlist \"${CUR_USER}\" for this host will be ignored." fi fi host_on_the_exclude_list "${CUR_HOST}" if [ $? -eq ${__TRUE} ] ; then LogMsg "++++ The host \"${CUR_HOST}\" is on the exclude list. Ignoring this host." continue fi (( COUNT = COUNT + 1 )) LogMsg "---- Processing \"${CUR_HOST}\" (User is \"${CUR_USER}\") ... ( ${COUNT} from ${NO_OF_HOSTS}) " if [ ${UNIQUE_LOGFILES} = ${__FALSE} ] ; then CUR_OUTPUTFILE="${OUTPUTFILE}" else CUR_OUTPUTFILE="${OUTPUTFILE}.${CUR_HOST}" BackupFileIfNecessary "${CUR_OUTPUTFILE}" if [ ${__OVERWRITE_MODE} = ${__TRUE} ] ; then echo >"${CUR_OUTPUTFILE}" ; THISRC=$? else touch "${CUR_OUTPUTFILE}" ; THISRC=$? fi if [ ${THISRC} -ne 0 ] ; then LogError "Can not write to the logfile \"${CUR_OUTPUTFILE}\" -- skipping the host \"${CUR_HOST}\" " INVALID_HOSTS_LIST="${INVALID_HOSTS_LIST} ${CUR_HOST}" continue fi fi get_curhost_interace "${CUR_HOST}" if [ ${DO_NOT_COPY_FILE} = ${__FALSE} ] ; then executeCommand "${SCP_BINARY}" "${SCP_OPTIONS}" "${SSH_KEY_PARM}" "${SCRIPTFILE}" "${CUR_USER}@${CUR_HOST_INTERFACE}:${TARGET_COMMAND}" if [ $? -ne 0 ] ; then LogError "Error copying the script to the host \"${CUR_HOST}\" - could not execute the script on that host" INVALID_HOSTS_LIST="${INVALID_HOSTS_LIST} ${CUR_HOST}" continue fi fi if [ ${ADD_COMMENTS} = ${__TRUE} ] ; then echo "# ### ---- Log of the script \"${SCRIPTFILE}\" executed on host \"${CUR_HOST}\" --- start ---" >>"${CUR_OUTPUTFILE}" fi executeCommandAndLog "${SSH_BINARY}" "${SSH_OPTIONS}" "${SSH_KEY_PARM}" -l "${CUR_USER}" "${CUR_HOST_INTERFACE}" ${SHELL_TO_USE} ${TARGET_COMMAND} | tee -a "${CUR_OUTPUTFILE}" if [ ${ADD_COMMENTS} = ${__TRUE} ] ; then echo "# ### ---- Log of the script executed on host \"${CUR_HOST}\" --- end ---" >>"${CUR_OUTPUTFILE}" echo "" >>"${CUR_OUTPUTFILE}" fi done fi LogMsg "" LogMsg "All done (${NO_OF_PROCS_STARTED} hosts)." LogMsg "" if [ "${HOSTS_EXCLUDED}"x != ""x ] ; then LogMsg "Not processed hosts on the host exclude list are:" for CUR_HOST in ${HOSTS_EXCLUDED} ; do LogMsg " ${CUR_HOST}" done LogMsg "" fi die ${__MAINRC} exit # -----------------------------------------------------------------------------