#!/usr/bin/env bash :<<'__comments__' Name: localinstall Usage: See show_usage() Synopsis: localinstall is a tool that invokes scripts which configure, build, install, manage and remove software outside the RPM package management system on this host. Worker scripts in LIBEXEC_PATH must be started from this script. Author: G. D. LaBossiere, Xview Solutions Inc. Release: 2 Date: 2024-04-04 RCS: $Id$ License: GNU GPL v3 __comments__ #------------------------------------------------------------------------------ # bash environment #------------------------------------------------------------------------------ # BASH_VERSINFO[@] # EXEC_NAME # EXEC_PID # FUNCNAME[@] #------------------------------------------------------------------------------ # constants #------------------------------------------------------------------------------ BASE_PATH="/opt/noc1/localinstall" # exported to worker scripts LIBEXEC_PATH="${BASE_PATH}/libexec" #------------------------------------------------------------------------------ # error codes #------------------------------------------------------------------------------ ERROR_10="Requires bash 4.2+" ERROR_15="Missing required program(s)" ERROR_16="Missing required function(s)" ERROR_21="Incorrect file permission(s)" ERROR_22="Required file(s) not found" ERROR_34="Bad or missing filename" ERROR_35="Bad file content, format, syntax or type" ERROR_255="Called program error or user interrupt" #------------------------------------------------------------------------------ # variables #------------------------------------------------------------------------------ argList=() errFuncName="" execTarget="" exitMessage="" listFiles="" #------------------------------------------------------------------------------ :<<'__function_calls__' main─┐ ├─exit_handler─┐ │ └─show_usage ├─get_input ├─list_files ├─exec_target └─show_usage __function_calls__ #------------------------------------------------------------------------------ # functions #------------------------------------------------------------------------------ :<<'__comments__' Name: exec_target Synopsis: Set and export the bash envars EXEC_NAME and EXEC_PID read-only; exec global execTarget with the arguments in global argList[@]; if exec is successful this program will be replaced by execTarget in the process table and execution will continue. Globals: EXEC_NAME, EXEC_PID, FUNCNAME, argList[@], errFuncName, execTarget, exitMessage Returns: 0 if execTarget is not set; $errFuncName, $exitMessage and exit 21, 22, 35 or 255 on error. __comments__ exec_target() { [[ $execTarget ]] || return 0 errFuncName="$FUNCNAME" [[ -f $execTarget ]] || { exitMessage="${execTarget} was not found." exit 22 } [[ -x $execTarget ]] || { exitMessage="${execTarget} is not executable." exit 21 } local shebang read shebang <${execTarget} [[ $shebang =~ 'bash' ]] || { exitMessage="'${execTarget}' is not a bash script." exit 35 } # EXEC_NAME must be set or execTarget will not run declare -grx EXEC_NAME="${0##*/}" # EXEC_PID value and execTarget $$ value must match or execTarget will not run declare -girx EXEC_PID="$$" # argList[@] will be unset (empty) if we are running as a cgi process exec ${execTarget} "${argList[@]}" exitMessage="Failed to exec '${execTarget}'" exit 255 } #------------------------------------------------------------------------------ :<<'__comments__' Name: exit_handler Synopsis: If $? is non-zero print a message; also call show_usage() if the value of $? is 22 or 34; the first statement to appear in main() must be: trap exit_handler EXIT Globals: errFuncName, exitMessage Calls: show_usage Returns: 0 on normal exit; $? on error. __comments__ exit_handler() { local errNum="$?" [[ $errNum -eq 0 ]] && return 0 local errMsg errTxt errTxt="ERROR_${errNum}" errMsg="Error ${errNum}: No description available" [[ ${!errTxt} ]] && errMsg="Error ${errNum}: ${!errTxt}" [[ ${errFuncName} ]] && errMsg="${errFuncName}: ${errMsg}" errMsg="${0##*/}: ${errMsg}" [[ $exitMessage ]] && printf '%s\n' "${exitMessage}" printf '%s\n' "${errMsg}" [[ $errNum -eq 34 || $errNum -eq 22 ]] && show_usage return $errNum } #------------------------------------------------------------------------------ :<<'__comments__' Name: get_input Synopsis: Read input from the command line; set argList[@]; parse argList[0]; set globals or return error. Globals: FUNCNAME[@], LIBEXEC_PATH, argList[@], errFuncName, execTarget, exitMessage, listFiles Returns: 0 on success; $errFuncName, $exitMessage and exit 34 on error. __comments__ get_input() { [[ ${argList[@]} ]] || return 0 errFuncName="$FUNCNAME" [[ ${argList[0]} =~ ^list$ ]] && listFiles="true" && return 0 [[ ${argList[0]} =~ \ ^[0-9a-zA-Z_]{1}[0-9a-zA-Z_\.\-]{1,}[0-9a-zA-Z_\.]{1}$ ]] && \ execTarget="${LIBEXEC_PATH}/${argList[0]}" || { exitMessage="'${argList[0]}' is not a valid file name." exit 34 } unset argList[0] return 0 } #------------------------------------------------------------------------------ :<<'__comments__' Name: list_files Synopsis: List files in LIBEXEC_PATH. Globals: FUNCNAME[@], LIBEXEC_PATH, errFuncName, listFiles Requires: ls Returns: 0 on success; errFuncName and exit 15 on error. __comments__ list_files() { [[ $listFiles ]] || return 0 errFuncName="$FUNCNAME" type -p ls &>/dev/null || exit 15 local i list readarray -t list <<< "$(ls -1 ${LIBEXEC_PATH})" printf '%b' " ------------------------------------------------------------------------------- Usage: ${0##*/} NAME [ args ] NAME must be one of the following: " for ((i=0;i<${#list[@]};i++)); do printf '%-8s%s\n' "" "${list[$i]}" done printf '%b' " ------------------------------------------------------------------------------- " return 0 } #------------------------------------------------------------------------------ :<<'__comments__' Name: show_usage Synopsis: Display program usage. Globals: FUNCNAME[@], LIBEXEC_PATH, errFuncName, listFiles Returns: 0 in all cases. __comments__ show_usage() { [[ $listFiles ]] && return 0 errFuncName="$FUNCNAME" printf '%b' " ------------------------------------------------------------------------------- ${0##*/} is a tool that invokes scripts which configure, build, install, manage and remove software on this host outside the RPM package management system. License is GNU GPL v3 Usage: ${0##*/} NAME [ args ] If NAME is an executable file present in ${LIBEXEC_PATH} then exec NAME and pass it the environment and any required arguments. If NAME is 'list' display the files in ${LIBEXEC_PATH} If NAME is missing, invalid or unrecognized then display this message. ------------------------------------------------------------------------------- " return 0 } #------------------------------------------------------------------------------ # main #------------------------------------------------------------------------------ main() { trap exit_handler EXIT argList=("$@") errFuncName="$FUNCNAME" [[ ${BASH_VERSINFO[0]} -eq 4 && ${BASH_VERSINFO[1]} -ge 2 ]] || \ [[ ${BASH_VERSINFO[0]} -gt 4 ]] || exit 10 declare -F exec_target exit_handler get_input list_files show_usage \ &>/dev/null || exit 16 # this constant may be required by worker scripts [[ -d $LIBEXEC_PATH ]] && declare -gx LIBEXEC_PATH get_input list_files exec_target show_usage exit 0 } #------------------------------------------------------------------------------ # run program #------------------------------------------------------------------------------ main "$@"