#!/bin/bash
-# Copyright (C) 2016 Ian Kelling
+# I, Ian Kelling, follow the GNU license recommendations at
+# https://www.gnu.org/licenses/license-recommendations.en.html. They
+# recommend that small programs, < 300 lines, be licensed under the
+# Apache License 2.0. This file contains or is part of one or more small
+# programs. If a small program grows beyond 300 lines, I plan to switch
+# its license to GPL.
+
+# Copyright 2024 Ian Kelling
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# limitations under the License.
+
set -eE -o pipefail
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
dryrun=false
+print_all=false
while [[ $1 == -* ]]; do
case "$1" in
-h|--help)
-ERRORS ERRORS is the number of failurs to accumulate before mailing the error.
Default is 3.
+-a Email the logs of all errors intead of just the last one.
-t TO_ADDRESS Address to email about errors
-n Dry run. Execute command but only print out what we would do in response.
EOF
-[0-9]*)
errors=${1#-}
;;
+ -a)
+ print_all=true
+ ;;
-t)
to="$2"
shift
fi
}
e() {
- printf "dryrun: %s\n" "$*"
+ if $dryrun; then
+ printf "dryrun: %s\n" "$*"
+ fi
}
c=$cbase/$service # c for command file path base
-if $dryrun; then
- e "c=$c"
-fi
+e "c=$c"
glob="${c}[0-9]*"
arr=($glob); file="${arr[0]}"; [[ $glob != "$file" ]] || file=
-if [[ $dryrun && $file ]]; then
+if [[ $file ]]; then
e "file=$file"
fi
mkdir -p $cbase
fi
-if [[ ! $file ]]; then
- cursor=$(journalctl --show-cursor -qn0|sed 's/^\s*--\scursor:\s*//')
-fi
code=0
"$@" || code=$?
if (( code )); then
send_mail=false
+ cursor=$(journalctl --show-cursor -qn0|sed 's/^\s*--\scursor:\s*//')
if [[ $file ]]; then
i=${file#"$c"}
if (( i < errors )); then
file=$new_file
if [[ $file == $c$errors ]]; then
send_mail=true
+ else
+ if $dryrun; then
+ printf "dryrun: appending to file $file: %s\n" "$cursor"
+ else
+ printf "%s\n" "$cursor" >>$file
+ fi
fi
fi
else
fi
fi
if $send_mail; then
+ if $print_all; then
+ cursor=$(head -n1 $file)
+ else
+ cursor=$(tail -n1 $file)
+ fi
echo "sysd-mail-once: emailing on $errors errors. exit code: $code"
mi exim -odf -t <<EOF
To: $to
-From: $USER@$(hostname -f)
+From: $(id -u -n)@$(hostname -f)
Subject: $HOSTNAME: $service exit code: $code
-$(journalctl -u $service.service --after-cursor="$(<$file)")
+$(journalctl -u $service.service --after-cursor="$cursor")
EOF
fi
else
echo "sysd-mail-once: emailing success after >= $errors errors."
mi exim -odf -t <<EOF
To: $to
-From: $USER@$(hostname -f)
+From: $(id -u -n)@$(hostname -f)
Subject: $HOSTNAME: $service success
EOF