#!/bin/bash ############################################################################### # # # F01 common.lib : A library for common functions. # # This library should work with KSH93 & BASH. # # # # +---------------------------------------------------------------------+ # # | Copyright (c) 2009-2015 Flyounet | # # +---------------------------------------------------------------------+ # # | This program is free software: you can redistribute it and/or | # # | modify it under the terms of the GNU General Public License as | # # | published by the Free Software Foundation, either version 3 of the | # # | License, or (at your option) any later version. | # # | | # # | This program is distributed in the hope that it will be useful, | # # | but WITHOUT ANY WARRANTY; without even the implied warranty of | # # | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | # # | GNU General Public License for more details. | # # | | # # | You should have received a copy of the GNU General Public License | # # | along with this program. | # # | If not, see . | # # +---------------------------------------------------------------------+ # # | Cette œuvre est distribuée SANS AUCUNE GARANTIE hormis celle d'être | # # | distribuée sous les termes de la License Demerdez-vous ("Demerden | # # | Sie Sich License") plus communément appelée DSSL telle que publiée | # # | par Flyounet : soit la version 1 de cette licence, soit (à votre | # # | gré) toute version ultérieure. | # # | | # # | Vous devriez avoir reçu une copie de la Licence Démerdez-vous avec | # # | cette œuvre ; si ce n’est pas le cas, consultez : | # # | . | # # +---------------------------------------------------------------------+ # # | Author: Flyounet < dev @@ flyounet . net > | # # +---------------------------------------------------------------------+ # # # ############################################################################### # # # v0.01 [20/01/2009] Flyounet [@Home] : # # > Initiale Release (from myEasyConnect script) # # v0.07 [20/11/2009] Flyounet [@Home] : # # + Rewriting code to be more readable and a really lib. # # v0.08 [23/11/2009] Flyounet [@Work] : # # + Add Comments and header. # # > If you need to Debug set the variable below to a value > 0 # # eg. 5 if you want the function call and 6 if you also want the exit # # v0.09 [23/11/2009] Flyounet [@Work] : # # + iniParseFile & iniGetValue : To parse INI files # # v0.10 [23/11/2009] Flyounet [@Work] : # # * p2s : add the -- before string to avoid problem # # v0.12 [23/11/2009] Flyounet [@Home] : # # * Force the DEBUG to var 0 if not set # # v0.12 [23/11/2009] Flyounet [@Home] : # # * myDebug: I forget to print the Debug level # # * myDebug: It was a problem of shift before print # # v0.13 [23/11/2009] Flyounet [@Work] : # # * fileCheck : Typo problem in a test # # v0.14 [23/11/2009] Flyounet [@Home] : # # * iniParseFile: Change of the awk matchString. # # v0.16 [23/11/2009] Flyounet [@Home] : # # + logMe, LogMeV, logRotate : Logs Functions # # v0.17 [25/11/2009] Flyounet [@Home] : # # * Correct the 3 last function added. # # v0.19 [27/11/2009] Flyounet [@Home] : # # + isFunction: Return 1/0 if the arg is function Name. # # v0.20 [02/12/2009] Flyounet [@Home] : # # + sprintf: Equivalent to C sprintf function. # # + isFunction: Now with a second arg can detect a programme or function# # v0.21 [22/01/2010] Flyounet [@Home] : # # * trim: As I want a shell lib, I comment the usage of sed and let the # # shell version by using variables. # # + ltrim & rtrim: left trim & right trim of [[:space:]] in shell. # # * trim: Now use ltrim & rtrim instead of builtin and sed. # # > Adding [@Home] and [@Work] to know where I work on this lib. # # v0.22 [??/01/2010] Flyounet [@Home] : # # > Can't remember what have been done. # # v0.23 [30/01/2010] Flyounet [@Home] : # # * fileCreate: In case of error during touch an ugly message is now # # sent to /dev/null (for chmod too) # # v0.24 [03/03/2010] Flyounet [@Home] : # # > First svn version # # v0.25 [01/04/2010] Flyounet [@Home] : # # + textFill: equivalent to perl "string" x number # # + textBox: put a caracter all around a text # # * textBox: not working with KSH # # + _str2lower & _str2upper have been added, cause to KSH that doesn't # # support Case modification of Bash. # # * textBox: now use _str2*er and work with KSH # # * iniGetValue: Remove the call to awk (Yeah ! Love shell !) # # v0.26 [22/04/2010] Flyounet [@Home] : # # + parseHeadersForHelp: Print the headers of each function in a file. # # Headers are based on a first line containing a #F??. # # > textBox: Only works with KSH... Fuck ! # # * textBox: A subfile is needed to make it works with bash. # # v0.27 [27/04/2010] Flyounet [@Home] : # # > Problem with the Bash version. If old Bash is use BASH_SOURCE # # doesn't exist... # # Now looks for the files instead of trying to load it directly to # # avoid, error messages. Search in above and under directory. # # * F01Version return the path of the Bash extension. # # * trim : Huge bug ! Instead of unsetting __ltrim & __trim, i unsetted # # functions ltrim & rtrim... # # > ltrim & rtrim don't work under Bash ! ARGGGGGGGGGGGGG !!!!! # # * iniParseFile : In case of a line only containing a left var with # # incorrect character (like a dash -), the awk version sent an error # # to the output (and under Ksh stops). # # Function has been rewritted purely in shell... # # * sprintf : Problem under Bash. Bash doesn't support only one _ as a # # variable name : Corrected. # # * iniGetValue : Not use grep anymore. Only Shell ! # # * fileCheck : Problem under Bash. Bash doesn't support only one _ as # # a variable name : Corrected. # # * logMe : Problem under Bash. Bash doesn't support only one _ as a # # variable name : Corrected. # # > Now only logRotate use non-shell programs ! # # + myError : If none args then empty __lastError # # v0.28 [03/05/2010] Flyounet [@Home] : # # + statusBar : generate the informations to have a status bar (eg. # # 0%....5%....10%.... and so on until 100% # #- * statusBar : Change the call during the myDebug(6) # # v0.29 [05/01/2011] Flyounet [@Home] : # # + Change scripts to use include instead of prereqs # # * statusBar : If function is called multiple time with a 0, it's # # printed until th evalue change... # # * p2s : Forced to use the builtin shell printf function. # # * isFunction Forced to use the builtin shell command function. # # * fileDelete & fileCreate : add a -- (double dash) in case of a weird # # filename containing dash.... # # + randomString : exists to generate pseudorandom strings # # * parseHeadersForHelp: Insensitive search added. # # + _p2s : print to screen without new line # # * p2s : now call _p2s instead of the builtin printf # # * Change some writing with ]; then and ohter ; do # # > It's the birthday of the husband of my sister... # # v0.30 [03/05/2011] Flyounet [@Home] : # # > Lots of modifications, since I discover a problem with string # # containing % (percent symbol) in case of use of p2s. # # + _p2sp & p2sp : they are able to deal with strings containing % and # # should be preffered to _p2s & p2s when you are sure about the # # text you use. # # * myDebug, logMe & others functions have been changed to use p2sp # # instead of p2s # # + I'm in the process of replacing sprintf by sprintfv2 but preliminary# # tests show sprintf is 50% faster than the v2 (but can't handle %i # # or %.2f, etc) like sprintfv2. # # > Need to import change from unstable/F01common.lib_v0.30* branche. # # > Import Start # # + Add 3 booleans : FALSE, TRUE & NULL. # # * Replace all exit status and return code by the Boolean. # # * I replace 'which' by 'command -v', it seems less slow than 'which', # # more independant as no external 'which' needed. # # * logRotate : remove the awk for wc -l... # # * oops & oopst could return another value than one if var set before # # * __bash & __ksh are set to TRUE when working Shell is discovered # # - logMe, logMeV, logRotate have been moved in the F04logger.lib # # > logMe, logMeV, logRotate not removed for the time being # # * TRUE & FALSE are now 0 & 1 # # > Protocol updated due to result of function returned. # # * myDebug Force the use of __utsCmd. If possible date is faster than # # perl. # # * _p2s : beurk, I really dislike this hack. # # > End of import # # * [lr]trimv2 created # # + __zsh is set to TRUE when ZSH discovered. Starting to test ZSH. # # + _e2s & e2s are 2 new function to use echo instead of printf when # # needed. # # v0.31 [28/02/2012] Flyounet [@Home] : # # * _p2sp : Under AIX when searching for %, return the end of string. # # Changed the //%/%% to //\%/%% # # * All command -v calls are followed by 2>/dev/null :) # # > It's important to note that it will never work with KSH88 !!! The # # default KSH used on AIX... :) # # * textFill : Default Value affectation error... & forget to use the # # _pattern variable... # # * rtrim: an error could appear during execution... Corrected with # # the new test F01.19 :) # # * ltrim: an error could appear during execution... Corrected with # # the new test F01.18 :) # # * isFunction : Modified error Message & the call with 'builtin' if # # under Ksh... builtin command -v --> command commnd -v # # + isNum : return true/false if the value is numeric or not. # # * testFill: if 3rd arg equal to TRUE, don't break the pattern to 1car # # + missingCommands : Exit if one command is missing (#22) # # + err2s(p) : Print message to stderr # # + _ltrim & _rtrim take a variable name instead of data. (#64) # # + _trim takes variable name instead of data. # # * __*sh are set to false and then to true. (#66) # # * missingCommands check if runnig onAIX to avoid stats check. (#67) # # * myDebug: prints messages to standard error. # # * logMe: Change the __ variable by __logme to avoid some strange # # behaviour under bash. When calling p2sp a double \n append. # # * fileCreate: I just replace touch by >. # # * If F01DEBUG is already set before the load of lib, it's lost ! # # Now, if already setted, the value is not lost ! # # * if __MYDEBUG is not defined, it's defined to 9. This variable is # # used to force the level at which the Debug is printed. # # * _p2sp: Internal change to avoid some conflict with exported __ vars.# # v0.32 [06/02/2015] Flyounet [@Home] : # # * Removing some old comments. # # + The checking part of the fileCheck function is FROZEN (and probably # # removed in the future, as not enough reliable). # # > fileCheck : Comments added about frozen zone # # + myDebug: If F01DEBUG @ 9 and in Bash mode, Stack Trace of function # # is added in the line printed. # # + getPidParent : To have the parent of the PID # # + getPidParents : To have the parents of the PID # # + getPidSons : To have all the Sons (and little sons) of the PID # # + getPidFamily : To have all Parents & sons of the PID # # * This versino was the last that support Ksh & Bash. The future # # version will only support Bash. # # v0.50 [??/??/2015] Flyounet [@Home] : # # * Merging external Bash extension # # * Removing Log Functions # # * Removing unused functions # # # # # F01VERSION=0.50 F01PROTOCOL=0.04 ############################################################################### # # # Todo : # # < iniGetValue and iniParseFile need an extra argument or a global variable # # to separate keyName and valueName. By default use :: # # <- rtrim & ltrim to be modified to only take variable name. # # <- trim to use new ltrim & rtrim # # < If the IFS is change before a call to myDebug,there is prb with date... # # # ############################################################################### # # # Legende : # # + --> Indique une nouveaute, un ajout de fonctionnalite. # # * --> Indique une correction de bogue. # # - --> Indique la suppression d'une fonctionnalite/variable. # # > --> Indique une information n'ayant pas forcement de rapport avec le code# # < --> Indique une amelioration a apporter au code. # # <- --> Indique une amelioration en cours de developpement/realisation. # # OK --> Indique qu'une amelioration a ete effectuee. # # # ############################################################################### # ############################################################################ # # Functions # ############################################################################ # #F01.00.06 #Function : _p2s(p), Print to screen (percent) string passed in argument #Syntaxe : _p2s(p) #Return : nothing #Notes : _p2s() { [[ ${__bash} -eq ${TRUE} ]] && builtin printf -- "${@}" || command printf -- "${@}" } _p2sp() { typeset __p2sp__="${@}"; _p2s "${__p2sp__//\%/%%}" } #F01.01.05 #Function : p2s(p), Print to screen (percent) string passed in argument (with an end of line) #Syntaxe : p2s(p) #Return : nothing #Notes : p2s() { _p2s "${@}\n" } p2sp() { _p2sp "${@}\n" } #F01.02.02 #Function : p2st, Print to screen string passed in argument, with Time before #Syntaxe : p2st #Return : nothing #Notes : p2st() { p2s "$(date '+%F %T')\n${@}" } #F01.03.02 #Function : oops, Print to screen string passed in argument, and exit 1 #Syntaxe : oops #Return : nothing #Notes : if __oops setted return __oops oops() { p2s "${@}" >&2 exit ${__oops:=1} } #F01.04.02 #Function : oopst, Print to screen string passed in argument, with time before, and exit 1 #Syntaxe : oopst #Return : nothing #Notes : if __oopst setted return __oopst oopst() { p2st "${@}" >&2 exit ${__oopst:=1} } #F01.05.11 #Function : myDebug, Print to screen string passed in argument if debug level is reach #Syntaxe : myDebug #Return : nothing #Notes : Dependent of __bash, F01DEBUG, F01STRACE myDebug() { if [ ${F01DEBUG:=0} -ge ${1} ]; then _debug="--\033[01;31mDEBUG\033[0m(\033[01;32m${1}\033[0m)----" shift if [ ${__bash} -eq ${TRUE} -a ${F01DEBUG} -eq 9 -a ${F01STRACE:=$TRUE} -eq ${TRUE} ]; then #_debug="${_debug}[$( ${__utsCmd} )][$(date '+%d/%m/%Y %H%M%S' )]--\033[02;37m${BASH_LINENO}-$( set -- "${FUNCNAME[@]}"; shift; echo ${@})\033[0m-${@}" _debug="${_debug}[$( ${__utsCmd} )][$(date '+%d/%m/%Y %H%M%S' )]--${@}--\033[02;37m$(set -- "${FUNCNAME[@]}"; shift 2; echo ${@})\033[0m" else _debug="${_debug}[$( ${__utsCmd} )][$(date '+%d/%m/%Y %H%M%S' )]----${@}" fi p2sp "${_debug}" >&2 fi } #F01.06.03 #Function : myError, Store error in variables #Syntaxe : myError #Return : nothing #Notes : Store last error in var __lastError and all errors in __allError myError() { myDebug ${__MYDEBUG} "myError(${@})" export __lastError="${@}" if [ ! -z "${@}" ]; then export __allError="[$(date '+%d/%m/%Y %H%M%S' )]${@}\n${__allError}" fi } #F01.07.05 #Function : fileCheck, Check file for presence and permission #Syntaxe : fileCheck [] #Return : 1=OK [fileName exists and permission are ok], 0=Fail #Notes : fileCheck() { myDebug ${__MYDEBUG} "fileCheck(${@})" if [ -z "${1}" ]; then myError "fileCheck: Filename is empty" return ${FALSE} fi if [ ! -f "${1}" ]; then myError "fileCheck: File doesn't exists are is not a file" return ${FALSE} fi ###### Cette partie est FROZEN ! DEBUT ##### if [ ! -z "${2}" ]; then if [ ${__cmdSTAT} -eq 0 ]; then myError "fileCheck: Command 'stat' is not available" return ${FALSE} fi __=$( stat -c'%a' "${1}" ) if [ "${__}" = "${2}" -o "${__}" = "0${2}" ]; then return ${TRUE} else myError "fileCheck: Rights error [${__} instead of ${2}]" return ${FALSE} fi fi ###### Cette partie est FROZEN ! FIN ##### return ${TRUE} } #F01.08.05 #Function : fileCreate, Create file with permissions if asked #Syntaxe : fileCreate [] #Return : 0=OK [fileName exists and permission are ok], 1=Fail #Notes : fileCreate() { myDebug ${__MYDEBUG} "fileCreate(${@})" if [ -z "${1:-}" ]; then myError "fileCreate: Filename is empty" return ${FALSE} fi #touch -- "${1}" 2>/dev/null (> "${1}") 2>/dev/null if [ $? -ne 0 ]; then myError "fileCreate: Can't touch file" return ${FALSE} fi if [ ! -z "${2:-}" ]; then chmod ${2} "${1}" 2>/dev/null if [ $? -ne 0 ]; then myError "fileCreate: Can't chmod" return ${FALSE} fi fi return ${TRUE} } #F01.09.02 #Function : fileDelete, Delete the specified file #Syntaxe : fileDelete #Return : 1=OK [fileName exists and permission are ok], 0=Fail #Notes : fileDelete() { myDebug ${__MYDEBUG} "fileDelete(${@})" if [ -z "${1}" ]; then myError "fileDelete: Filename is empty" return ${FALSE} fi rm -f -- "${1}" if [ $? -ne 0 ]; then myError "fileDelete: Can't remove file" return ${FALSE} fi return ${TRUE} } #F01.10.06 #Function : iniGetValue, Get the value from a specified INI file #Syntaxe : iniGetValue [] #Return : 1=OK, 0=Fail #Notes : Default way of working is to set __iniGetValue. If the third arg is # set the is set with the result. iniGetValue() { myDebug ${__MYDEBUG} "iniGetValue(${@})" fileCheck "${1}" if [ $? -ne ${TRUE} ]; then return ${FALSE} fi if [ -z "${2}" ]; then myError "iniGetValue: Variable name is empty" return ${FALSE} fi _findValue=0 while read _line; do if [ "x${_line//*$2*::*/$2}x" = "x${2}x" ]; then ltrim "${_line}" if [ "${__ltrim:0:1}" != '#' ]; then rtrim "${__ltrim%%::*}" _lvar="${__rtrim}" trim "${_line#*::}" #let _findValue=${_findValue}+1 (( _findValue=${_findValue}+1 )) if [ ${_findValue} -gt 1 ]; then myError "iniGetValue: Variable name found more than once" return ${FALSE} fi fi fi done < "${1}" if [ ${_findValue} -eq 0 ]; then myError "iniGetValue: Variable name not found" return ${FALSE} fi export __iniGetValue="${__trim}" if [ ! -z ${3} ]; then if [ "x${_lvar//[_a-zA-Z0-9]/}x" = "xx" -a "${_lvar: -1}" != "_" -a "${_lvar}" != "_" -a "${_lvar}" != "__" ]; then eval "export ${_lvar}='${__iniGetValue}'" else myError "iniGetValue: Variable name is unsafe to be set !" return ${FALSE} fi fi return ${TRUE} } #F01.11.06 #Function : iniParseFile, Set all values from a specified INI file #Syntaxe : iniParseFile #Return : 1=OK, 0=Fail #Notes : All non commented variables are setted if they are valid # : variable name MUST be in the Followinf Format : # : _?_?[0-9a-zA-Z][_0-9a-zA-Z]*[^_] iniParseFile() { myDebug ${__MYDEBUG} "iniParseFile(${@})" if [ -z "${1}" ]; then myError "iniParseFile: Filename is empty" return ${FALSE} fi _nbExportedVars=0 while read _line; do if [ ! -z "${_line}" -a "x${_line//*::*/::}x" = "x::x" ]; then ltrim "${_line}" if [ "${__ltrim:0:1}" != '#' ]; then rtrim "${_line%%::*}" _lvar="${__rtrim}" if [ "x${_lvar//[_a-zA-Z0-9]/}x" = "xx" -a "${_lvar: -1}" != "_" -a "${_lvar}" != "_" -a "${_lvar}" != "__" ]; then trim "${_line#*::}" eval "export ${_lvar}='${__trim}'" (( _nbExportedVars=${_nbExportedVars}+1 )) fi fi fi done < "${1}" return ${_nbExportedVars} } #F01.12a.01 #Function : _trim, Remove all blank from begining and end #Syntaxe : _trim #Return : N/A #Notes : Get data from Variable Name given as Arguement and re-set this variable # : All catacters \t, \n, \r and space are removed. _trim() { myDebug ${__MYDEBUG} "_trim(${@})" __="${1}" _ltrim "${1}" _rtrim "${1}" unset __ } #F01.12b.05 #Function : trim, Remove all blank from begining and end #Syntaxe : trim #Return : 1=OK #Notes : export the trimmed variable in __trim. # : All catacters \t, \n, \r and space are removed. # : If we had use sed : __trim=$( sed -e 's/^[[:space:]]*//g' -e 's/[[:space:]]*$//g' <<<"${@}" ) trim() { myDebug ${__MYDEBUG} "trim(${@})" __trim="${@}" _trim "__trim" return ${TRUE} } #F01.13.05 #Function : logRotate, Transfer the begining of a file to the rotationned version. #Syntaxe : logRotate #Return : 1=OK, 0=Fail #Notes : Log rotation couldn't be under 10 lines #Notes : The rotated log file are suffixed by the date of day. logRotate() { myDebug ${__MYDEBUG} "logRotate(${@})" fileCheck "${1}" if [ ${?} -ne ${TRUE} ]; then myError "logRotate: can't find logfile" return ${FALSE} fi if [ -z "${2}" -o ${2:-0} -lt 10 ]; then _maxLine=10 else _maxLine=${2} fi _lines=$( wc -l < "${1}" ) (( _linesToDrop=${_lines}-${_maxLine}+1 )) if [ ${_lines} -gt ${_maxLine} ]; then head -${_linesToDrop} "${1}" >> "${1}.$( date '+%Y%m%d' )" if [ $? -ne 0 ]; then myError "logRotate: can't transfer head lines" return ${FALSE} fi sed -i "1,${_linesToDrop}d" "${1}" if [ $? -ne 0 ]; then myError "logRotate: can't delete head lines" return ${FALSE} fi fi return ${TRUE} } #F01.14.06 #Function : logMe, Send the log to the log files #Syntaxe : logMe #Return : 1=OK #Notes : Even if the log fail, it returns 1 #Notes : Log are systematically rotated before writting. #Notes : Log are systematically sent into the verbose log. #Notes : Variables __cmdPERL, __logVerbose, __logDir, __logFile, __logFileV, # __logFileSize, __logFileVSize must be defined before the call. logMe() { myDebug ${__MYDEBUG} "logMe(${@})" typeset __logme="[$( ${__utsCmd} )][$(date '+%d/%m/%Y %H%M%S' )] --> ${@}" if [ -z "${__logVerbose}" ]; then logRotate "${__logDir}/${__logFile}" ${__logFileSize} p2sp "${__logme}" >> "${__logDir}/${__logFile}" fi logRotate "${__logDir}/${__logFileV}" ${__logFileVSize} p2sp "${__logme}" >> "${__logDir}/${__logFileV}" return ${TRUE} } #F01.15.01 #Function : logMeV, Send the log to the verbose log files #Syntaxe : logMeV #Return : 1=OK #Notes : Even if the log fail, it returns 1 logMeV() { myDebug ${__MYDEBUG} "logMeV(${@})" export __logVerbose=1 logMe "${@}" unset __logVerbose return ${TRUE} } #F01.16.07 #Function : isFunction, Verify that the function exists #Syntaxe : isFunction [<1>] #Return : 1=OK, 0=Fail #Notes : Set the 2nd arg to check either programme or function isFunction() { myDebug ${__MYDEBUG} "isFunction(${@})" if [ -z "${1}" ]; then myError "isFunction: Function name is empty" return ${FALSE} fi __="$([[ ${__bash} -eq ${TRUE} ]] && builtin command -v "${1}" 2>/dev/null || command command -v "${1}" 2>/dev/null)" if [ "${1}" = "${__}" ]; then return ${TRUE} elif [ ! -z "${2}" ]; then if [ "${1}" = "${__##*/}" ]; then return ${TRUE} else myError "isFunction: Function name, builtin or programme is unknown" return ${FALSE} fi else myError "isFunction: Function name or builtin is unknown" return ${FALSE} fi } #F01.17.08 #Function : sprintf, return a formatted string #Syntaxe : sprintf #Return : 1=OK #Notes : __sprintf contains the result of the sprintf call sprintf() { myDebug ${__MYDEBUG} "sprintf(${@})" __=${#} __sprintf="${1}" shift i=1 while [ $i -ne ${__} ]; do __sprintf="${__sprintf%%%s*}${1}${__sprintf#*%s}" #let i=$i+1 (( i=$i+1 )) shift done export __sprintf return ${TRUE} } sprintfv2() { myDebug ${__MYDEBUG} "sprintfv2(${@})" _tmp="${1}" shift export ${_tmp}="$(_p2s "${@}" 2>/dev/null)" return ${TRUE} } #F01.18b.01 #Function : _ltrim, Remove all blank from begining #Syntaxe : _ltrim #Return : N/A #Notes : Get data from Variable Name given as Arguement and re-set this variable # : All catacters \t, \n, \r and space are removed. _ltrim () { myDebug ${__MYDEBUG} "_ltrim(${@})" if [ -z "${1:-}" ]; then myError "_ltrim: Variable name empty" elif [ ${__bash} -eq ${TRUE} -a "x${__BASH_EXTENSION}" = 'xloaded' ]; then _ltrimBash "${@}" else eval _local="\${${1}}" if [ ! -z "${_local}" ]; then while [ "x${_local:0:1}" = "x " -o "x${_local:0:1}" = "x " -o "x${_local:0:1}" = "x\n" -o "x${_local:0:1}" = "x\r" -o "x${_local:0:1}" = 'x ' ]; do _local="${_local:1}" done eval export "${1}"='${_local}' unset _local fi fi } #F01.18a.06 #Function : ltrim, Remove all blank from begining #Syntaxe : ltrim #Return : 1=OK #Notes : export the ltrimmed variable in __ltrim # : All catacters \t, \n, \r and space are removed. ltrim() { myDebug ${__MYDEBUG} "ltrim(${@})" __ltrim="${@}" _ltrim "__ltrim" return ${TRUE} } #F01.19b.01 #Function : _rtrim, Remove all blank from end #Syntaxe : _rtrim #Return : N/A #Notes : Get data from Variable Name given as Arguement and re-set this variable # : All catacters \t, \n, \r and space are removed. _rtrim () { myDebug ${__MYDEBUG} "_rtrim(${@})" if [ -z "${1:-}" ]; then myError "_rtrim: Variable name empty" elif [ ${__bash} -eq ${TRUE} -a "x${__BASH_EXTENSION}" = 'xloaded' ]; then _rtrimBash "${@}" else eval _local="\${${1}}" if [ ! -z "${_local}" ]; then while [ "x${_local: -1}" = "x " -o "x${_local: -1}" = "x " -o "x${_local: -1}" = "x\n" -o "x${_local: -1}" = "x\r" -o "x${_local: -1}" = 'x ' ]; do #let __=${#_local}-1 (( __=${#_local}-1 )) _local="${_local:0:$__}" done eval export "${1}"='${_local}' unset _local fi fi } #F01.19a.05 #Function : rtrim, Remove all blank from end #Syntaxe : rtrim #Return : 1=OK #Notes : export the rtrimmed variable in __rtrim # : All catacters \t, \n, \r and space are removed. rtrim() { myDebug ${__MYDEBUG} "rtrim(${@})" __rtrim="${@}" _rtrim "__rtrim" return ${TRUE} } #F01.20.01 #Function : _str2lower, lower all characters #Syntaxe : _str2lower #Return : 1=OK #Notes : export the text variable in __str2lower # : Just because this fucking KSH doesn't yet support the Case modification like Bash _str2lower() { myDebug ${__MYDEBUG} "_str2lower(${@})" _alphaHigh="ABCDEFGHIJKLMNOPQRSTUVWXYZ" _alphaLow="abcdefghijklmnopqrstuvwxyz" _incr=0 __str2lower="${@}" while [ $_incr -ne ${#_alphaHigh} ]; do _upper=${_alphaHigh:$_incr:1} _lower=${_alphaLow:$_incr:1} __str2lower="${__str2lower//$_upper/$_lower}" (( _incr=${_incr}+1 )) done export __str2lower return ${TRUE} } #F01.21.01 #Function : _str2upper, upper all characters #Syntaxe : _str2upper #Return : 1=OK #Notes : export the text variable in __str2upper # : Just because this fucking KSH doesn't yet support the Case modification like Bash _str2upper() { myDebug ${__MYDEBUG} "_str2upper(${@})" _alphaHigh="ABCDEFGHIJKLMNOPQRSTUVWXYZ" _alphaLow="abcdefghijklmnopqrstuvwxyz" _incr=0 __str2upper="${@}" while [ $_incr -ne ${#_alphaHigh} ]; do _upper=${_alphaHigh:$_incr:1} _lower=${_alphaLow:$_incr:1} __str2upper="${__str2upper//$_lower/$_upper}" (( _incr=${_incr}+1 )) done export __str2upper return ${TRUE} } #F01.22.03 #Function : textFill, Create a text filled by the caracter #Syntaxe : textFill [] #Return : 1=OK #Notes : export the text variable in __textFill # : If 3rd value is $TRUE, don't shrink the pattern textFill() { myDebug ${__MYDEBUG} "textFill(${@})" _pattern="${1:- }" if [ ${#_pattern} -gt 1 -a ${3:-$FALSE} -eq ${FALSE} ]; then _pattern="${_pattern:0:1}"; fi __textFill='' _incr=0 while [ ${_incr} -lt ${2:-10} ]; do __textFill="${__textFill}${_pattern}" (( _incr=${_incr}+1 )) done export __textFill return ${TRUE} } #F01.23.04 #Function : textBox, Create a box around the text #Syntaxe : textBox <(left|center|right)> #Return : 1=OK #Notes : export the text variable in __textBox # : All catacters \t, \n, \r and space are removed. # : When used with Bash the function _textBox4Bash is called. textBox() { myDebug ${__MYDEBUG} "textBox(${@})" # if only KSH support <(cmd) for the while; do ; done < like Bash if [ ${__bash} -eq ${TRUE} ]; then if [ "x${__BASH_EXTENSION}" = 'xloaded' ]; then case "${#}" in 1) _textBox4Bash "${1}" ;; 2) _textBox4Bash "${1}" "${2}" ;; 3) _textBox4Bash "${1}" "${2}" "${3}" ;; esac return ${TRUE} else myError "textBox: Bash Extention is not loaded ! Can't call _textBox4Bash. Aborting..." export __textBox="${1}" return ${FALSE} fi fi _max=0 # if only KSH supoprt Case modificatino like Bash # if [ ! -z "${3}"]; then _align="${3}"; _align="${_align,,}"; else _align="left"; fi if [ ${#} -gt 2 ]; then _str2lower "${3}" _align="${__str2lower}" else _align="left" fi eval $( p2s "${1}" | while read _string; do if [ ${#_string} -gt ${_max} ]; then export _max=${#_string}; fi p2s "_max=${_max};" done ) #let _maxRow=${_max}+4 (( _maxRow=${_max}+4 )) _padding="${2}" __textBox='' p2sp "${1}" | while read _string; do _subString="" case "${_align}" in center) #let "_padLeft=(${_max}-${#_string})/2" (( _padLeft=(${_max}-${#_string})/2 )) #let _padRight=${_max}-${#_string}-${_padLeft} (( _padRight=${_max}-${#_string}-${_padLeft} )) textFill ' ' ${_padLeft} _subString="${_padding} ${__textFill}${_string}" textFill ' ' ${_padRight} _subString="${_subString}${__textFill} ${_padding}" ;; left|right|*) #let _pad=${_max}-${#_string} (( _pad=${_max}-${#_string} )) textFill ' ' ${_pad} if [ "${_align}" = "right" ]; then _subString="${_padding} ${__textFill}${_string} ${_padding}" else _subString="${_padding} ${_string}${__textFill} ${_padding}" fi ;; esac __textBox="${__textBox}${_subString}\n" done textFill "${2}" ${_maxRow} __textBox="${__textFill}\n${__textBox}${__textFill}" export __textBox return ${TRUE} } #F01.24.09 #Function : parseHeadersForHelp, Print headers of function for a given file #Syntaxe : parseHeadersForHelp [fn] [s|search ] #Return : 1=OK, O=FAIL #Notes : fn argument just return the function name # : s or search argument just return the function when name is matching (case sensitive) # : is or isearch argument just return the function when name is matching (case insensitive) # : Headers must begin with #F??. (where ?? are two characters), # : and each line after must begin with a #. parseHeadersForHelp() { myDebug ${__MYDEBUG} "parseHeadersForHelp(${@})" _onlyFunctionName=0; _searchFunction=0; _searchFunctionName='' _fileName="${1}" shift fileCheck "${_fileName}" if [ ${?} -ne ${TRUE} ]; then oops "Can't open/read File '${_fileName}' (error: ${__lastError})" fi while [ $# -ne 0 ]; do _str2lower "${1}" if [ ${_searchFunction} -ge 1 -a ${_searchFunction} -le 2 -a -z "${_searchFunctionName}" ]; then _searchFunctionName="${1}" elif [ "x${__str2lower}x" = 'xfnx' ]; then _onlyFunctionName=1 elif [ "x${__str2lower}x" = 'xsx' -o "x${__str2lower}x" = 'xsearchx' ]; then _searchFunction=1 elif [ "x${__str2lower}x" = 'xisx' -o "x${__str2lower}x" = 'xisearchx' ]; then _searchFunction=2 else myError "parseHeadersForHelp: Argument '${1}' is unknown !" fi shift done if [ -z "${_searchFunctionName}" ]; then _searchFunction=0 fi _beginBlock=0 _forceEndBlock=0 while read a; do if [ "x${a:0:2}x" = 'x#Fx' -a "x${a:4:1}x" = 'x.x' ]; then _beginBlock=1 _headers="\033[01;31m${a}\033[0m\n" elif [ "x${a:0:1}x" = 'x#x' -a ${_beginBlock} -eq 1 ]; then #_str2lower "${a}" #if [ ${_searchFunction} -ge 1 -a ${_searchFunction} -le 2 -a "x${__str2lower%% : *}x" = 'x#functionx' ]; then if [ ${_searchFunction} -ge 1 -a ${_searchFunction} -le 2 -a "x${a%% : *}x" = 'x#Functionx' ]; then if [ ${_searchFunction} -eq 2 ]; then b="${a}" _str2lower "${a}" export a="${__str2lower}" _str2lower "${_searchFunctionName}" export _searchFunctionName="${__str2lower}" fi if [ "x${a//*$_searchFunctionName*/$_searchFunctionName}x" != "x${_searchFunctionName}x" ]; then _beginBlock=0 fi if [ ${_searchFunction} -eq 2 ]; then a="${b}" unset b fi fi if [ ${_beginBlock} -eq 1 ]; then #_str2lower "${a}" if [ ${_onlyFunctionName} -eq 0 ]; then _headers="${_headers}${a}\n" #elif [ "x${__str2lower%% : *}x" = 'x#functionx' ]; then elif [ "x${a%% : *}x" = 'x#Functionx' ]; then _headers="${_headers}${a}\n" fi fi elif [ ${_beginBlock} -eq 1 -o ${_forceEndBlock} -eq 1 ]; then _beginBlock=0 _forceEndBlock=0 p2sp "${_headers}" fi done < "${_fileName}" } #F01.25.05 #Function : statusBar, Print (or return) datas to make a status bar #Syntaxe : statusBar [] #Return : 1=OK #Notes : export the text variable in __statusBar # : Instead of having multi variable exported only the one as second arg is set # : If third argument is set nothing is printed # : __statusBarPercent2Print (Global) is could be set before call export __statusBarPercent2Print=5 statusBar() { myDebug ${__MYDEBUG} "statusBar(${@})" _globalVariableName="${2}" __statusBar='' if [ ${1} -eq 0 ]; then __statusBar='0' _statusBarPrevious=0 _statusBarNextLevel=${__statusBarPercent2Print} _statusBarInitComplete=0 elif [ ${1} -gt 100 ]; then set -- 100 "${_globalVariableName}" else eval _tmp=\$${_globalVariableName} _statusBarPrevious=${_tmp//::*} __statusBarPercent2Print=${_tmp//*::} _tmp=${_tmp#*::}; _statusBarNextLevel=${_tmp//::*} #myDebug 6 "\n${_statusBarPrevious}-${_statusBarNextLevel}-${__statusBarPercent2Print}" fi while [ ${1} -gt ${_statusBarPrevious} ]; do if [ ${1} -lt ${_statusBarNextLevel:=$__statusBarPercent2Print} ]; then #let __=${1}-${_statusBarPrevious} (( __=${1}-${_statusBarPrevious} )) #let _statusBarPrevious=${_statusBarPrevious}+${__} (( _statusBarPrevious=${_statusBarPrevious}+${__} )) textFill '.' ${__} __statusBar="${__statusBar}${__textFill}" elif [ ${1} -eq ${_statusBarNextLevel} ]; then textFill '.' $((${1}-${_statusBarPrevious}-1)) __statusBar="${__statusBar}${__textFill}${_statusBarNextLevel}" _statusBarPrevious=${_statusBarNextLevel} (( _statusBarNextLevel=${_statusBarNextLevel}+${__statusBarPercent2Print} )) else textFill '.' $((${_statusBarNextLevel}-${_statusBarPrevious}-1)) __statusBar="${__statusBar}${__textFill}${_statusBarNextLevel}" _statusBarPrevious=${_statusBarNextLevel} (( _statusBarNextLevel=${_statusBarNextLevel}+${__statusBarPercent2Print} )) fi done if [ ${_statusBarInitComplete:=0} -eq 0 -o ${1} -gt 1 ]; then export _statusBarInitComplete=1 export __statusBar if [ -z "${3}" ]; then printf -- "${__statusBar}" fi if [ ${1} -lt 100 ]; then export eval "${_globalVariableName}=${_statusBarPrevious}::${_statusBarNextLevel}::${__statusBarPercent2Print}" fi else export __statusBar='' fi } #F01.26.01 #Function : randomString, Return a string containing random data #Syntaxe : randomString "" #Return : 1=OK, 0=format unknown #Notes : export the text variable in $varName # : Format : 1st digit : value betwen 0-9 # : Format : 2sd digit : value betwen a-z # : Format : 3rd digit : value betwen A-Z # : It suppose /dev/urandom exists and tr & head available randomString() { myDebug ${__MYDEBUG} "randomString(${@})" _s='' if [ "x${1}" = 'x000' -o ${#1} -ne 3 ]; then myError "randomString: Format error : '${1}' !" return ${FALSE} fi if [ ${2} -lt 1 ]; then myError "randomString: Length is too short !" return ${FALSE} fi if [ -z "${3}" ]; then myError "randomString: Variable name is empty !" return ${FALSE} fi if [ ${1:0:1} -eq 1 ]; then _s="${_s}0-9" fi if [ ${1:1:1} -eq 1 ]; then _s="${_s}a-z" fi if [ ${1:2:1} -eq 1 ]; then _s="${_s}A-Z" fi eval "export ${3}=$( #Return : nothing #Notes : _e2s() { [[ ${__bash} -eq ${TRUE} ]] && builtin echo -n "${@}" || command echo -n "${@}" } #F01.28.02 #Function : e2s, echo to screen string passed in argument (with an end of line) #Syntaxe : e2s #Return : nothing #Notes : Usefull when you have to print something with percent symbol % e2s() { [[ ${__bash} -eq ${TRUE} ]] && builtin echo "${@}" || command echo "${@}" } #F01.29.01 #Function : isNum, return True if the value is numeric #Syntaxe : isNum #Return : nothing #Notes : The second argument force to be less permissive isNum() { myDebug ${__MYDEBUG} "isNum(${@})" if [ -z "${1:-}" ]; then return ${FALSE}; fi if [ "x${2:-$FALSE}" = "x${FALSE}" ]; then if [ "${1//[^-+.,0-9]/}" = "${1}" ]; then return ${TRUE}; fi else if [ "${1//[^0-9]/}" = "${1}" ]; then return ${TRUE}; fi fi return ${FALSE} } #F01.30.03 #Function : missingCommands, Verify if needed command are existing, else quit #Syntaxe : missingCommands #Return : nothing #Notes : this function check either programme (binaries) or function # : this function has been imported from megaGetDLoad.sh missingCommands () { myDebug ${__MYDEBUG} "missingCommands(${@})" if [ -z "${1:-}" ]; then return ${FALSE}; fi for neededCommand in ${1:-}; do if ! isFunction "${neededCommand}" 1; then missingCommands="${missingCommands:=} ${neededCommand}" fi done if [ ! -z "${missingCommands:=}" ]; then err2sp "List of command(s) not in PATH: (${missingCommands} )\nAborting..." exit 255 fi } #F01.31.01 #Function : err2s(p), Print to screen (percent) string passed in argument (with an end of line) on stderr #Syntaxe : err2s(p) #Return : nothing #Notes : err2s () { myDebug ${__MYDEBUG} "err2s(${@})" p2s "${@}" >&2 } err2sp () { myDebug ${__MYDEBUG} "err2sp(${@})" p2sp "${@}" >&2 } #F01.32.01 #Function : getPidParent, Find the Parent of the given PID #Syntaxe : getPidParent #Return : nothing #Notes : getPidParent () { myDebug ${__MYDEBUG} "getPidParent(${@})" eval export "${2}"='$(ps --no-header -o ppid -p ${1})' } #F01.33.01 #Function : getPidParents, Find the Parents of the given PID #Syntaxe : getPidParent #Return : nothing #Notes : Force __includeInit to TRUE to include Init Father getPidParents () { myDebug ${__MYDEBUG} "getPidParents(${@})" _myLocalParents=${1} while [ ! -z "${_myLocalParents}" -a ${_myLocalParents} -ne 1 ]; do getPidParent ${_myLocalParents} '_myLocalParents' if [ ${_myLocalParents} -ne 1 -o ${__includeInit:=$FALSE} -eq ${TRUE} ]; then eval export "${2}"="'$(eval echo "\$${2}") ${_myLocalParents}'" fi done } #F01.34.01 #Function : getPidSons, Find the Sons of the given PID #Syntaxe : getPidParent #Return : nothing #Notes : getPidSons () { myDebug ${__MYDEBUG} "getPidSons(${@})" _myLocalSons="$(ps --no-header -o pid --ppid ${1})" export _mySonsParsed="${_mySonsParsed:= }" for _pid in ${_myLocalSons:= }; do if [ "x${_mySonsParsed//* $_pid */$_pid}" != "x${_pid}" ]; then export _mySonsParsed="${_mySonsParsed:=}${_pid} " getPidSons ${_pid} '_myLocalSons' fi done eval export "${2}"='${_mySonsParsed}' } #F01.35.02 #Function : getPidFamily, Find the All the Familly of a PID (include this PID) #Syntaxe : getPidFamily #Return : nothing #Notes : getPidFamily () { myDebug ${__MYDEBUG} "getPidFamily(${@})" getPidParents ${1} '_getPidFamily' _trim '_getPidFamily' if [ -z "${_getPidFamily}" ]; then _ancestor=${1} else _ancestor=${_getPidFamily##* } fi getPidSons ${_ancestor} "${2}" eval export "${2}"='"${_ancestor} $(eval echo "\$${2}")"' } #F01.36.01 #Function : cryptContent, crypt the stream with openssl or rot13like #Syntaxe : cryptContent #Return : nothing #Notes : You SHOULD change the change _saltKey variable before calling this function. cryptContent () { myDebug ${__MYDEBUG} "cryptContent(${@})" if isFunction 'openssl' 1; then cat | openssl aes-256-cbc -a -salt -k "${_saltKey:=LeSaucissonCestBonPourLesBoutons}" else cat | tr 'a-zA-Z0-9' 'N-ZA-Mn-za-m5-90-4' fi } #F01.36.01 #Function : decryptContent, decrypt the stream with openssl or rot13like #Syntaxe : decryptContent [] #Return : nothing #Notes : You SHOULD change the change _saltKey variable before calling this function. # : And of course, use the same as when you called the cryptContent function. decryptContent () { myDebug ${__MYDEBUG} "decryptContent(${@})" #if isFunction 'openssl' 1 -a "${1:-}" != 'rot' ; then if isFunction 'openssl' 1; then cat | openssl aes-256-cbc -a -d -k "${_saltKey:=LeSaucissonCestBonPourLesBoutons}" elif [ "${1:-}" = 'openssl' ]; then cat | openssl aes-256-cbc -a -d -k "${_saltKey:=LeSaucissonCestBonPourLesBoutons}" else cat | tr 'N-ZA-Mn-za-m5-90-4' 'a-zA-Z0-9' fi } # ############################################################################ # # Library related Functions # ############################################################################ # #F01.99.05 #Function : F01Version, Return/Print version information #Syntaxe : F01Version [<1>] #Return : 1=OK #Notes : __F01Version contains the result F01Version() { myDebug 1 "F01Version(${1})" _rev='$Revision$' export __F01Version="common.lib v${F01VERSION} / p${F01PROTOCOL} [${_rev}]" if [ "x${BASH_VERSION}" != "x" -a "x${KSH_VERSION}" = "x" ]; then __F01Version="${__F01Version} (with Bash extension : ${__BASH_EXTENSION_LOCATION})" fi if [ -z "${1}" ]; then p2s "${__F01Version}"; fi return ${TRUE} } # ############################################################################ # # Variables Initialisation # ############################################################################ # # Debug Variables F01DEBUG=${F01DEBUG:=0} # Forced to be Level 0, if not defined __MYDEBUG=${__MYDEBUG:=9} # Forced to be Level 9, if not defined # Boolean definition export FALSE=1 # An Integer export TRUE=0 # An Integer export NULL='00' # ! A String ! # In some earlier version of Date, we could use the %s # Verify presence of Perl if [ "$(date "+%s" 2>/dev/null)" != "%s" ]; then __utsCmd="date +%s" elif [ -z "$(command -v perl 2>/dev/null)" ]; then __utsCmd="perl -e 'print time();'" else __utsCmd=''; fi; export __utsCmd # Verify presence of stat if [ -z "$(command -v stat 2>/dev/null)" ]; then export __cmdSTAT=0; else export __cmdSTAT=1; fi # Check and Set : Bash or Ksh or Zsh export __bash=${FALSE}; export __ksh=${FALSE}; export __zsh=${FALSE}; if [ "x${BASH_VERSION}" != "x" ]; then export __bash=${TRUE} elif [ "x${KSH_VERSION}" != "x" ]; then export __ksh=${TRUE} elif [ "x${ZSH_VERSION}" != "x" ]; then export __zsh=${TRUE}; fi # Initialize Default Log Variables export __logDir="${__logDir:=/tmp}" export __logFile="${__logFile:=logFile.log}" export __logFileV="${__logFileV:=logFileV.log}" export __logFileSize="${__logFileSize:=21600}" # 60 hours with 1 line/sec export __logFileVSize="${__logFileVSize:=43200}" # 120 hours with 1 line/sec #if [ -z "${__logDir}" ]; then export __logDir='/tmp'; fi #if [ -z "${__logFile}" ]; then export __logFile='logFile.log'; fi #if [ -z "${__logFileV}" ]; then export __logFileV='logFileV.log'; fi #if [ -z "${__logFileSize}" ]; then export __logFileSize=21600; fi # 60 hours with 1 line/sec #if [ -z "${__logFileVSize}" ]; then export __logFileVSize=43200; fi # 120 hours with 1 line/sec # As Prerequisites for Bash the subLibrary _common4bash.lib is needed # But it will not stop your program if not loaded if [ ${__bash} -eq ${TRUE} ]; then if [ ${BASH_VERSINFO[0]} -lt 4 -a ${BASH_VERSINFO[1]} -lt 3 -a ${BASH_VERSINFO[2]} -lt 26 ]; then # Due to some limitations with Bash 3.2.25 and inferior, I don't load it __BASH_EXTENSION_LOCATION='Not Supported ! Bash too old.' else if [ -f "${BASH_SOURCE%/*}/_common4bash.lib" ]; then . "$(cd ${BASH_SOURCE%/*}; pwd)/_common4bash.lib" export __BASH_EXTENSION_LOCATION="$(cd ${BASH_SOURCE%/*}; pwd)/_common4bash.lib" elif [ -f "${0%/*}/_common4bash.lib" ]; then . "${0%/*}/_common4bash.lib" export __BASH_EXTENSION_LOCATION="${0%/*}/_common4bash.lib" elif [ -f "${0%/*}/../_common4bash.lib" ]; then . "${0%/*}/../_common4bash.lib" export __BASH_EXTENSION_LOCATION="${0%/*}/../_common4bash.lib" elif [ -f "${0%/*}/include/_common4bash.lib" ]; then . "${0%/*}/include/_common4bash.lib" export __BASH_EXTENSION_LOCATION="${0%/*}/include/_common4bash.lib" elif [ -f "${0%/*}/lib/_common4bash.lib" ]; then . "${0%/*}/lib/_common4bash.lib" export __BASH_EXTENSION_LOCATION="${0%/*}/lib/_common4bash.lib" elif [ -f "${0%/*}/prereq/_common4bash.lib" ]; then . "${0%/*}/prereq/_common4bash.lib" export __BASH_EXTENSION_LOCATION="${0%/*}/prereq/_common4bash.lib" elif [ -f "${0%/*}/prereqs/_common4bash.lib" ]; then . "${0%/*}/prereqs/_common4bash.lib" export __BASH_EXTENSION_LOCATION="${0%/*}/prereqs/_common4bash.lib" else export __BASH_EXTENSION_LOCATION='Not Found !' fi fi fi # Have a look for Missing Commands used internally if [ ${__zsh} -ne ${TRUE} ]; then if [ "x$(uname -s)" != "xAIX" ]; then missingCommands "stat" fi missingCommands "printf echo head sed chmod rm tr wc" fi # +---------------------------------------------------------------------------+ # # | Last subversion informations : # | $URL$ # | $Revision$ : $Date$ # | $Author$ # +---------------------------------------------------------------------------+ #