#!/usr/bin/env bash # # Update /etc/default/postfwd (idempotent) and reload postfwd. # # For every variable below: # - already set to the wanted value -> nothing to do # - set to a different value -> comment out the current setting # and add the new one directly below # - not set at all -> append the new setting # # Quotes around values are ignored when comparing (PORT="10040" == PORT=10040). # # At the end: # - file changed -> 'systemctl restart postfwd' # (ARGS, INET and PORT are start parameters of the # daemon - a reload does NOT apply them) # - file unchanged -> 'systemctl reload postfwd' # (rereads postfwd.cf and the file: lists) # postfwd_default_file="/etc/default/postfwd" # - Wanted settings: "VAR|VALUE" (VALUE written exactly as it should appear) wanted_settings=( 'STARTUP|1' 'CONF|/etc/postfix/postfwd.cf' 'INET|127.0.0.1' 'PORT|10040' 'ARGS|"--summary=600 --cache=0"' ) # ------------- # --- Some functions # ------------- log_file="$(mktemp)" clean_up() { rm -f "$log_file" exit $1 } echononl() { echo -e -n "$*" } echo_ok() { echo -e "\033[60G[ \033[32mok\033[m ]" } echo_skipped() { echo -e "\033[60G[ \033[33m\033[1mskipped\033[m ]" } echo_failed() { echo -e "\033[60G[ \033[1;31mfailed\033[m ]" } error() { echo "" echo -e "\t[ \033[31m\033[1mError\033[m ]: $*" echo "" } fatal() { error "$*" echo -e "\t\033[31m\033[1mScript will be interrupted\033[m" echo "" clean_up 1 } # - set_postfwd_default # - # - returns 0 if the file was changed, 1 if nothing changed, 2 on error # - set_postfwd_default() { local _var="$1" local _val="$2" local _tmp_file local _rval echononl " ${_var}=${_val}" _tmp_file="$(mktemp)" awk -v var="$_var" -v val="$_val" ' function unq(s) { gsub(/^[ \t]+|[ \t]+$/, "", s) if (s ~ /^".*"$/ || s ~ /^\047.*\047$/) s = substr(s, 2, length(s) - 2) return s } $0 ~ "^[ \t]*" var "=" { cur = $0 ; sub("^[ \t]*" var "=", "", cur) if (! done && unq(cur) == unq(val)) { print ; done = 1 ; next } print "#" $0 if (! done) { print var "=" val ; done = 1 } next } { print } END { if (! done) print var "=" val } ' "$postfwd_default_file" > "$_tmp_file" 2> "$log_file" if [[ $? -ne 0 ]] ; then echo_failed error "$(cat "$log_file")" _rval=2 elif cmp -s "$_tmp_file" "$postfwd_default_file" ; then echo_skipped _rval=1 else # - cat instead of mv/cp keeps owner and permissions of the original file if cat "$_tmp_file" > "$postfwd_default_file" 2> "$log_file" ; then echo_ok _rval=0 else echo_failed error "$(cat "$log_file")" _rval=2 fi fi rm -f "$_tmp_file" return $_rval } # ------------- # --- Main # ------------- [[ "$(id -u)" -eq 0 ]] || fatal "This script must be run as root." command -v postfwd > /dev/null 2>&1 || fatal "postfwd is not installed." if [[ ! -f "$postfwd_default_file" ]] ; then touch "$postfwd_default_file" 2> "$log_file" || fatal "$(cat "$log_file")" fi echo "" echo "Update ${postfwd_default_file}" echo "" file_changed=false errors=false for _setting in "${wanted_settings[@]}" ; do set_postfwd_default "${_setting%%|*}" "${_setting#*|}" case $? in 0) file_changed=true ;; 2) errors=true ;; esac done echo "" if $errors ; then fatal "Errors while updating '${postfwd_default_file}' - postfwd NOT reloaded." fi if $file_changed ; then echononl " Restart postfwd (start parameters changed)" _action="restart" else echononl " Reload postfwd" _action="reload" fi if systemctl $_action postfwd > "$log_file" 2>&1 ; then echo_ok else echo_failed error "$(cat "$log_file")" clean_up 1 fi echo "" clean_up 0