]> git.decadent.org.uk Git - dak.git/blob - config/debian/cron.dinstall
ensure boolean values are true/false only
[dak.git] / config / debian / cron.dinstall
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 set -o pipefail
31 # make sure to only use defined variables
32 set -u
33 # ERR traps should be inherited from functions too. (And command
34 # substitutions and subshells and whatnot, but for us the functions is
35 # the important part here)
36 set -E
37
38 # import the general variable set.
39 export SCRIPTVARS=/srv/ftp-master.debian.org/dak/config/debian/vars
40 . $SCRIPTVARS
41
42 ########################################################################
43 # Functions                                                            #
44 ########################################################################
45 # common functions are "outsourced"
46 . "${configdir}/common"
47
48 # source the dinstall functions
49 . "${configdir}/dinstall.functions"
50
51 ########################################################################
52 ########################################################################
53
54 # Function to save which stage we are in, so we can restart an interrupted
55 # dinstall. Or even run actions in parallel, if we dare to, by simply
56 # backgrounding the call to this function. But that should only really be
57 # done for things we don't care much about.
58 #
59 # This should be called with the first argument being an array, with the
60 # members
61 #  - FUNC - the function name to call
62 #  - ARGS - Possible arguments to hand to the function. Can be the empty string
63 #  - TIME - The timestamp name. Can be the empty string
64 #  - ERR  - if this is the string false, then the call will be surrounded by
65 #           set +e ... set -e calls, so errors in the function do not exit
66 #           dinstall. Can be the empty string, meaning true.
67 #
68 # MAKE SURE TO KEEP THIS THE LAST FUNCTION, AFTER ALL THE VARIOUS ONES
69 # ADDED FOR DINSTALL FEATURES!
70 function stage() {
71     ARGS='GO[@]'
72     local "${!ARGS}"
73
74     local error=${ERR:-"true"}
75
76     ARGS=${ARGS:-""}
77
78     log "########## DINSTALL BEGIN: ${FUNC} ${ARGS} ##########"
79     local STAGEFILE="${stagedir}/${FUNC}_${ARGS}"
80     STAGEFILE=${STAGEFILE// /_}
81     if [ -f "${STAGEFILE}" ]; then
82         local stamptime=$(/usr/bin/stat -c %Z "${STAGEFILE}")
83         local unixtime=$(date +%s)
84         local difference=$(( $unixtime - $stamptime ))
85         if [ ${difference} -ge 14400 ]; then
86             log_error "Did already run ${FUNC}, stagefile exists, but that was ${difference} seconds ago. Please check."
87         else
88             log "Did already run ${FUNC}, not calling again..."
89         fi
90         return
91     fi
92
93     debug "Now calling function ${FUNC}. Arguments: ${ARGS}. Timestamp: ${TIME}"
94
95     # Make sure we are always at the same place. If a function wants
96     # to be elsewhere, it has to cd first!
97     cd ${configdir}
98
99     # Now redirect the output into $STAGEFILE.log. In case it errors
100     # out somewhere our errorhandler trap can then mail the contents
101     # of $STAGEFILE.log only, instead of a whole dinstall logfile.
102     # Short error mails ftw!
103     exec >> "${STAGEFILE}.log" 2>&1
104
105     if [ -f "${LOCK_STOP}" ]; then
106         log "${LOCK_STOP} exists, exiting immediately"
107         exit 42
108     fi
109
110     # Do we care about trouble in the function we call?
111     if [ "${error}" = "false" ]; then
112         set +e
113     fi
114     ${FUNC} ${ARGS}
115
116     # No matter what happened in the function, we make sure we have
117     # set -e default state back
118     set -e
119
120     # Make sure we are always at the same place.
121     cd ${configdir}
122
123     # We always use the same umask. If a function wants to do
124     # different, fine, but we reset.
125     umask 022
126
127     touch "${STAGEFILE}"
128
129     if [ -n "${TIME}" ]; then
130         ts "${TIME}"
131     fi
132
133     # And the output goes back to the normal logfile
134     exec >> "$LOGFILE" 2>&1
135
136     # Now we should make sure that we have a usable dinstall.log, so
137     # append the $STAGEFILE.log to it.
138     cat "${STAGEFILE}.log" >> "${LOGFILE}"
139     rm -f "${STAGEFILE}.log"
140
141     log "########## DINSTALL END: ${FUNC} ##########"
142
143     if [ -f "${LOCK_STOP}" ]; then
144         log "${LOCK_STOP} exists, exiting immediately"
145         exit 42
146     fi
147 }
148
149 ########################################################################
150
151 # We need logs.
152 LOGFILE="$logdir/dinstall.log"
153
154 exec >> "$LOGFILE" 2>&1
155
156 # And now source our default config
157 . "${configdir}/dinstall.variables"
158
159 # Make sure we start out with a sane umask setting
160 umask 022
161
162 # And use one locale, no matter what the caller has set
163 export LANG=C
164 export LC_ALL=C
165
166 touch "${DINSTALLSTART}"
167 ts "startup"
168 DINSTALLBEGIN="$(date -u +"%a %b %d %T %Z %Y (%s)")"
169 state "Startup"
170
171 lockfile -l 3600 "${LOCK_DAILY}"
172 trap onerror ERR
173 trap remove_daily_lock EXIT TERM HUP INT QUIT
174
175 touch "${LOCK_BRITNEY}"
176
177 # This loop simply wants to be fed by a list of values (see below)
178 # made out of 5 columns.
179 # The first four are the array values for the stage function, the
180 # fifth tells us if we should background the stage call.
181 #
182 #  - FUNC - the function name to call
183 #  - ARGS - Possible arguments to hand to the function. Can be the empty string
184 #  - TIME - The timestamp name. Can be the empty string
185 #  - ERR  - if this is the string false, then the call will be surrounded by
186 #           set +e ... set -e calls, so errors in the function do not exit
187 #           dinstall. Can be the empty string, meaning true.
188 #  - BG   - Background the function stage?
189 #
190 # ATTENTION: Spaces in arguments or timestamp names need to be escaped by \
191 #
192 # NOTE 1: There are two special values for the first column (FUNC).
193 #         STATE   - do not call stage function, call the state
194 #                   function to update the public statefile "where is dinstall"
195 #         NOSTAGE - do not call stage function, call the command directly.
196 #
197 # Note 2: If you want to hand an empty value to the stage function,
198 #         use the word "none" in the list below.
199 while read FUNC ARGS TIME ERR BACKGROUND; do
200     debug "FUNC: $FUNC ARGS: $ARGS TIME: $TIME ERR: $ERR BG: $BACKGROUND"
201
202     # Empty values in the value list are the string "none" (or the
203     # while read loop won't work). Here we ensure that variables that
204     # can be empty, are empty if the string none is set for them.
205     for var in ARGS TIME; do
206         if [[ ${!var} == none ]]; then
207             typeset ${var}=''
208         fi
209     done
210
211     # ERR/BACKGROUND are boolean, check that they are.
212     for var in ERR BACKGROUND; do
213         if [[ ${!var} != false ]] && [[ ${!var} != true ]]; then
214             error "Illegal value ${!var} for ${var} (should be true or false), line for function ${FUNC}"
215         fi
216     done
217
218     case ${FUNC} in
219         STATE)
220             state ${ARGS}
221         ;;
222         NOSTAGE)
223             ${ARGS}
224         ;;
225         *)
226             GO=(
227                 FUNC=${FUNC}
228                 TIME=${TIME}
229                 ARGS=${ARGS}
230                 ERR=${ERR}
231             )
232             if [[ ${BACKGROUND} == true ]]; then
233                 stage $GO &
234             else
235                 stage $GO
236             fi
237         ;;
238     esac
239 done < <(cat - <<EOF
240 savetimestamp          none                       none                       false   false
241 qa1                    none                       init                       true    true
242 pg_timestamp           predinstall                pg_dump1                   false   false
243 updates                none                       External\ Updates          false   false
244 i18n1                  none                       i18n\ 1                    false   false
245 dep11                  none                       dep11\ 1                   false   false
246 NOSTAGE                lockaccepted               none                       false   false
247 punew                  stable-new                 p-u-new                    false   false
248 opunew                 oldstable-new              o-p-u-new                  false   false
249 backports_policy       none                       backports-policy           false   false
250 cruft                  none                       cruft                      false   false
251 STATE                  indices                    none                       false   false
252 dominate               none                       dominate                   false   false
253 autocruft              none                       autocruft                  false   false
254 fingerprints           none                       import-keyring             false   false
255 overrides              none                       overrides                  false   false
256 mpfm                   none                       pkg-file-mapping           false   false
257 STATE                  packages/contents          none                       false   false
258 packages               none                       apt-ftparchive             false   false
259 STATE                  dists/                     none                       false   false
260 pdiff                  none                       pdiff                      false   false
261 release                none                       release\ files             false   false
262 dakcleanup             none                       cleanup                    false   false
263 STATE                  scripts                    none                       false   false
264 mkmaintainers          none                       mkmaintainers              false   false
265 copyoverrides          none                       copyoverrides              false   false
266 mklslar                none                       mklslar                    false   false
267 mkfilesindices         none                       mkfilesindices             false   false
268 mkchecksums            none                       mkchecksums                false   false
269 mirror                 none                       mirror\ hardlinks          false   false
270 NOSTAGE                remove_locks               none                       false   false
271 STATE                  postlock                   none                       false   false
272 ddaccess               none                       ddaccessible\ sync         true    true
273 changelogs             none                       changelogs                 false   true
274 pg_timestamp           postdinstall               pg_dump2                   false   false
275 expire                 none                       expire_dumps               false   true
276 transitionsclean       none                       transitionsclean           false   true
277 dm                     none                       none                       false   true
278 bts                    none                       none                       false   true
279 mirrorpush             none                       mirrorpush                 false   true
280 mirrorpush-backports   none                       mirrorpush-backports       false   true
281 i18n2                  none                       i18n\ 2                    false   true
282 stats                  none                       stats                      false   true
283 testingsourcelist      none                       none                       false   true
284 NOSTAGE                rm\ -f\ "\${LOCK_BRITNEY}" none                       false   false
285 cleantransactions      none                       none                       false   false
286 EOF
287         )
288
289 # we need to wait for the background processes before the end of dinstall
290 wait
291
292 log "Daily cron scripts successful, all done"
293
294 exec > "$logdir/afterdinstall.log" 2>&1
295
296 if [ -f "${dbdir}/dinstallstart" ]; then
297     NOW=$(cat "${dbdir}/dinstallstart")
298     mv "$LOGFILE" "$logdir/dinstall_${NOW}.log"
299     logstats "$logdir/dinstall_${NOW}.log"
300     bzip2 -9 "$logdir/dinstall_${NOW}.log"
301 else
302     error "Problem, I don't know when dinstall started, unable to do log statistics."
303     NOW=`date "+%Y.%m.%d-%H:%M:%S"`
304     mv "$LOGFILE" "$logdir/dinstall_${NOW}.log"
305     bzip2 -9 "$logdir/dinstall_${NOW}.log"
306 fi
307
308 state "all done"
309
310 # Now, at the very (successful) end of dinstall, make sure we remove
311 # our stage files, so the next dinstall run will do it all again.
312 rm -f ${stagedir}/*
313 touch "${DINSTALLEND}"