handle race condition
[log-quiet] / sysd-mail-once
index e4305aec3ce621764cf517f9d311c179106bc79b..2f7f4d5d9efd035d7803d623bb946090f4597be7 100755 (executable)
@@ -18,11 +18,12 @@ set -eE -o pipefail
 trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
 
 errors=3
-cbase=/var/local/cron-errors
+cbase=$HOME/sysd-mail-once-state
+to=root
 case "$1" in
-    -h|--help)
-        cat <<EOF
-Usage: sysd-log-once [-ERRORS] SERVICE COMMAND [ARGS...]
+  -h|--help)
+    cat <<EOF
+Usage: sysd-mail-once [-t TO_ADDRESS] [-ERRORS] SERVICE COMMAND [ARGS...]
 For systemd timers, email on repeated failure & success after failure.
 
 In the service triggered by the timer, prepend this script to the ExecStart.
@@ -34,47 +35,60 @@ Stores error counts in $cbase
 -ERRORS:  ERRORS is the number of failurs to accumulate before mailing the error.
           Default is 3.
 EOF
-        exit 0
-        ;;
-    -[0-9]*)
-        errors=${1#-}
-        shift
-        ;;
+    exit 0
+    ;;
+  -[0-9]*)
+    errors=${1#-}
+    shift
+    ;;
+  -t)
+    to="$2"
+    shift 2
+    ;;
 esac
 service=$1
 shift
 
-c=$cbase/$service
+c=$cbase/$service # c for command file path base
 
 glob="$c[0-9]*"
 arr=($glob); file="${arr[0]}"; [[ $glob != "$file" ]] || file=
-u=${USER:-root}
 [[ -d $cbase ]] || mkdir -p $cbase
 
 if [[ ! $file ]]; then
-    cursor=$(journalctl --show-cursor -qn0|sed 's/^\s*--\scursor:\s*//')
+  cursor=$(journalctl --show-cursor -qn0|sed 's/^\s*--\scursor:\s*//')
 fi
-if "$@"; then
-    if [[ $file ]]; then
-        rm -f $file
-        if [[ $file == $c$errors ]]; then
-            echo | mail -s "$HOSTNAME: $service success" $u@localhost
-        fi
+
+code=0
+"$@" || code=$?
+if (( code )); then
+  send_mail=false
+  if [[ $file ]]; then
+    i=${file#$c}
+    if (( i < errors )); then
+      new_file=$c$((i+1))
+      mv $file $new_file
+      file=$new_file
+      if [[ $file == $c$errors ]]; then
+        send_mail=true
+      fi
+    fi
+  else
+    file=${c}1
+    printf "%s\n" "$cursor" >$file
+    if (( errors == 1 )); then
+      send_mail=true
     fi
-else # $@ failed
-    if [[ $file ]]; then
-        i=${file#$c}
-        if (( i < errors )); then
-            new_file=$c$((i+1))
-            mv $file $new_file
-            file=$new_file
-            if [[ $file == $c$errors ]]; then
-                journalctl -u $service.service --after-cursor=$(<$file) | \
-                    mail -s "$HOSTNAME: $service failure" $u@localhost
-            fi
-        fi
-    else
-        file=${c}1
-        printf "%s\n" "$cursor" >$file
+  fi
+  if $send_mail; then
+    journalctl -u $service.service --after-cursor=$(<$file) | \
+      mail -s "$HOSTNAME: $service exit code: $code" "$to"
+  fi
+else
+  if [[ $file ]]; then
+    rm -f $file
+    if [[ $file == $c$errors ]]; then
+      echo | mail -s "$HOSTNAME: $service success" "$to"
     fi
+  fi
 fi