]> git.decadent.org.uk Git - dak.git/blob - config/debian/cronscript
e77e082df8e80cbed0d04d80597764a8c8344a72
[dak.git] / config / debian / cronscript
1 #!/bin/bash
2 # No way I try to deal with a crippled sh just for POSIX foo.
3
4 # Copyright (C) 2009-2015 Joerg Jaspert <joerg@debian.org>
5 #
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License as
8 # published by the Free Software Foundation; version 2.
9 #
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 # General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 # Homer: Are you saying you're never going to eat any animal again? What
20 #        about bacon?
21 # Lisa: No.
22 # Homer: Ham?
23 # Lisa: No.
24 # Homer: Pork chops?
25 # Lisa: Dad, those all come from the same animal.
26 # Homer: Heh heh heh. Ooh, yeah, right, Lisa. A wonderful, magical animal.
27
28 # exit on errors
29 set -e
30 # A pipeline's return status is the value of the last (rightmost)
31 # command to exit with a non-zero status, or zero if all commands exit
32 # successfully.
33 set -o pipefail
34 # make sure to only use defined variables
35 set -u
36 # ERR traps should be inherited from functions too. (And command
37 # substitutions and subshells and whatnot, but for us the functions is
38 # the important part here)
39 set -E
40
41 # And use one locale, no matter what the caller has set
42 export LANG=C.UTF-8
43 export LC_ALL=C.UTF-8
44
45 # One arg please
46 declare -lr ARG=${1:-"meh"}
47
48 # set DEBUG if you want to see a little more logs (needs to be used more)
49 DEBUG=${DEBUG:-0}
50
51 # This doesn't catch calling us with an unknown argument, but it
52 # catches missing args and saves a good bunch of processing time
53 # (reading the scriptvars later is slow)
54 if [[ ${ARG} == meh ]]; then
55     cat - <<EOF
56 This is the FTPMaster cronscript. It needs an argument or it won't do
57 anything for you.
58
59 Currently accepted Arguments:
60
61    unchecked - Process the unchecked queue
62    dinstall  - Run a dinstall
63    yearly, hourly, daily, weekly - Run that part
64
65 EOF
66     exit 0
67 fi
68
69 # import the general variable set.
70 export SCRIPTVARS=/srv/ftp-master.debian.org/dak/config/debian/vars
71 . $SCRIPTVARS
72
73 # common functions are "outsourced"
74 . "${configdir}/common"
75
76 # program name is the (lower cased) first argument.
77 PROGRAM="${ARG}"
78
79 # Timestamp when we started
80 NOW=$(date "+%Y.%m.%d-%H:%M:%S")
81
82 # Which list of tasks should we run?
83 declare -r TASKLIST="${configdir}/${PROGRAM}.tasks"
84
85 # A logfile for every cron script
86 LOGFILE="${logdir}/${PROGRAM}_${NOW}.log"
87
88 # Each "cronscript" may have a variables and a functions file
89 # that we source
90 for what in variables functions; do
91     if [[ -f ${configdir}/${PROGRAM}.${what} ]]; then
92         . ${configdir}/${PROGRAM}.${what}
93     fi
94 done
95
96 # Get rid of tempfiles at the end
97 trap cleanup EXIT TERM HUP INT QUIT
98
99 case ${ARG} in
100     unchecked)
101         # Do not run during dinstall
102         if [[ -e ${LOCK_DAILY} ]]; then
103             exit 0;
104         fi
105         # only run one cron.unchecked and also lock against hourly (newoverview)
106         if ! lockfile -r8 ${LOCK_UNCHECKED} 2> /dev/null; then
107             # log "aborting cron.unchecked because $LOCK_UNCHECKED has already been locked"
108             exit 0
109         fi
110         TMPFILES="${TMPFILES} ${LOCK_UNCHECKED}"
111         ;;
112     dinstall)
113         ;;
114     hourly)
115         # Only one of me should ever run.
116         FLOCKER=${FLOCKER:-""}
117         [  "${FLOCKER}"  != "${configdir}/${PROGRAM}.variables" ] && exec env FLOCKER="${configdir}/${PROGRAM}.variables" flock -E 0 -en "${configdir}/${PROGRAM}.variables" "$0" "$@" || :
118         ;;
119     daily)
120         ;;
121     weekly)
122         ;;
123     monthly)
124         ;;
125     yearly)
126         ;;
127     *)
128         error "Unknown arg ${ARG}"
129         exit 42
130     ;;
131 esac
132
133 # An easy access by name for the current log
134 ln -sf ${LOGFILE} ${logdir}/${PROGRAM}
135
136 # And from here, all output to the log please
137 exec >> "$LOGFILE" 2>&1
138
139 # The stage function uses this directory
140 # This amends the stagedir variable from "vars"
141 stagedir="${stagedir}/${PROGRAM}"
142 # Ensure the dir exists
143 mkdir -p ${stagedir}
144
145 # This loop simply wants to be fed by a list of values (see below)
146 # made out of 5 columns.
147 # The first four are the array values for the stage function, the
148 # fifth tells us if we should background the stage call.
149 #
150 #  - FUNC - the function name to call
151 #  - ARGS - Possible arguments to hand to the function. Can be the empty string
152 #  - TIME - The timestamp name. Can be the empty string
153 #  - ERR  - if this is the string false, then the call will be surrounded by
154 #           set +e ... set -e calls, so errors in the function do not exit
155 #           dinstall. Can be the empty string, meaning true.
156 #  - BG   - Background the function stage?
157 #
158 # ATTENTION: Spaces in arguments or timestamp names need to be escaped by \
159 #
160 # NOTE 1: There are two special values for the first column (FUNC).
161 #         STATE   - do not call stage function, call the state
162 #                   function to update the public statefile "where is dinstall"
163 #         NOSTAGE - do not call stage function, call the command directly.
164 #
165 # Note 2: If you want to hand an empty value to the stage function,
166 #         use the word "none" in the list below.
167 while read FUNC ARGS TIME ERR BACKGROUND; do
168     debug "FUNC: $FUNC ARGS: $ARGS TIME: $TIME ERR: $ERR BG: $BACKGROUND"
169
170     # Empty values in the value list are the string "none" (or the
171     # while read loop won't work). Here we ensure that variables that
172     # can be empty, are empty if the string none is set for them.
173     for var in ARGS TIME; do
174         if [[ ${!var} == none ]]; then
175             typeset ${var}=''
176         fi
177     done
178
179     # ERR/BACKGROUND are boolean, check that they are.
180     for var in ERR BACKGROUND; do
181         if [[ ${!var} != false ]] && [[ ${!var} != true ]]; then
182             error "Illegal value ${!var} for ${var} (should be true or false), line for function ${FUNC}"
183         fi
184     done
185
186     case ${FUNC} in
187         STATE)
188             state ${ARGS}
189         ;;
190         NOSTAGE)
191             ${ARGS}
192         ;;
193         *)
194             GO=(
195                 FUNC=${FUNC}
196                 TIME=${TIME}
197                 ARGS=${ARGS}
198                 ERR=${ERR}
199             )
200             if [[ ${BACKGROUND} == true ]]; then
201                 stage $GO &
202             else
203                 stage $GO
204             fi
205         ;;
206     esac
207 done < <(grep -v '^#' ${TASKLIST} )
208
209 # we need to wait for the background processes before the end of the cron script
210 wait
211
212
213 # Common to all cron scripts
214 log "Cron script successful, all done"
215 # Redirect output to another file, as we want to compress our logfile
216 # and ensure its no longer used
217 exec > "$logdir/after${PROGRAM}.log" 2>&1
218
219 case ${ARG} in
220     unchecked)
221         ;;
222     dinstall)
223         logstats ${LOGFILE}
224         state "all done"
225         touch "${DINSTALLEND}"
226         ;;
227     hourly)
228         ;;
229     daily)
230         ;;
231     weekly)
232         ;;
233     monthly)
234         ;;
235     yearly)
236         ;;
237 esac
238
239 # Now, at the very (successful) end of this run, make sure we remove
240 # our stage files, so the next dinstall run will do it all again.
241 rm -f ${stagedir}/*
242 bzip2 -9 ${LOGFILE}
243
244 # Logfile should be gone, remove the symlink
245 [[ -L ${logdir}/${PROGRAM} ]] && [[ ! -f ${logdir}/${PROGRAM} ]] && rm -f ${logdir}/${PROGRAM} || log "Logfile still exists or symlink gone already? Something fishy going on"
246
247 # FIXME: Mail the log when its non-empty
248 [[ -s "${logdir}/after${PROGRAM}.log" ]] || rm "${logdir}/after${PROGRAM}.log"