use upstream name for bash dependency
[log-quiet] / sysd-mail-once
index b1a67b881cee88388d64ff0e31cda81d24de96f7..32aa02d2dbd5911c72656b1b5f39595acfc7c1d6 100755 (executable)
@@ -18,13 +18,18 @@ set -eE -o pipefail
 trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
 
 errors=3
 trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?" >&2' ERR
 
 errors=3
-cbase=$HOME/sysd-mail-once-state
+tmp=(~)
+cbase="${tmp[0]}/sysd-mail-once-state"
 to=root
 to=root
-case "$1" in
-  -h|--help)
-    cat <<EOF
-Usage: sysd-mail-once [-t TO_ADDRESS] [-ERRORS] SERVICE COMMAND [ARGS...]
-For systemd timers, email (with exim) on repeated failure & success after failure.
+dryrun=false
+while [[ $1 == -* ]]; do
+  case "$1" in
+    -h|--help)
+      cat <<EOF
+Usage: sysd-mail-once [-t TO_ADDRESS] [-ERRORS] SERVICE COMMAND [COMMAND_ARGS...]
+
+For use with systemd timers, to email (with exim) on repeated failure &
+success after failure.
 
 In the service triggered by the timer, prepend this script to the ExecStart.
 The email will contain the service's logs for the last ERRORS runs.
 
 In the service triggered by the timer, prepend this script to the ExecStart.
 The email will contain the service's logs for the last ERRORS runs.
@@ -32,28 +37,78 @@ The email will contain the service's logs for the last ERRORS runs.
 
 Stores error counts in $cbase
 
 
 Stores error counts in $cbase
 
--ERRORS:  ERRORS is the number of failurs to accumulate before mailing the error.
-          Default is 3.
+-ERRORS         ERRORS is the number of failurs to accumulate before mailing the error.
+                Default is 3.
+
+-t TO_ADDRESS   Address to email about errors
+-n              Dry run. Execute command but only print out what we would do in response.
 EOF
 EOF
-    exit 0
-    ;;
-  -[0-9]*)
-    errors=${1#-}
-    shift
-    ;;
-  -t)
-    to="$2"
-    shift 2
-    ;;
-esac
-service=$1
+      exit 0
+      ;;
+    -[0-9]*)
+      errors=${1#-}
+      ;;
+    -t)
+      to="$2"
+      shift
+      ;;
+    -n)
+      dryrun=true
+      ;;
+    *)
+      echo "error: unexpected arg: $1"
+      exit 1
+      ;;
+  esac
+  shift
+done
+
+if (( $# < 2 )); then
+  echo "error: expected at least 2 args after options. args:"
+  exit 1
+fi
+
+service="$1"
 shift
 
 shift
 
+
+# maybe run, depending on $dryrun
+m() {
+  if $dryrun; then
+    printf "%s\n" "$*"
+  else
+    "$@"
+  fi
+}
+# maybe run, with stdin
+mi() {
+  if $dryrun; then
+    printf "%s <<'EOF'\n" "$*"
+    cat
+    echo EOF
+  else
+    "$@"
+  fi
+}
+e() {
+  printf "dryrun: %s\n" "$*"
+}
+
 c=$cbase/$service # c for command file path base
 
 c=$cbase/$service # c for command file path base
 
-glob="$c[0-9]*"
+if $dryrun; then
+  e "c=$c"
+fi
+
+glob="${c}[0-9]*"
 arr=($glob); file="${arr[0]}"; [[ $glob != "$file" ]] || file=
 arr=($glob); file="${arr[0]}"; [[ $glob != "$file" ]] || file=
-[[ -d $cbase ]] || mkdir -p $cbase
+if [[ $dryrun && $file ]]; then
+  e "file=$file"
+fi
+
+if ! [[ -d $cbase ]]; then
+  mkdir -p $cbase
+fi
 
 if [[ ! $file ]]; then
   cursor=$(journalctl --show-cursor -qn0|sed 's/^\s*--\scursor:\s*//')
 
 if [[ ! $file ]]; then
   cursor=$(journalctl --show-cursor -qn0|sed 's/^\s*--\scursor:\s*//')
@@ -64,10 +119,10 @@ code=0
 if (( code )); then
   send_mail=false
   if [[ $file ]]; then
 if (( code )); then
   send_mail=false
   if [[ $file ]]; then
-    i=${file#$c}
+    i=${file#"$c"}
     if (( i < errors )); then
       new_file=$c$((i+1))
     if (( i < errors )); then
       new_file=$c$((i+1))
-      mv $file $new_file
+      m mv $file $new_file
       file=$new_file
       if [[ $file == $c$errors ]]; then
         send_mail=true
       file=$new_file
       if [[ $file == $c$errors ]]; then
         send_mail=true
@@ -75,27 +130,33 @@ if (( code )); then
     fi
   else
     file=${c}1
     fi
   else
     file=${c}1
-    printf "%s\n" "$cursor" >$file
+    if $dryrun; then
+      printf "dryrun: creating $file, contents: %s\n" "$cursor"
+    else
+      printf "%s\n" "$cursor" >$file
+    fi
     if (( errors == 1 )); then
       send_mail=true
     fi
   fi
   if $send_mail; then
     if (( errors == 1 )); then
       send_mail=true
     fi
   fi
   if $send_mail; then
-      exim -odf -t <<EOF
+    echo "sysd-mail-once: emailing on $errors errors. exit code: $code"
+    mi exim -odf -t <<EOF
 To: $to
 To: $to
-From: $USER@$(hostname -f)
+From: $(id -u -n)@$(hostname -f)
 Subject: $HOSTNAME: $service exit code: $code
 
 Subject: $HOSTNAME: $service exit code: $code
 
-$(journalctl -u $service.service --after-cursor=$(<$file))
+$(journalctl -u $service.service --after-cursor="$(<$file)")
 EOF
   fi
 else
   if [[ $file ]]; then
 EOF
   fi
 else
   if [[ $file ]]; then
-    rm -f $file
+    rm -f $file
     if [[ $file == $c$errors ]]; then
     if [[ $file == $c$errors ]]; then
-      exim -odf -t <<EOF
+      echo "sysd-mail-once: emailing success after >= $errors errors."
+      mi exim -odf -t <<EOF
 To: $to
 To: $to
-From: $USER@$(hostname -f)
+From: $(id -u -n)@$(hostname -f)
 Subject: $HOSTNAME: $service success
 
 EOF
 Subject: $HOSTNAME: $service success
 
 EOF