# # Author: Georg Voell - georg.voell@standby.cloud # Version: @(#)lib.bash 3.2.0 11.08.2024 (c)2024 Standby.cloud # Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ # # This script can be used free of charge. Use it as is or customize as needed. It is not guaranteed to be # error free and you will not be reimbursed for any damage it may cause. # # To include with "source lib.bash" # # Update history: # # V 3.0.0 18.04.2020 New version # V 3.0.1 02.07.2020 Show version (only version - no toolname) / Avoid 'abort by user message' in 'confirm' and 'errormsg' # V 3.0.2 19.01.2021 New function ClearSTDIN # V 3.1.0 05.06.2023 New copyright # V 3.1.1 07.09.2023 Use gnu sed and tail if available # V 3.1.2 23.07.2024 New resource types # V 3.2.0 11.08.2024 New minor version: New function ConvertKeys # # Test if fuction is defined function FunctionExists() { local name=${1} if [ "$name" != "" ]; then declare -f -F $1 > /dev/null stat=$? if [ $stat -eq 0 ]; then echo "true" else echo "false" fi else echo "unknown" fi } # trap ctrl-c and call interrupt() trap Interrupt INT # Check if functions are already declared if [ `FunctionExists Cleanup` != true ]; then # Do cleanup function Cleanup() { if [ -f $scratchfile ]; then rm -f $scratchfile fi if [ `FunctionExists ExtraCleanup` = true ]; then ExtraCleanup fi } # Clear /dev/stdin - Clear Pipe function ClearSTDIN() { # Check if we have something in input stream if [ ! -t 0 ]; then cat /dev/stdin > /dev/null 2>&1 fi } # Do cleanup, display error message and exit function Interrupt() { exitcode=99 if [ "$itrfile" != "" ]; then if [ ! -f "$itrfile" ]; then # Print newline and bell printf "${bell}\n" >/dev/tty # Display abort messages # errormsg $exitcode "Script aborted by user interrupt." "$script '$itrfile'" >/dev/tty 2>&1 errormsg $exitcode "Script aborted by user interrupt." >/dev/tty 2>&1 # Create user interrupt file touch "$itrfile" if [ "$SUDO_USER" != "" ]; then chown "${REALUSER}:$REALGROUP" "$itrfile" fi # Change filerights chmod 666 "$itrfile" fi fi # Delete temp files, clear pipe, leave the script and return errorcode Cleanup ClearSTDIN exit $exitcode } # Delimit strings to given size function ShrinkString() { local str=${1} local slen=${2} local size=0 if [ "$str" != "" ]; then size=`printf "%s" "$str" | wc -m` if [ "$slen" = "" ]; then slen=$size fi if [ $size -gt $slen ]; then let slen-- echo "${str:0:$slen}*" else echo "$str" fi fi } # Used with DEBUG function ShowVariable() { local varname=${1} local content=${2} local stat=0 if [ "$LOGFILE" != "" ]; then # Check if $LOGFILE exists - otherwise create it if [ ! -f "$LOGFILE" ]; then touch "$LOGFILE" > /dev/null 2>&1 stat=$? fi if [ "$varname" != "" -a $stat -eq 0 ]; then printf "DEBUG (%s): %s: '%s'\n" "$progstr" "$varname" "$content" >> "$LOGFILE" fi fi if [ "$varname" != "" ]; then printf "DEBUG (%s): %s: '%s'\n" "$progstr" "$varname" "$content" > /dev/tty fi } # Define PATH function BuildPath() { local orgpath=${1} local locpath="/usr/local/sbin /usr/local/bin" local stdpath="/usr/sbin /usr/bin /sbin /bin" local newpath="" local addpath="" local usrpath="" local curpath="" if [ "$HOME" = "/" ]; then userpath="/.local/bin" else if [ "$REALHOME" != "$HOME" ]; then usrpath="${HOME}/bin ${HOME}/.local/bin ${REALHOME}/bin ${REALHOME}/.local/bin" else usrpath="${REALHOME}/bin ${REALHOME}/.local/bin" fi fi curpath=`echo $orgpath | tr ' ' '°' | tr ':' ' '` # On Mac we can have blanks in folder names - translate blanks to spec char first case "$OS" in Darwin) addpath="/opt/local/sbin /opt/local/bin /opt/X11/bin" ;; SunOS) addpath="/usr/gnu/bin /usr/sfw/bin /opt/sfw/bin /opt/sfw/bin /opt/csw/sbin /opt/csw/bin" ;; esac for folder in $usrpath $locpath $addpath $stdpath $curpath; do folder=`echo $folder | tr '°' ' '` # spec char translation for Mac grepres=`echo "$newpath" | grep -w "$folder"` if [ -d "$folder" -a "$grepres" = "" ]; then if [ "$newpath" = "" ]; then newpath="$folder" else newpath="$newpath:$folder" fi fi done # Return result echo "$newpath" } # Convert a colon (preferred), tab or comma separated string to blank separated string function ConvertKeys() { local param=${1} local result="" if [ "$param" != "" ]; then # Convert space to non-breaking-space param=`echo "$param" | tr ' ' ' '` result=`echo "$param" | grep ':'` if [ "$result" != "" ]; then # Fields are separated by colon (preferred) result=`echo "$param" | tr -s ':' ' '` else result=`\echo -e "$param" | grep $'\t'` if [ "$result" != "" ]; then # Fields are separated by tab result=`\echo -e "$param" | tr -d ':' | tr -s '\t' ' '` else # Fields are separated by comma (we assume) result=`echo "$param" | tr -d ':' | tr -s ',' ' '` fi fi fi echo "$result" } # Sometimes the resource type name from OCID doesn't match the real resource type function AdjustResourceType() { local rtype=${1} if [ "$rtype" != "" ]; then rtype=`echo "$rtype" | tolower` case "$rtype" in blockvolumereplica) rtype="volumereplica" ;; certificatesassociation) rtype="certificateauthorityassociation" ;; cluster) rtype="clusterscluster" ;; computecontainer) rtype="container" ;; computecontainerinstance) rtype="containerinstance" ;; contentexperiencecloudservice) rtype="oceinstance" ;; datasafetargetalertpolicyassoc) rtype="datasafetargetalertpolicyassociation" ;; dns-zone) rtype="customerdnszone" ;; domainapp) rtype="app" ;; dynamicgroup) rtype="dynamicresourcegroup" ;; floatingip) rtype="publicip" ;; fnapp) rtype="functionsapplication" ;; fnfunc) rtype="functionsfunction" ;; recoveryserviceprotecteddatabase) rtype="protecteddatabase" ;; saml2idp) rtype="identityprovider" ;; esac # Return result echo "$rtype" fi } # Sometimes the region name from OCID doesn't match the real region name function AdjustRegion() { local region=${1} if [ "$region" != "" ]; then region=`echo "$region" | tolower` case "$region" in phx) region="us-phoenix-1" ;; iad | us-ashburn) region="us-ashburn-1" ;; esac # Return result echo "$region" fi } # Convert an OCID into it's parts and return it as tsv # https://docs.oracle.com/en-us/iaas/Content/General/Concepts/identifiers.htm # ocid1...[REGION][.FUTURE USE]. function ConvertOCID() { local ocid=${1} local vers="" local rtype="" local realm="" local region="" local uid="" local dc="" local result="" # Check if ocid contains dots ocid=`echo "$ocid" | grep '\.'` if [ "$ocid" != "" ]; then vers=`echo "$ocid" | cut -d'.' -f1` rtype=`echo "$ocid" | cut -d'.' -f2` realm=`echo "$ocid" | cut -d'.' -f3` region=`echo "$ocid" | cut -d'.' -f4` uid=`echo "$ocid" | cut -d'.' -f5` # Convert additional parameter if [ "$vers" = "ocid1" -a "$rtype" != "" -a "$uid" != "" ]; then # Convert resource type rtype=`AdjustResourceType "$rtype"` # Convert region region=`AdjustRegion "$region"` # Convert uid to dc result=`filecheck -x base32` if [ "$result" != "" ]; then dc=`echo "$uid" | head -c 8 | toupper | base32 -d | tr -d '\0'` fi # Print result printf "version\tresourceType\trealm\tregion\tuid\tdc\n" printf "$vers\t$rtype\t$realm\t$region\t$uid\t$dc\n" fi fi } # Display help or error message function DisplayHelp() { local commentvers="" local namestr="" local cversion="" local cright="" local cowner="" local versstr="" if [ "$showversion" = true -o "$showhelp" = true -o "$errstr" != "" ]; then # Get the version of the script commentvers=`head -n 5 "$script" | grep '^# Version: @(' | cut -d')' -f2-` namestr=`echo "$commentvers" | cut -d' ' -f1` # Name from comment cversion=`echo "$commentvers" | cut -d' ' -f2` # Version from comment cright=`echo "$commentvers" | cut -d' ' -f4` # Copyright cowner=`echo "$commentvers" | cut -d' ' -f5-` # Copyright owner if [ "$showversion" = true ]; then printf "%s\n" "$cversion" else # Build version string versstr="$namestr ${cversion}, ${cright} $cowner" printf "\n$versstr\n" grep '^#@' $script | sed 's|^#@||' printf "\n" # Display error message and exit with return code 1 if [ "$showhelp" = false -a "$errstr" != "" ]; then exitcode=1 errormsg $exitcode "$errstr" fi fi # Delete temp files, clear pipe, leave the script and return errorcode Cleanup ClearSTDIN exit $exitcode fi } fi # Get the REALUSER if [ "$REALUSER" = "" ]; then export USER=`whoami` # Current user export OS=`uname -s` # Infos about the host os (e.g. Darwin, SunOS, Linux) # Try to get HOME if it is not set if [ "$HOME" = "" -o "$HOME" = "/" ]; then export HOME=$(eval echo ~${USER}) if [ "$HOME" = "" ]; then export HOME="/" fi fi # Check if script runs with 'sudo' if [ "$SUDO_USER" != "" ]; then export REALUSER="$SUDO_USER" export REALGROUP=`id -gn $SUDO_USER` export REALHOME=$(eval echo ~${SUDO_USER}) export HOME=$(eval echo ~${USER}) else export REALUSER="$USER" export REALGROUP=`id -gn $USER` export REALHOME="$HOME" fi # Show debug infos if aked for if [ "$DEBUG_LIB" = true ]; then ShowVariable "USER" "$USER" ShowVariable "HOME" "$HOME" ShowVariable "OS" "$OS" ShowVariable "SUDO_USER" "$SUDO_USER" ShowVariable "REALUSER" "$REALUSER" ShowVariable "REALHOME" "$REALHOME" ShowVariable "USER_HOME" "$HOME" fi fi # Define global default variables if [ "$script" = "" ]; then if [ "$scriptname" != "" ]; then script="$scriptname" else script=`echo "$0" | sed 's|^[-]*||'` # Name of this script without any leading dashes fi readonly progstr=`basename "$script"` # Basename of the script readonly progdir=`dirname "$script"` # Dirname of the script readonly pid="$$" # Get the process id from current shell readonly tmpdir="/tmp" # Temporary directory readonly timestamp=`date '+%y%m%d%H%M%S'` # Extension String with current date and time readonly scratchfile="${tmpdir}/${progstr}.${timestamp}.${pid}.tmp" # Temporary file readonly itrfile="${tmpdir}/${REALUSER}_INTERRUPT.tmp" # Will be created if user presses crtl C exitcode=0 # Default exit code showhelp=false # true to show help showversion=false # true to show version errstr="" # Default error message result="" # Result string fi # Check if user interrupt file exists (was created by the last user interrupt) and delete it if [ "$itrfile" != "" ]; then if [ -f "$itrfile" ]; then # if [ "$progstr" != "errormsg" -a "$progstr" != "filecheck" -a "$progstr" != "oci-api" -a "$progstr" != "convert-json" ]; then if [ "$progstr" != "errormsg" -a "$progstr" != "filecheck" -a "$progstr" != "oci-api" ]; then # echo "($script) Deleting '$itrfile'" > /dev/tty rm -f "$itrfile" fi fi fi # Show debug infos if aked for if [ "$DEBUG_LIB" = true ]; then ShowVariable "script" "$script" ShowVariable "scratchfile" "$scratchfile" fi # Define some colors and bell if [ "$normal" = "" ]; then readonly normal='\033[0m' readonly bell='\007' readonly red='\033[0;31m' readonly green='\033[0;32m' readonly yellow='\033[0;33m' readonly blue='\033[0;34m' readonly magenta='\033[0;35m' readonly cyan='\033[0;36m' readonly gray='\033[0;90m' readonly white='\033[0;97m' readonly black='\033[0;30m' readonly bold='\033[1m' readonly highred='\033[0;91m' # Highlighted red readonly pink='\033[0;95m' # Highlighted magenta fi # Set PATH to something useful if [ "$WORKPATH" = "" ]; then export CURRPATH="$PATH" export WORKPATH=`BuildPath $PATH:$progdir` export PATH="$WORKPATH" # Show debug infos if aked for if [ "$DEBUG_LIB" = true ]; then ShowVariable "CURRPATH" "$CURRPATH" ShowVariable "WORKPATH" "$WORKPATH" fi fi # Define helpful aliases result=`alias tolower 2>/dev/null` if [ "$result" = "" ]; then shopt -s expand_aliases # unalias -a alias stripcomment="sed 's|#.*$||'" # Ignore all comments alias tolower="tr '[:upper:]' '[:lower:]'" # Lowercase string alias toupper="tr '[:lower:]' '[:upper:]'" # Uppercase string alias ll="ls -als" # Full directory listing alias more="less -R" # Show color codes # Check if we have gnu tools installed for tool in sed tail; do result=`which g$tool 2>/dev/null` if [ "$result" != "" ]; then alias $tool="$result" fi done if [ "$OS" = "SunOS" ]; then # If we are runnung on Solaris, tail had to be handled different if [ -x "/usr/gnu/bin/tail" ]; then alias tailfromline2="/usr/gnu/bin/tail -n +2" alias taillastline="/usr/gnu/bin/tail -n 1" else alias tailfromline2="/usr/bin/tail +2" alias taillastline="/usr/bin/tail -1" fi else alias tailfromline2="tail -n +2" alias taillastline="tail -n 1" fi fi