#!/bin/bash # No way I try to deal with a crippled sh just for POSIX foo. # Copyright (C) 2009-2016, 2018 Joerg Jaspert # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as # published by the Free Software Foundation; version 2. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # Homer: Are you saying you're never going to eat any animal again? What # about bacon? # Lisa: No. # Homer: Ham? # Lisa: No. # Homer: Pork chops? # Lisa: Dad, those all come from the same animal. # Homer: Heh heh heh. Ooh, yeah, right, Lisa. A wonderful, magical animal. # exit on errors set -e # A pipeline's return status is the value of the last (rightmost) # command to exit with a non-zero status, or zero if all commands exit # successfully. set -o pipefail # make sure to only use defined variables set -u # ERR traps should be inherited from functions too. (And command # substitutions and subshells and whatnot, but for us the functions is # the important part here) set -E # If the extglob shell option is enabled using the shopt builtin, # several extended pattern matching operators are recognized. We use # it for the POSSIBLEARGS and the first case ${ARGS} matching. shopt -s extglob # And use one locale, no matter what the caller has set export LANG=C.UTF-8 export LC_ALL=C.UTF-8 # One arg please declare -lr ARG=${1:-"meh"} # program name is the (lower cased) first argument. PROGRAM="${ARG}" # import the general variable set. (This will overwrite configdir, but # it is expected to have the same value) export SCRIPTVARS=${configdir:?Please define configdir to run this script}/vars . ${SCRIPTVARS} # set DEBUG if you want to see a little more logs (needs to be used more) DEBUG=${DEBUG:-0} # Check if the argument is a known one. If so, lock us so that only # one copy of the type of cronscript runs. The $type.tasks file is # mandantory, so use that for locking. case ${ARG} in ${POSSIBLEARGS}) # Only one of me should ever run. FLOCKER=${FLOCKER:-""} [[ ${FLOCKER} != ${configdir}/${PROGRAM}.tasks ]] && exec env FLOCKER="${configdir}/${PROGRAM}.tasks" flock -E 0 -en "${configdir}/${PROGRAM}.tasks" "$0" "$@" || : ;; *) cat - <&- } function laststeps() { local successval=${1:-0} # Redirect output to another file, as we want to compress our logfile # and ensure its no longer used exec > "$logdir/after${PROGRAM}.log" 2>&1 # Rotate out old logfiles find ${logdir}/${PROGRAM}_*.log.bz2 -mtime +${logkeep} -delete # Now, at the very (successful) end of this run, make sure we remove # our stage files, so the next script run will do it all again. if [[ ${successval} -eq 0 ]]; then rm -f ${stagedir}/* fi bzip2 -9 ${LOGFILE} # Logfile should be gone, remove the symlink [[ -L ${logdir}/${PROGRAM} ]] && [[ ! -f ${logdir}/${PROGRAM} ]] && rm -f ${logdir}/${PROGRAM} || log "Logfile still exists or symlink gone already? Something fishy going on" # FIXME: Mail the log when its non-empty [[ -s "${logdir}/after${PROGRAM}.log" ]] || rm "${logdir}/after${PROGRAM}.log" } ( # Where we store lockfile filehandles declare -A LOCKFD # common functions are "outsourced" . "${configdir}/common" # Timestamp when we started NOW=$(date "+%Y.%m.%d-%H:%M:%S") # A logfile for every cron script LOGFILE="${logdir}/${PROGRAM}_${NOW}.log" # Each "cronscript" may have a variables and a functions file # that we source _preparetasks ${PROGRAM} # Get rid of tempfiles at the end trap cleanup EXIT TERM HUP INT QUIT # An easy access by name for the current log ln -sf ${LOGFILE} ${logdir}/${PROGRAM} # And from here, all output to the log please exec >> "$LOGFILE" 2>&1 # The stage function uses this directory # This amends the stagedir variable from "vars" stagedir="${stagedir}/${PROGRAM}" # Ensure the dir exists mkdir -p ${stagedir} # Run all tasks _runtasks ${PROGRAM} # we need to wait for the background processes before the end of the cron script wait # Common to all cron scripts log "Cron script successful, all done" laststeps 0 )