#!/bin/bash function _exit_with_error() { if [[ -n ${1+set} ]]; then _log 'error' "${1}" else _log 'error' "Call to '_exit_with_error' is missing a message to log" fi _log 'error' 'Aborting' exit "${2:-1}" } # `dms_panic` methods are appropriate when the type of error is a not recoverable, # or needs to be very clear to the user about misconfiguration. # # Method is called with args: # PANIC_TYPE => (Internal value for matching). You should use the convenience methods below based on your panic type. # PANIC_INFO => Provide your own message string to insert into the error message for that PANIC_TYPE. # PANIC_SCOPE => Optionally provide a string for debugging to better identify/locate the source of the panic. function dms_panic() { local PANIC_TYPE=${1:-} local PANIC_INFO=${2:-} local PANIC_SCOPE=${3:-} local SHUTDOWN_MESSAGE case "${PANIC_TYPE:-}" in ( 'fail-init' ) # PANIC_INFO == SHUTDOWN_MESSAGE="Failed to start ${PANIC_INFO}!" ;; ( 'no-env' ) # PANIC_INFO == SHUTDOWN_MESSAGE="Environment Variable: ${PANIC_INFO} is not set!" ;; ( 'no-file' ) # PANIC_INFO == SHUTDOWN_MESSAGE="File ${PANIC_INFO} does not exist!" ;; ( 'misconfigured' ) # PANIC_INFO == SHUTDOWN_MESSAGE="${PANIC_INFO} appears to be misconfigured, please verify." ;; ( 'invalid-value' ) # PANIC_INFO == SHUTDOWN_MESSAGE="Invalid value for ${PANIC_INFO}!" ;; ( 'general' ) SHUTDOWN_MESSAGE=${PANIC_INFO} ;; ( * ) # `dms_panic` was called directly without a valid PANIC_TYPE SHUTDOWN_MESSAGE='Something broke :(' ;; esac if [[ -n ${PANIC_SCOPE:-} ]]; then _shutdown "${PANIC_SCOPE} | ${SHUTDOWN_MESSAGE}" else _shutdown "${SHUTDOWN_MESSAGE}" fi } # Convenience wrappers based on type: function _dms_panic__fail_init { dms_panic 'fail-init' "${1:-}" "${2:-}" "${3:-}" ; } function _dms_panic__no_env { dms_panic 'no-env' "${1:-}" "${2:-}" "${3:-}" ; } function _dms_panic__no_file { dms_panic 'no-file' "${1:-}" "${2:-}" "${3:-}" ; } function _dms_panic__misconfigured { dms_panic 'misconfigured' "${1:-}" "${2:-}" "${3:-}" ; } function _dms_panic__invalid_value { dms_panic 'invalid-value' "${1:-}" "${2:-}" "${3:-}" ; } function _dms_panic__general { dms_panic 'general' "${1:-}" "${2:-}" "${3:-}" ; } # Call this method when you want to panic (i.e. emit an 'ERROR' log, and exit uncleanly). # `dms_panic` methods should be preferred if your failure type is supported. trap "exit 1" SIGUSR1 SCRIPT_PID=${$} function _shutdown() { _log 'error' "${1:-_shutdown called without message}" _log 'error' 'Shutting down' sleep 1 kill -SIGTERM 1 # Trigger graceful DMS shutdown. kill -SIGUSR1 "${SCRIPT_PID}" # Stop start-mailserver.sh execution, even when _shutdown() is called from a subshell. } # Calling this function sets up a handler for the `ERR` signal, that occurs when # an error is not properly checked (e.g., in an `if`-clause or in an `&&` block). # # This is mostly useful for debugging. It also helps when using something like `set -eE`, # as it shows where the script aborts. function _trap_err_signal() { trap '__log_unexpected_error "${FUNCNAME[0]:-}" "${BASH_COMMAND:-}" "${LINENO:-}" "${?:-}"' ERR # shellcheck disable=SC2317 function __log_unexpected_error() { local MESSAGE="Unexpected error occured :: script = ${SCRIPT:-${0}} " MESSAGE+=" | function = ${1:-none (global)}" MESSAGE+=" | command = ${2:-?}" MESSAGE+=" | line = ${3:-?}" MESSAGE+=" | exit code = ${4:-?}" _log 'error' "${MESSAGE}" return 0 } }