]> git.decadent.org.uk Git - dak.git/blobdiff - config/debian/cronscript
Only hardcode path to config if variable isn't set
[dak.git] / config / debian / cronscript
index ffaf977ea8557c344c2d3cb26f0b69ca21aa2079..2418d79a75249ad441c8e6e8e4ad303a391a574d 100755 (executable)
@@ -27,6 +27,9 @@
 
 # exit on errors
 set -e
 
 # 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
 set -o pipefail
 # make sure to only use defined variables
 set -u
@@ -35,15 +38,46 @@ set -u
 # the important part here)
 set -E
 
 # the important part here)
 set -E
 
+# 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
 # And use one locale, no matter what the caller has set
-export LANG=C
-export LC_ALL=C
-
-ARG=${1:-"meh"}
-# While this check can be done in the following case, some assumptions
-# down there are easier if we sorted out calls without an arg before.
-if [[ ${ARG} == meh ]]; then
-    cat - <<EOF
+export LANG=C.UTF-8
+export LC_ALL=C.UTF-8
+
+# If run from crontab, CONFIGDIR will point to the correct dir
+# where we find the vars file
+configdir=${configdir:-"/srv/ftp-master.debian.org/dak/config/debian"}
+# import the general variable set. (This will overwrite configdir, but
+# it is expected to have the same value)
+export SCRIPTVARS=${configdir}/vars
+. $SCRIPTVARS
+
+# One arg please
+declare -lr ARG=${1:-"meh"}
+
+# program name is the (lower cased) first argument.
+PROGRAM="${ARG}"
+
+# And the following types of cronscripts exists
+declare -lr POSSIBLEARGS='+(unchecked|dinstall|hourly|daily|weekly|monthly|yearly)'
+
+# 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 - <<EOF
 This is the FTPMaster cronscript. It needs an argument or it won't do
 anything for you.
 
 This is the FTPMaster cronscript. It needs an argument or it won't do
 anything for you.
 
@@ -51,185 +85,194 @@ Currently accepted Arguments:
 
    unchecked - Process the unchecked queue
    dinstall  - Run a dinstall
 
    unchecked - Process the unchecked queue
    dinstall  - Run a dinstall
-   hourly, daily, weekly - Run that part
+   yearly, hourly, daily, weekly - Run that part
 
 EOF
 
 EOF
-    exit 0
-fi
-
-# Make sure we start out with a sane umask setting
-umask 022
+        exit 0
+        ;;
+esac
 
 
-# import the general variable set.
-export SCRIPTVARS=/srv/ftp-master.debian.org/dak/config/debian/vars
-. $SCRIPTVARS
+(
+    LOCKFREE=0
+    flock --shared --nonblock 42 || LOCKFREE=1
 
 
-# common functions are "outsourced"
-. "${configdir}/common"
+    # Did we get the lock? (It's shared, so usually we will. But DSA
+    # can take an exclusive one in preparation for a reboot)
+    if [[ ${LOCKFREE} -gt 0 ]]; then
+        echo "Couldn't get (shared) reboot lock"
+        exit 1
+    fi
 
 
-# program name is the (lower cased) first argument.
-PROGRAM="${ARG,,}"
+    # common functions are "outsourced"
+    . "${configdir}/common"
 
 
-# Timestamp when we started
-NOW=$(date "+%Y.%m.%d-%H:%M:%S")
+    # Timestamp when we started
+    NOW=$(date "+%Y.%m.%d-%H:%M:%S")
 
 
-# Which list of tasks should we run?
-TASKLIST="${configdir}/${PROGRAM}.tasks"
+    # Which list of tasks should we run?
+    declare -r TASKLIST="${configdir}/${PROGRAM}.tasks"
 
 
-# A logfile for every cron script
-LOGFILE="${logdir}/${PROGRAM}_${NOW}.log"
+    # A logfile for every cron script
+    LOGFILE="${logdir}/${PROGRAM}_${NOW}.log"
 
 
-# Each "cronscript" may have a variables and a functions file
-# that we source
-for what in variables functions; do
-    if [[ -f ${configdir}/${PROGRAM}.${what} ]]; then
-        . ${configdir}/${PROGRAM}.${what}
-    fi
-done
+    # Each "cronscript" may have a variables and a functions file
+    # that we source
+    for what in variables functions; do
+        if [[ -f ${configdir}/${PROGRAM}.${what} ]]; then
+            . ${configdir}/${PROGRAM}.${what}
+        fi
+    done
 
 
-# Get rid of tempfiles at the end
-trap cleanup EXIT TERM HUP INT QUIT
+    # Get rid of tempfiles at the end
+    trap cleanup EXIT TERM HUP INT QUIT
 
 
-case ${ARG,,} in
-    unchecked)
-        # Do not run during dinstall
-        if [[ -e ${LOCK_DAILY} ]]; then
-            exit 0;
-        fi
-        # only run one cron.unchecked and also lock against hourly (newoverview)
-        if ! lockfile -r8 ${LOCK_UNCHECKED} 2> /dev/null; then
-            # log "aborting cron.unchecked because $LOCK_UNCHECKED has already been locked"
-            exit 0
-        fi
-        TEMPFILES="${TEMPFILES} ${LOCK_UNCHECKED}"
-        ;;
-    dinstall)
-        ;;
-    hourly)
-        # Only one of me should ever run.
-        FLOCKER=${FLOCKER:-""}
-        [  "${FLOCKER}"  != "${configdir}/${PROGRAM}.variables" ] && exec env FLOCKER="${configdir}/${PROGRAM}.variables" flock -E 0 -en "${configdir}/${PROGRAM}.variables" "$0"
-        "$@" || :
-        ;;
-    daily)
-        ;;
-    weekly)
-        ;;
-    monthly)
-        ;;
-    *)
-        error "Unknown arg ${ARG}"
-        exit 42
-    ;;
-esac
+    case ${ARG} in
+        unchecked)
+            # Do not run during dinstall
+            if [[ -e ${LOCK_DAILY} ]]; then
+                exit 0;
+            fi
+            # only run one cron.unchecked and also lock against hourly (newoverview)
+            if ! lockfile -r8 ${LOCK_UNCHECKED} 2> /dev/null; then
+                # log "aborting cron.unchecked because $LOCK_UNCHECKED has already been locked"
+                exit 0
+            fi
+            TMPFILES="${TMPFILES} ${LOCK_UNCHECKED}"
+            ;;
+        dinstall)
+            ;;
+        hourly)
+            ;;
+        daily)
+            ;;
+        weekly)
+            ;;
+        monthly)
+            ;;
+        yearly)
+            ;;
+        *)
+            error "Unknown arg ${ARG}"
+            exit 42
+            ;;
+    esac
 
 
-# An easy access by name for the current log
-ln -sf ${LOGFILE} ${PROGRAM}
+    # 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
+    # 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}
+    # The stage function uses this directory
+    # This amends the stagedir variable from "vars"
+    stagedir="${stagedir}/${PROGRAM}"
+    # Ensure the dir exists
+    mkdir -p ${stagedir}
 
 
-# This loop simply wants to be fed by a list of values (see below)
-# made out of 5 columns.
-# The first four are the array values for the stage function, the
-# fifth tells us if we should background the stage call.
-#
-#  - FUNC - the function name to call
-#  - ARGS - Possible arguments to hand to the function. Can be the empty string
-#  - TIME - The timestamp name. Can be the empty string
-#  - ERR  - if this is the string false, then the call will be surrounded by
-#           set +e ... set -e calls, so errors in the function do not exit
-#           dinstall. Can be the empty string, meaning true.
-#  - BG   - Background the function stage?
-#
-# ATTENTION: Spaces in arguments or timestamp names need to be escaped by \
-#
-# NOTE 1: There are two special values for the first column (FUNC).
-#         STATE   - do not call stage function, call the state
-#                   function to update the public statefile "where is dinstall"
-#         NOSTAGE - do not call stage function, call the command directly.
-#
-# Note 2: If you want to hand an empty value to the stage function,
-#         use the word "none" in the list below.
-while read FUNC ARGS TIME ERR BACKGROUND; do
-    debug "FUNC: $FUNC ARGS: $ARGS TIME: $TIME ERR: $ERR BG: $BACKGROUND"
-
-    # Empty values in the value list are the string "none" (or the
-    # while read loop won't work). Here we ensure that variables that
-    # can be empty, are empty if the string none is set for them.
-    for var in ARGS TIME; do
-        if [[ ${!var} == none ]]; then
-            typeset ${var}=''
-        fi
-    done
+    # This loop simply wants to be fed by a list of values (see below)
+    # made out of 5 columns.
+    # The first four are the array values for the stage function, the
+    # fifth tells us if we should background the stage call.
+    #
+    #  - FUNC - the function name to call
+    #  - ARGS - Possible arguments to hand to the function. Can be the empty string
+    #  - TIME - The timestamp name. Can be the empty string
+    #  - ERR  - if this is the string false, then the call will be surrounded by
+    #           set +e ... set -e calls, so errors in the function do not exit
+    #           dinstall. Can be the empty string, meaning true.
+    #  - BG   - Background the function stage?
+    #
+    # ATTENTION: Spaces in arguments or timestamp names need to be escaped by \
+    #
+    # NOTE 1: There are two special values for the first column (FUNC).
+    #         STATE   - do not call stage function, call the state
+    #                   function to update the public statefile "where is dinstall"
+    #         NOSTAGE - do not call stage function, call the command directly.
+    #
+    # Note 2: If you want to hand an empty value to the stage function,
+    #         use the word "none" in the list below.
+    while read FUNC ARGS TIME ERR BACKGROUND; do
+        debug "FUNC: $FUNC ARGS: $ARGS TIME: $TIME ERR: $ERR BG: $BACKGROUND"
 
 
-    # ERR/BACKGROUND are boolean, check that they are.
-    for var in ERR BACKGROUND; do
-        if [[ ${!var} != false ]] && [[ ${!var} != true ]]; then
-            error "Illegal value ${!var} for ${var} (should be true or false), line for function ${FUNC}"
-        fi
-    done
+        # Empty values in the value list are the string "none" (or the
+        # while read loop won't work). Here we ensure that variables that
+        # can be empty, are empty if the string none is set for them.
+        for var in ARGS TIME; do
+            if [[ ${!var} == none ]]; then
+                typeset ${var}=''
+            fi
+        done
 
 
-    case ${FUNC} in
-        STATE)
-            state ${ARGS}
-        ;;
-        NOSTAGE)
-            ${ARGS}
-        ;;
-        *)
-            GO=(
-                FUNC=${FUNC}
-                TIME=${TIME}
-                ARGS=${ARGS}
-                ERR=${ERR}
-            )
-            if [[ ${BACKGROUND} == true ]]; then
-                stage $GO &
-            else
-                stage $GO
+        # ERR/BACKGROUND are boolean, check that they are.
+        for var in ERR BACKGROUND; do
+            if [[ ${!var} != false ]] && [[ ${!var} != true ]]; then
+                error "Illegal value ${!var} for ${var} (should be true or false), line for function ${FUNC}"
             fi
             fi
-        ;;
-    esac
-done < <(grep -v '^#' ${TASKLIST} )
+        done
 
 
-# we need to wait for the background processes before the end of the cron script
-wait
+        case ${FUNC} in
+            STATE)
+                state ${ARGS}
+                ;;
+            NOSTAGE)
+                ${ARGS}
+                ;;
+            *)
+                GO=(
+                    FUNC=${FUNC}
+                    TIME=${TIME}
+                    ARGS=${ARGS}
+                    ERR=${ERR}
+                )
+                if [[ ${BACKGROUND} == true ]]; then
+                    stage $GO &
+                else
+                    stage $GO
+                fi
+                ;;
+        esac
+    done < <(grep -v '^#' ${TASKLIST} )
 
 
+    # 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"
-# 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
 
 
-case ${ARG,,} in
-    unchecked)
-        ;;
-    dinstall)
-        logstats ${LOGFILE}
-        state "all done"
-        touch "${DINSTALLEND}"
-        ;;
-    hourly)
-        ;;
-    daily)
-        ;;
-    weekly)
-        ;;
-    monthly)
+    # Common to all cron scripts
+    log "Cron script successful, all done"
+    # 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
+
+    case ${ARG} in
+        unchecked)
         ;;
         ;;
-esac
+        dinstall)
+            logstats ${LOGFILE}
+            state "all done"
+            touch "${DINSTALLEND}"
+            ;;
+        hourly)
+            ;;
+        daily)
+            ;;
+        weekly)
+            ;;
+        monthly)
+            ;;
+        yearly)
+            ;;
+    esac
+
+    # Now, at the very (successful) end of this run, make sure we remove
+    # our stage files, so the next dinstall run will do it all again.
+    rm -f ${stagedir}/*
+    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"
 
 
-# Now, at the very (successful) end of this run, make sure we remove
-# our stage files, so the next dinstall run will do it all again.
-rm -f ${stagedir}/*
-bzip2 -9 ${LOGFILE}
-# FIXME: Mail the log when its non-empty
-[[ -s "${logdir}/after${PROGRAM}.log" ]] || rm "${logdir}/after${PROGRAM}.log"
+# And end the reboot-locked part
+) 42</var/run/reboot-lock