Add -A option for ensuring clean builds and pack artifacts
[grml-live.git] / grml-live
1 #!/bin/bash
2 # Filename:      grml-live
3 # Purpose:       build process script for generating a (grml based) Linux Live-ISO
4 # Authors:       grml-team (grml.org),
5 #                (c) Michael Prokop <mika@grml.org>,
6 #                (c) Thorsten Glaser <tg@mirbsd.org>
7 # Bug-Reports:   see http://grml.org/bugs/
8 # License:       This file is licensed under the GPL v2 or any later version.
9 ################################################################################
10
11 # some misc and global stuff {{{
12 export LANG=C
13 export LC_ALL=C
14
15 # define function getfilesize before "set -e"
16 if stat --help >/dev/null 2>&1; then
17   getfilesize='stat -c %s'  # GNU stat
18 else
19   getfilesize='stat -f %z'  # BSD stat
20 fi
21
22 # exit on any error:
23 # disable for now since it seems to cause some problems
24 # set -e
25
26 # global variables
27 GRML_LIVE_VERSION='0.16.1'
28 PN="$(basename $0)"
29 CMDLINE="$0 $@"
30 ADDONS_LIST_FILE='/boot/isolinux/addons_list.cfg'
31 # }}}
32
33 # usage information {{{
34 usage()
35 {
36   echo "
37 $PN - build process script for generating a (grml based) Linux Live-ISO
38
39 Usage: $PN [options, see as follows]
40
41    -a <architecture>       architecture; available values: i386 and amd64
42    -A                      ensure clean build and pack artifacts
43    -b                      build the ISO without updating the chroot via FAI
44    -B                      build the ISO without touching the chroot (skips cleanup)
45    -c <classe[s]>          classes to be used for building the ISO via FAI
46    -C <configfile>         configuration file for grml-live
47    -d <date>               use specified date instead of build time as date of release
48    -D <configdir>          use specified configuration directory instead of /etc/grml/fai
49    -F                      force execution without prompting
50    -g <grml_name>          set the grml flavour name
51    -h                      display short usage information and exit
52    -i <iso_name>           name of ISO
53    -I <src_directory>      directory which provides files that should become
54                            part of the chroot/ISO
55    -n                      skip generation of ISO
56    -N                      bootstrap (build chroot) only, do not create files for ISO
57    -o <output_directory>   main output directory of the build process
58    -q                      skip mksquashfs
59    -r <release_name>       release name
60    -s <suite>              Debian suite; values: etch, lenny, squeeze, sid
61    -t <template_directory> place of the templates
62    -u                      update existing chroot instead of rebuilding it from scratch
63    -v <version_number>     specify version number of the release
64    -V                      increase verbosity in the build process
65    -z                      use ZLIB instead of LZMA/XZ compression
66
67 Usage examples:
68
69     $PN
70     $PN -c GRMLBASE,GRML_MEDIUM,I386 -o /dev/shm/grml
71     $PN -c GRMLBASE,GRML_SMALL,REMOVE_DOCS,I386 -g grml-small -v 1.0
72     $PN -c GRMLBASE,GRML_FULL,I386 -i grml_0.0-1.iso -v 0.0-1
73     $PN -c GRMLBASE,GRML_FULL,I386 -s sid -V -r 'grml-live rocks'
74
75 More details: man grml-live + /usr/share/doc/grml-live/grml-live.html
76               http://grml.org/grml-live/
77
78 Please send your bug reports and feedback to the grml-team: http://grml.org/bugs/
79 "
80 }
81
82 # make sure it's possible to get usage information without being
83 # root or actually executing the script
84 if [ "$1" = '-h' -o "$1" = '--help' ] ; then
85    usage
86    [ "$(id -u 2>/dev/null)" != 0 ] && echo "Please notice that this script requires root permissions."
87    exit 0
88 fi
89 # }}}
90
91 # some runtime checks {{{
92 # we need root permissions for the build-process:
93 if [ "$(id -u 2>/dev/null)" != 0 ] ; then
94    echo "Error: please run this script with uid 0 (root)." >&2
95    exit 1
96 fi
97
98 if [ -r /var/run/fai/FAI_INSTALLATION_IN_PROGRESS ] ; then
99    echo "/usr/sbin/fai already running or was aborted before.">&2
100    echo "You may remove /var/run/fai/FAI_INSTALLATION_IN_PROGRESS and try again.">&2
101    exit 1
102 fi
103
104 # see #449236
105 if [ -r /var/run/fai/fai_softupdate_is_running ] ; then
106    echo "/usr/sbin/fai softupdate already running or was aborted before.">&2
107    echo "You may remove /var/run/fai/fai_softupdate_is_running and try again.">&2
108    exit 1
109 fi
110 # }}}
111
112 # lsb-functions and configuration stuff {{{
113 # make sure they are not set by default
114 VERBOSE=''
115 FORCE=''
116 UPDATE=''
117 BUILD_ONLY=''
118 BUILD_DIRTY=''
119 BOOTSTRAP_ONLY=''
120 HOSTNAME=''
121
122 # don't use colors/escape sequences
123 if [ -r /lib/lsb/init-functions ] ; then
124   . /lib/lsb/init-functions
125   ! log_use_fancy_output && NOCOLORS=true
126 fi
127
128 if [ -r /etc/grml/lsb-functions ] ; then
129    . /etc/grml/lsb-functions
130 else
131    einfo()  { echo "  [*] $*" ;}
132    eerror() { echo "  [!] $*">&2 ;}
133    ewarn()  { echo "  [x] $*" ;}
134    eend()   { return 0 ;}
135    eindent()  { return 0 ;}
136    eoutdent() { return 0 ;}
137 fi
138
139 # source main configuration file:
140 LIVE_CONF=/etc/grml/grml-live.conf
141 . $LIVE_CONF
142 # }}}
143
144 # umount all directories {{{
145 umount_all() {
146    # make sure we don't leave any mounts - FAI doesn't remove them always
147    umount $CHROOT_OUTPUT/proc 2>/dev/null || /bin/true
148    umount $CHROOT_OUTPUT/sys  2>/dev/null || /bin/true
149    umount $CHROOT_OUTPUT/dev/pts 2>/dev/null || /bin/true
150    umount $CHROOT_OUTPUT/dev 2>/dev/null || /bin/true
151    [ -n "$MIRROR_DIRECTORY" ] && umount "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
152 }
153 # }}}
154
155 # clean exit {{{
156 bailout() {
157   rm -f /var/run/fai/fai_softupdate_is_running \
158         /var/run/fai/FAI_INSTALLATION_IN_PROGRESS
159   [ -n "$SQUASHFS_STDERR" ]  && rm -rf "$SQUASHFS_STDERR"
160   umount_all
161   [ -n "$1" ] && EXIT="$1" || EXIT="1"
162   [ -n "$2" ] && eerror "$2">&2
163   if [ -n "$PACK_ARTIFACTS" ]; then
164     log "Cleaning up"
165     einfo "Cleaning up"
166     [ -n "${CHROOT_OUTPUT}" -a -d "${CHROOT_OUTPUT}" ] && rm -r "${CHROOT_OUTPUT}"
167     [ -n "${BUILD_OUTPUT}"  -a -d "${BUILD_OUTPUT}"  ] && rm -r "${BUILD_OUTPUT}"
168     eend 0
169   fi
170   log "------------------------------------------------------------------------------"
171   exit "$EXIT"
172 }
173 trap bailout 1 2 3 3 6 9 14 15
174 trap umount_all EXIT
175 # }}}
176
177 # some important functions {{{
178
179 # log output:
180 # usage: log "string to log"
181 log() { echo "$*" >> $LOGFILE ; }
182
183 # cut string at character number int = $1
184 # usage: cut_string 5 "1234567890" will output "12345"
185 cut_string() {
186   [ -n "$2" ] || return 1
187   echo "$2" | head -c "$1"; echo -ne "\n"
188 }
189
190 # prepend int = $1 spaces before string = $2
191 # usage: extend_string_begin 5 "123" will output "  123"
192 extend_string_begin() {
193   [ -n "$2" ] || return 1
194   local COUNT="$(echo $2 | wc -c)"
195   local FILL="$(expr $COUNT - $1)"
196   while [ "$FILL" -gt 1 ] ; do
197     echo -n " "
198     local FILL=$(expr $FILL - 1)
199   done
200   while [ "$FILL" -lt 1 ] ; do
201     echo -n " "
202     local FILL=$(expr $FILL + 1)
203   done
204   echo "$2" | head -c "$1"; echo -ne "\n"
205 }
206
207 # append int = $1 spaces to string = $2
208 # usage: extend_string_begin 5 "123" will output "123  "
209 extend_string_end() {
210   [ -n "$2" ] || return 1
211   echo -n "$2" | head -c "$1"
212   local COUNT="$(echo $2 | wc -c)"
213   local FILL="$(expr $COUNT - $1)"
214   while [ "$FILL" -gt 1 ] ; do
215     echo -n " "
216     local FILL=$(expr $FILL - 1)
217   done
218   while [ "$FILL" -lt 1 ] ; do
219     echo -n " "
220     local FILL=$(expr $FILL + 1)
221   done
222   echo -ne "\n"
223 }
224
225 # Copy addonfile $1 from either
226 #   * the chroot (via $2, the system path),
227 #   * or from TEMPLATE_DIRECTORY/compat (if exists),
228 #   * or from the host system (again, using $2),
229 # or warn about the missing file.
230 #
231 # This is because:
232 #   * We assume that the chroot always has a "good" version of
233 #     the file. Also it makes sources handling easier.
234 #   * On unstable, we Recommend the Debian packages containing
235 #     these files. The user can override them by putting his
236 #     "better" version into the chroot.
237 #   * On stable, the Debian packages are probably not available,
238 #     or outdated, so we look in TEMPLATE_DIRECTORY/compat first, where
239 #     our grml-live-compat package installs current file versions.
240 copy_addon_file() {
241   DEST="${BUILD_OUTPUT}/boot/$3"
242   if [ ! -d "${DEST}/" ]; then
243     mkdir -p "${DEST}"
244   fi
245   if [ -e "$CHROOT_OUTPUT/$2/$1" ]; then
246     log   "Copying $1 from chroot"
247     cp "$CHROOT_OUTPUT/$2/$1" "${DEST}/"
248     return $?
249   fi
250   if [ -e "${TEMPLATE_DIRECTORY}/compat/$3/$1" ]; then
251     log   "Copying $1 from grml-live-compat"
252     cp "${TEMPLATE_DIRECTORY}/compat/$3/$1" "${DEST}/"
253     return $?
254   fi
255   if [ -e "$2/$1" ]; then
256     log   "Copying $1 from system"
257     cp "$2/$1" "${DEST}/"
258     return $?
259   fi
260
261   msg="Missing addon file: \"$1\""
262   ewarn "$msg" ; eend 1
263   log "copy_addon_file: $msg"
264 }
265 # }}}
266
267 # read local (non-packaged) configuration {{{
268 LOCAL_CONFIG=/etc/grml/grml-live.local
269 if [ -r "$LOCAL_CONFIG" ] ; then
270    . $LOCAL_CONFIG
271 else
272    LOCAL_CONFIG=''
273 fi
274 # }}}
275
276 # command line parsing {{{
277 while getopts "a:C:c:d:D:g:i:I:o:r:s:t:v:AbBFnNquVz" opt; do
278   case "$opt" in
279     a) ARCH="$OPTARG" ;;
280     A) PACK_ARTIFACTS=1 ;;
281     b) BUILD_ONLY=1 ;;
282     B) BUILD_DIRTY=1 ;;
283     c) CLASSES="$OPTARG" ;;
284     C) CONFIG="$OPTARG" ;;
285     d) DATE="$OPTARG" ;;
286     D) GRML_FAI_CONFIG="$OPTARG" ;;
287     g) GRML_NAME="$OPTARG" ;;
288     i) ISO_NAME="$OPTARG" ;;
289     I) CHROOT_INSTALL="$OPTARG" ;;
290     n) SKIP_MKISOFS=1 ;;
291     N) BOOTSTRAP_ONLY=1; SKIP_MKISOFS=1; SKIP_MKSQUASHFS=1 ;;
292     o) OUTPUT="$OPTARG" ;;
293     q) SKIP_MKSQUASHFS=1 ;;
294     r) RELEASENAME="$OPTARG" ;;
295     s) SUITE="$OPTARG" ;;
296     t) TEMPLATE_DIRECTORY="$OPTARG";;
297     v) VERSION="$OPTARG" ;;
298     F) FORCE=1 ;;
299     u) UPDATE=1 ;;
300     V) VERBOSE="-v" ;;
301     z) SQUASHFS_ZLIB=1 ;;
302     ?) echo "invalid option -$OPTARG" >&2; bailout 1 ;;
303   esac
304 done
305 shift $(($OPTIND - 1))  # set ARGV to the first not parsed commandline parameter
306 # }}}
307
308 # assume sane defaults (if not set already) {{{
309 [ -n "$ARCH" ]                    || ARCH="$(dpkg --print-architecture)"
310 [ -n "$BOOT_METHOD" ]             || BOOT_METHOD='isolinux'
311 [ -n "$CLASSES" ]                 || CLASSES="GRMLBASE,GRML_MEDIUM,I386"
312 [ -n "$DATE" ]                    || DATE="$(date +%Y-%m-%d)"
313 [ -n "$DISTRI_INFO" ]             || DISTRI_INFO='Grml - Live Linux for system administrators   '
314 [ -n "$DISTRI_NAME" ]             || DISTRI_NAME="grml"
315 [ -n "$DISTRI_SPLASH" ]           || DISTRI_SPLASH='grml.png'
316 [ -n "$FORCE_ISO_REBUILD" ]       || FORCE_ISO_REBUILD="false"
317 [ -n "$GRML_FAI_CONFIG" ]         || GRML_FAI_CONFIG='/etc/grml/fai'
318 [ -n "$GRML_NAME" ]               || GRML_NAME='grml'
319 [ -n "$HOSTNAME" ]                || HOSTNAME='grml'
320 [ -n "$HYBRID_METHOD" ]           || HYBRID_METHOD='manifold'
321 [ -n "$NFSROOT_CONF" ]            || NFSROOT_CONF="${GRML_FAI_CONFIG}/make-fai-nfsroot.conf"
322 [ -n "$RELEASENAME" ]             || RELEASENAME='grml-live rocks'
323 [ -n "$SOURCES_LIST_OUTPUT" ]     || SOURCES_LIST_OUTPUT="${GRML_FAI_CONFIG}/config/files/etc/apt/sources.list/GRML_LIVE_SOURCES_LIST"
324 [ -n "$SQUASHFS_EXCLUDES_FILE" ]  || SQUASHFS_EXCLUDES_FILE="${GRML_FAI_CONFIG}/config/grml/squashfs-excludes"
325 [ -n "$SUITE" ]                   || SUITE='squeeze'
326 [ -n "$TEMPLATE_DIRECTORY" ]      || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
327 [ -n "$USERNAME" ]                || USERNAME='grml'
328 [ -n "$VERSION" ]                 || VERSION='0.0.1'
329
330 # output specific stuff, depends on $OUTPUT (iff not set):
331 [ -n "$OUTPUT" ]           || OUTPUT='/grml/grml-live'
332 [ -n "$BUILD_OUTPUT" ]     || BUILD_OUTPUT="$OUTPUT/grml_cd"
333 [ -n "$CHROOT_OUTPUT" ]    || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
334 [ -n "$CHROOT_ARCHIVE" ]   || CHROOT_ARCHIVE="$OUTPUT/$(basename $CHROOT_OUTPUT).tgz"
335 [ -n "$ISO_OUTPUT" ]       || ISO_OUTPUT="$OUTPUT/grml_isos"
336 [ -n "$LOG_OUTPUT" ]       || LOG_OUTPUT="$OUTPUT/grml_logs"
337 # }}}
338
339 # some misc checks before executing FAI {{{
340 [ -n "$CLASSES" ] || bailout 1 "Error: \$CLASSES unset, please set it in $LIVE_CONF or
341 specify it on the command line using the -c option."
342 [ -n "$OUTPUT" ] || bailout 1 "Error: \$OUTPUT unset, please set it in $LIVE_CONF or
343 specify it on the command line using the -o option."
344
345 # trim characters that are known to cause problems inside $GRML_NAME;
346 # for example isolinux does not like '-' inside the directory name
347 [ -n "$GRML_NAME" ] && export SHORT_NAME="$(echo $GRML_NAME | tr -d ',./;\- ')"
348
349 # export variables to have them available in fai scripts:
350 [ -n "$GRML_NAME" ]   && export GRML_NAME="$GRML_NAME"
351 [ -n "$RELEASENAME" ] && export RELEASENAME="$RELEASENAME"
352 # }}}
353
354 # ZERO_LOGFILE - check for backwards compatibility reasons {{{
355 # this was default behaviour until grml-live 0.9.34:
356 if [ -n "$ZERO_LOGFILE" ] ; then
357    PRESERVE_LOGFILE='' # make sure it's cleaned then
358    ewarn "Please consider disabling the \$ZERO_LOGFILE option as grml-live clears..."
359    ewarn "... the logfile $LOGFILE by default (unless \$PRESERVE_LOGFILE is set) nowadays."
360    eend 0
361 fi
362 # }}}
363
364 # ask user whether the setup is ok {{{
365 if [ -z "$FORCE" ] ; then
366    echo
367    echo "${PN} [${GRML_LIVE_VERSION}]: check your configuration (or use -F to force execution):"
368    echo
369    echo "  FAI classes:       $CLASSES"
370    [ -r "$LOCAL_CONFIG" ]        && echo "  Local config:      /etc/grml/grml-live.local"
371    [ -n "$CONFIG" ]              && echo "  Configuration:     $CONFIG"
372    [ -n "$GRML_FAI_CONFIG" ]     && echo "  Config directory:  $GRML_FAI_CONFIG"
373    echo "  main directory:    $OUTPUT"
374    [ -n "$CHROOT_OUTPUT" ]       && echo "  Chroot target:     $CHROOT_OUTPUT"
375    [ -n "$BUILD_OUTPUT" ]        && echo "  Build target:      $BUILD_OUTPUT"
376    [ -n "$ISO_OUTPUT" ]          && echo "  ISO target:        $ISO_OUTPUT"
377    [ -n "$GRML_NAME" ]           && echo "  Grml name:         $GRML_NAME"
378    [ -n "$RELEASENAME" ]         && echo "  Release name:      $RELEASENAME"
379    [ -n "$DATE" ]                && echo "  Build date:        $DATE"
380    [ -n "$VERSION" ]             && echo "  Grml version:      $VERSION"
381    [ -n "$SUITE" ]               && echo "  Debian suite:      $SUITE"
382    [ -n "$ARCH" ]                && echo "  Architecture:      $ARCH"
383    [ -n "$BOOT_METHOD" ]         && echo "  Boot method:       $BOOT_METHOD"
384    [ -n "$HYBRID_METHOD" ]       && echo "  Hybrid method:     $HYBRID_METHOD"
385    [ -n "$TEMPLATE_DIRECTORY" ]  && echo "  Template files:    $TEMPLATE_DIRECTORY"
386    [ -n "$CHROOT_INSTALL" ]      && echo "  Install files from directory to chroot:  $CHROOT_INSTALL"
387    [ -n "$BOOTID" ]              && echo "  Boot identifier:   $BOOTID"
388    [ -n "$NO_BOOTID" ]           && echo "  Skipping bootid feature."
389    [ -n "$DEFAULT_BOOTOPTIONS" ] && echo "  Adding default bootoptions: \"$DEFAULT_BOOTOPTIONS\""
390    [ -n "$FAI_ARGS" ]            && echo "  Additional arguments for FAI: $FAI_ARGS"
391    [ -n "$LOGFILE" ]             && echo "  Logging to file:   $LOGFILE"
392    [ -n "$SQUASHFS_ZLIB" ]       && echo "  Using ZLIB (instead of LZMA/XZ) compression."
393    [ -n "$SQUASHFS_OPTIONS" ]    && echo "  Using SQUASHFS_OPTIONS ${SQUASHFS_OPTIONS}"
394    [ -n "$VERBOSE" ]             && echo "  Using VERBOSE mode."
395    [ -n "$PACK_ARTIFACTS" ]      && echo "  Will prepare packed artifacts and ensure clean build."
396    [ -n "$UPDATE" ]              && echo "  Executing UPDATE instead of fresh installation."
397    if [ -n "$BOOTSTRAP_ONLY" ] ; then
398      echo "  Bootstrapping only and not building (files for) ISO."
399    else
400      [ -n "$SKIP_MKSQUASHFS" ]     && echo "  Skipping creation of SQUASHFS file."
401      [ -n "$SKIP_MKISOFS" ]        && echo "  Skipping creation of ISO file."
402      [ -n "$BUILD_ONLY" ]          && echo "  Executing BUILD_ONLY instead of fresh installation or UPDATE."
403      [ -n "$BUILD_DIRTY" ]         && echo "  Executing BUILD_DIRTY to leave chroot untouched."
404    fi
405    echo
406    echo -n "Is this ok for you? [y/N] "
407    read a
408    if ! [ "$a" = 'y' -o "$a" = 'Y' ] ; then
409       bailout 1 "Exiting as requested."
410    fi
411    echo
412 fi
413 # }}}
414
415 # clean up before start {{{
416 if [ -n "${PACK_ARTIFACTS}" ]; then
417   echo "Wiping old artifacts"
418   [ -n "${CHROOT_OUTPUT}"  -a -d "${CHROOT_OUTPUT}"  ] && rm -r "${CHROOT_OUTPUT}"
419   [ -n "${CHROOT_ARCHIVE}" -a -d "${CHROOT_ARCHIVE}" ] && rm -r "${CHROOT_ARCHIVE}"
420   [ -n "${BUILD_OUTPUT}"   -a -d "${BUILD_OUTPUT}"   ] && rm -r "${BUILD_OUTPUT}"
421   [ -n "${ISO_OUTPUT}"     -a -d "${ISO_OUTPUT}"     ] && rm -r "${ISO_OUTPUT}"
422   [ -n "${LOG_OUTPUT}"     -a -d "${LOG_OUTPUT}"     ] && rm -r "${LOG_OUTPUT}"
423 fi
424 # }}}
425
426 # create log file {{{
427 [ -n "$LOGFILE" ] || LOGFILE=${LOG_OUTPUT}/grml-live.log
428 mkdir -p $(dirname "${LOGFILE}")
429 touch $LOGFILE
430 chown root:adm $LOGFILE
431 chmod 664 $LOGFILE
432 # }}}
433
434 # clean/zero/remove logfiles {{{
435
436 if [ -n "$PRESERVE_LOGFILE" ] ; then
437    echo "Preserving logfile $LOGFILE as requested via \$PRESERVE_LOGFILE"
438 else
439    # make sure it is empty (as it is e.g. appended to grml-live-db)
440    echo -n > $LOGFILE
441 fi
442
443 if [ -n "$ZERO_FAI_LOGFILE" ] ; then
444    if [ -d /var/log/fai/"$HOSTNAME" ] ; then
445       rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last)"
446       rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-dirinstall)"
447       rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-softupdate)"
448       rm -f /var/log/fai/"$HOSTNAME"/last \
449             /var/log/fai/"$HOSTNAME"/last-dirinstall \
450             /var/log/fai/"$HOSTNAME"/last-softupdate
451    fi
452 fi
453 # }}}
454
455 # source config and startup {{{
456 if [ -n "$CONFIG" ] ; then
457    if ! [ -f "$CONFIG" ] ; then
458       log    "Error: $CONFIG could not be read. Exiting. [$(date)]"
459       eerror "Error: $CONFIG could not be read. Exiting." ; eend 1
460       bailout 1
461    else
462       log "Sourcing $CONFIG"
463       . $CONFIG
464    fi
465 fi
466
467 start_seconds=$(cut -d . -f 1 /proc/uptime)
468 log "------------------------------------------------------------------------------"
469 log "Starting grml-live [${GRML_LIVE_VERSION}] run on $(date)"
470 if [ -n "$LOCAL_CONFIG" ]; then
471   log "Using local config file: $LOCAL_CONFIG"
472 fi
473 log "Executed grml-live command line:"
474 log "$CMDLINE"
475
476 einfo "Logging actions to logfile $LOGFILE"
477 # }}}
478
479 # on-the-fly configuration {{{
480 mkdir -p "$(dirname $SOURCES_LIST_OUTPUT)" # might not be present in -D config space
481
482 cat > "$SOURCES_LIST_OUTPUT" << EOF
483 # NOTE: This file is *NOT* meant for manual customisation! This file is
484 # installed temporarily only by grml-live and will be overriden in the
485 # installation and configuration process then.
486 EOF
487
488 if [ -n "$MIRROR_DIRECTORY" ] ; then
489   if ! [ -d "$MIRROR_DIRECTORY/debian" ] ; then
490     log    "Error: $MIRROR_DIRECTORY/debian does not seem to exist. Exiting. [$(date)]"
491     eerror "Error: $MIRROR_DIRECTORY/debian does not seem to exist. Exiting." ; eend 1
492     bailout 1
493   fi
494   echo "$MIRROR_SOURCES" >> "$SOURCES_LIST_OUTPUT"
495 fi
496
497 if [ -n "$FAI_DEBOOTSTRAP" ] ; then
498   sed "s#^FAI_DEBOOTSTRAP=.*#FAI_DEBOOTSTRAP=\"$FAI_DEBOOTSTRAP\"#" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
499 fi
500
501 # does this suck? YES!
502 # /usr/share/debootstrap/scripts/unstable does not exist, instead use 'sid':
503 case $SUITE in
504    unstable) SUITE='sid' ;;
505    # make sure that we *NEVER* write any broken suite name to sources.list,
506    # otherwise we won't be able to adjust it one next (correct) execution
507    stable)   ;;
508    testing)  ;;
509    etch)     ;;
510    lenny)    ;;
511    squeeze)  ;;
512    wheezy)   ;;
513    sid)      ;;
514    *) echo "Sorry, $SUITE is not a valid Debian suite, exiting.">&2; bailout 1 ;;
515 esac
516 export SUITE # make sure it's available in FAI scripts
517
518 if [ -n "${GRML_LIVE_SOURCES:-}" ] ; then
519   DIST=" etch\| stable\| lenny\| squeeze\| wheezy\| testing\| sid\| unstable"
520   echo "# generated based on \$GRML_LIVE_SOURCES by grml-live
521 $GRML_LIVE_SOURCES" | \
522     sed -e "s/\(^deb .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/;
523             s/\(^deb-src .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/" >> "$SOURCES_LIST_OUTPUT"
524 else
525   cat >> "$SOURCES_LIST_OUTPUT" << EOF
526 # generated by grml-live
527 deb http://deb.grml.org/            grml-stable  main
528 deb http://deb.grml.org/            grml-testing main
529 deb http://cdn.debian.net/debian $SUITE  main contrib non-free
530 EOF
531 fi
532
533 # notice: activate grml-live pool when building against unstable or testing:
534 if grep -qwe unstable -qwe sid -qwe testing -qwe wheezy "$SOURCES_LIST_OUTPUT" ; then
535    grep -q 'grml-live.*main' "$SOURCES_LIST_OUTPUT" || \
536    grep grml-stable "$SOURCES_LIST_OUTPUT" | \
537         sed 's/grml-stable/grml-live/' >> "$SOURCES_LIST_OUTPUT"
538 else
539    grep -q 'grml-live.*main' "$SOURCES_LIST_OUTPUT" && \
540    sed -i 's/.*grml-live.*main/# removed grml-live repository/' "$SOURCES_LIST_OUTPUT"
541 fi
542
543 for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" "$NFSROOT_CONF" ; do
544     if [ -n "$file" ] ; then
545        sed "s|^FAI_DEBOOTSTRAP=\"[a-z]* |FAI_DEBOOTSTRAP=\"$SUITE |" "$file" | sponge "$file"
546     fi
547 done
548
549 # validate whether the specified architecture class matches the
550 # architecture (option), otherwise installation of kernel will fail
551 if echo $CLASSES | grep -qi i386 ; then
552    if ! [[ "$ARCH" == "i386" ]] ; then
553       log    "Error: You specified the I386 class but are trying to build something else (AMD64?)."
554       eerror "Error: You specified the I386 class but are trying to build something else (AMD64?)."
555       eerror "Tip:   Either invoke grml-live with '-a i386' or adjust the architecture class. Exiting."
556       eend 1
557       bailout
558    fi
559 elif echo $CLASSES | grep -qi amd64 ; then
560    if ! [[ "$ARCH" == "amd64" ]] ; then
561       log    "Error: You specified the AMD64 class but are trying to build something else (I386?)."
562       eerror "Error: You specified the AMD64 class but are trying to build something else (I386?)."
563       eerror "Tip:   Either invoke grml-live with '-a amd64' or adjust the architecture class. Exiting."
564       eend 1
565       bailout
566    fi
567 fi
568
569 if grep -q -- 'FAI_DEBOOTSTRAP_OPTS.*--arch' "$NFSROOT_CONF" ; then
570    sed "s/--arch [a-z0-9]* /--arch $ARCH /" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
571 else
572    sed "s|^FAI_DEBOOTSTRAP_OPTS=\"\(.*\)|FAI_DEBOOTSTRAP_OPTS=\"--arch $ARCH \1|" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
573 fi
574 # }}}
575
576 # CHROOT_OUTPUT - execute FAI {{{
577 if [ -n "$BUILD_DIRTY" ]; then
578    log   "Skipping stage 'fai' as requested via option -B"
579    ewarn "Skipping stage 'fai' as requested via option -B" ; eend 0
580 else
581    [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
582
583    # provide inform fai about the ISO we build
584    [ -d "$CHROOT_OUTPUT/etc/" ] || mkdir -p "$CHROOT_OUTPUT/etc/"
585    echo '# This file has been generated by grml-live.' > "$CHROOT_OUTPUT/etc/grml_live_version"
586    [ -n "$GRML_LIVE_VERSION" ] && echo "GRML_LIVE_VERSION=$GRML_LIVE_VERSION" >> "$CHROOT_OUTPUT/etc/grml_live_version"
587    [ -n "$SUITE" ] && echo "SUITE=$SUITE" >> "$CHROOT_OUTPUT/etc/grml_live_version"
588
589    if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
590       FAI_ACTION=softupdate
591    else
592       FAI_ACTION=dirinstall
593    fi
594
595    if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
596       if ! [ -r "$CHROOT_OUTPUT/etc/debian_version" ] ; then
597          log    "Error: does not look like you have a working chroot. Updating/building not possible."
598          eerror "Error: does not look like you have a working chroot. Updating/building not possible. (Drop -u/-b option?)"
599          eend 1
600          bailout 20
601       fi
602    fi
603
604    if [ -d "$CHROOT_OUTPUT/bin" -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
605       log   "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already."
606       ewarn "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already." ; eend 0
607    else
608       mkdir -p "$CHROOT_OUTPUT" || bailout 5 "Problem with creating $CHROOT_OUTPUT for FAI"
609
610       if [ -n "${MIRROR_DIRECTORY}" ] ; then
611          mkdir -p "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
612          mount --bind "${MIRROR_DIRECTORY}" "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
613       fi
614
615       # tell dpkg to use "unsafe io" during the build
616       [ -d "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d" ] || mkdir -p "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d"
617       echo force-unsafe-io > "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
618
619       log "Executed FAI command line:"
620       log "BUILD_ONLY=$BUILD_ONLY BOOTSTRAP_ONLY=$BOOTSTRAP_ONLY fai $VERBOSE -C $GRML_FAI_CONFIG -s file:///$GRML_FAI_CONFIG/config -c$CLASSES -u $HOSTNAME $FAI_ACTION $CHROOT_OUTPUT $FAI_ARGS"
621       BUILD_ONLY="$BUILD_ONLY" BOOTSTRAP_ONLY="$BOOTSTRAP_ONLY" fai $VERBOSE \
622                   -C "$GRML_FAI_CONFIG" -s "file:///$GRML_FAI_CONFIG/config" -c"$CLASSES" \
623                   -u "$HOSTNAME" "$FAI_ACTION" "$CHROOT_OUTPUT" $FAI_ARGS | tee -a $LOGFILE
624       RC="$PIPESTATUS" # notice: bash-only
625
626       rm -f "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
627
628       FORCE_ISO_REBUILD=true
629
630       if [ "$RC" != 0 ] ; then
631          log    "Error: critical error while executing fai [exit code ${RC}]. Exiting."
632          eerror "Error: critical error while executing fai [exit code ${RC}]. Exiting." ; eend 1
633          bailout 1
634       else
635          einfo "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
636          log   "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
637          echo "$GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]" > $CHROOT_OUTPUT/etc/grml_version
638          chmod 644 $CHROOT_OUTPUT/etc/grml_version
639          einfo "Rebuilding initramfs"
640          # make sure new /etc/grml_version reaches initramfs, iterate over all
641          # present kernel versions (note: we can't really handle more than one
642          # kernel version anyway right now)
643          # chroot $CHROOT_OUTPUT update-initramfs -u -t => might break when using kernel-package :(
644          for initrd in "$(basename $CHROOT_OUTPUT/boot/vmlinuz-*)" ; do
645            if ! chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -c ; then
646              einfo "Creating fresh initrd did not work, trying update instead:"
647              log   "Creating fresh initrd did not work, trying update instead:"
648              chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -u
649            fi
650          done
651          eend $?
652       fi
653
654       # move fai logs into grml_logs directory
655       mkdir -p "$LOG_OUTPUT"/fai/
656       cp -r "$CHROOT_OUTPUT"/var/log/fai/"$HOSTNAME"/last/* "$LOG_OUTPUT"/fai/
657       chown root:adm "$LOG_OUTPUT"/fai/*
658       chmod 664 "$LOG_OUTPUT"/fai/*
659       rm -rf "$CHROOT_OUTPUT"/var/log/fai
660
661       # Remove all FAI logs from chroot if class RELEASE is used:
662       rm -f "$CHROOT_OUTPUT"/var/log/install_packages.list
663
664       umount_all
665
666       # notice: 'fai dirinstall' does not seem to exit appropriate, so:
667       ERROR=''
668       CHECKLOG=/var/log/fai/$HOSTNAME/last
669       if [ -r "$CHECKLOG/software.log" ] ; then
670          # 1 errors during executing of commands
671          grep 'dpkg: error processing' $CHECKLOG/software.log >> $LOGFILE && ERROR=1
672          grep 'E: Method http has died unexpectedly!' $CHECKLOG/software.log >> $LOGFILE && ERROR=2
673          grep 'ERROR: chroot' $CHECKLOG/software.log >> $LOGFILE && ERROR=3
674          grep 'E: Failed to fetch' $CHECKLOG/software.log >> $LOGFILE && ERROR=4
675          grep 'Unable to write mmap - msync (28 No space left on device)' $CHECKLOG/software.log >> $LOGFILE && ERROR=5
676       fi
677
678       if [ -r "$CHECKLOG/shell.log" ] ; then
679          grep 'FAILED with exit code' $CHECKLOG/shell.log >> $LOGFILE && ERROR=6
680       fi
681
682       if [ -n "$ERROR" ] ; then
683          log    "Error: there was a critical error [${ERROR}] during execution of stage 'fai dirinstall' [$(date)]"
684          eerror "Error: there was a critical error during execution of stage 'fai dirinstall'"
685          eerror "Note:  check out ${CHECKLOG}/ for details. [exit ${ERROR}]"
686          eend 1
687          bailout 1
688       else
689          log "Finished execution of stage 'fai dirinstall' [$(date)]"
690          einfo "Finished execution of stage 'fai dirinstall'"
691       fi
692
693       einfo "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
694       log   "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
695       eend 0
696    fi
697 fi # BUILD_DIRTY?
698 # }}}
699
700 # package validator {{{
701 CHECKLOG=/var/log/fai/$HOSTNAME/last
702 # package validator
703 if [ -r "$CHECKLOG/package_errors.log" ] && grep -q '[a-z]' "$CHECKLOG/package_errors.log" ; then
704
705    if [ -n "$EXIT_ON_MISSING_PACKAGES" -a -z "$BUILD_DIRTY" ] ; then
706       eerror "The following packages were requested for installation but could not be processed:"
707       cat $CHECKLOG/package_errors.log
708       eerror "... exiting as requested via \$EXIT_ON_MISSING_PACKAGES."
709       eend 1
710       bailout 13
711    else
712       ewarn "The following packages were requested for installation but could not be processed:"
713       cat $CHECKLOG/package_errors.log
714       eend 0
715    fi
716 fi
717 # }}}
718
719 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
720 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
721 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
722
723 # prepare ISO
724 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
725   if [ -n "$BOOTSTRAP_ONLY" ] ; then
726      log   "Skipping stage 'boot' as building with bootstrap only."
727      ewarn "Skipping stage 'boot' as building with bootstrap only." ; eend 0
728   else
729     if [ -d "$BUILD_OUTPUT"/boot/isolinux -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
730        log   "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already."
731        ewarn "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already." ; eend 0
732     else
733        # booting stuff:
734        [ -d "$BUILD_OUTPUT"/boot/isolinux ] || mkdir -p "$BUILD_OUTPUT"/boot/isolinux
735        [ -d "$BUILD_OUTPUT"/boot/"${SHORT_NAME}" ] || mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"
736
737        # if we don't have an initrd we a) can't boot and b) there was an error
738        # during build, so check for the file:
739        INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
740        if [ -n "$INITRD" ] ; then
741           cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/initrd.gz
742           find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
743        else
744           log    "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
745           eerror "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
746           bailout 10
747        fi
748
749        KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
750        if [ -n "$KERNEL_IMAGE" ] ; then
751           cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/linux26
752        else
753           log    "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
754           eerror "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
755           bailout 11
756        fi
757
758        [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
759        if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
760           log    "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
761           eerror "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
762           bailout 8
763        fi
764
765        # copy _required_ isolinux files
766        for file in ifcpu64.c32 isolinux.bin vesamenu.c32; do
767          copy_addon_file "${file}" /usr/lib/syslinux isolinux
768        done
769
770        # *always* copy files to output directory so the variables
771        # get adjusted according to the build.
772        cp ${TEMPLATE_DIRECTORY}/boot/isolinux/*  "$BUILD_OUTPUT"/boot/isolinux/
773
774        if [ -n "$NO_ADDONS" ] ; then
775           log   "Skipping installation of boot addons as requested via \$NO_ADDONS."
776           einfo "Skipping installation of boot addons as requested via \$NO_ADDONS."; eend 0
777        else
778           if ! [ -d "$TEMPLATE_DIRECTORY"/boot/addons ] ; then
779             log   "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)"
780             ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
781           else
782             # copy addons from system packages or grml-live-compat
783             copy_addon_file ipxe.lkrn /usr/lib/ipxe addons
784             copy_addon_file pci.ids /usr/share/misc addons
785             copy_addon_file memtest86+.bin /boot addons
786             for file in memdisk chain.c32 hdt.c32 menu.c32; do
787               copy_addon_file "${file}" /usr/lib/syslinux addons
788             done
789
790             # make memtest filename FAT16/8.3 compatible
791             mv "${BUILD_OUTPUT}/boot/addons/memtest86+.bin" \
792               "${BUILD_OUTPUT}/boot/addons/memtest"
793
794             # copy only files so we can handle bsd4grml on its own
795             for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
796               test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
797             done
798
799             if [ -n "$NO_ADDONS_BSD4GRML" ] ; then
800                log   "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."
801                einfo "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."; eend 0
802             else
803                if [ -d "$TEMPLATE_DIRECTORY"/boot/addons/bsd4grml ] ; then
804                  cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
805                else
806                  log   "Missing addon file: bsd4grml"
807                  ewarn "Missing addon file: bsd4grml" ; eend 0
808                fi
809             fi
810
811           fi # no "$TEMPLATE_DIRECTORY"/boot/addons
812        fi # NO_ADDONS
813
814        if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
815          mkdir -p "${BUILD_OUTPUT}/boot/grub"
816        fi
817        cp ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
818
819        if [ -e ${TEMPLATE_DIRECTORY}/compat/grub/linux.mod ]; then
820          cp "${TEMPLATE_DIRECTORY}"/compat/grub/* "${BUILD_OUTPUT}"/boot/grub/
821        else
822          if ! which "grub-mkimage" >/dev/null 2>&1 ; then
823            log   "grub-mkimage not found, skipping Grub step therefore." ; eend 0
824            ewarn "grub-mkimage not found, skipping Grub step therefore."
825            ewarn "Please install grub-pc-bin or grub-common >= 1.98+20100804-14." ; eend 0
826          elif ! grub-mkimage --help | grep -q -- --format ; then
827            log   "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore." ; eend 0
828            ewarn "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore."
829            ewarn "Please install grub-common >= 1.98+20100804-14 or grub-pc-bin." ; eend 0
830          else
831            # copy system grub files if grml-live-compat is not installed
832            cp -a /usr/lib/grub/*-pc/*.mod "${BUILD_OUTPUT}"/boot/grub/
833            cp -a /usr/lib/grub/*-pc/*.o "${BUILD_OUTPUT}"/boot/grub/
834            cp -a /usr/lib/grub/*-pc/*.lst "${BUILD_OUTPUT}"/boot/grub/
835            cp -a /usr/share/grub/ascii.pf2 "${BUILD_OUTPUT}"/boot/grub/
836            grub-mkimage -d /usr/lib/grub/*-pc -o \
837              "${BUILD_OUTPUT}/boot/grub/core.img" biosdisk iso9660 --format=i386-pc
838          fi
839        fi
840
841        if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
842           log    "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
843           eerror "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
844           bailout 9
845        fi
846
847        [ -d "$BUILD_OUTPUT"/GRML ] || mkdir "$BUILD_OUTPUT"/GRML
848        cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/
849
850        # adjust boot splash information:
851        RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
852        RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
853        RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
854
855        if [ -r "$BUILD_OUTPUT"/GRML/grml-version ] ; then
856           sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/grml-version
857           sed -i "s/%DATE%/$DATE/"                                      "$BUILD_OUTPUT"/GRML/grml-version
858        fi
859
860        # make sure the squashfs filename is set accordingly:
861        SQUASHFS_NAME="$GRML_NAME.squashfs"
862
863        if [ -n "$NO_BOOTID" ] ; then
864           log   'Skipping bootid feature as requested via $NO_BOOTID.'
865           einfo 'Skipping bootid feature as requested via $NO_BOOTID.'
866        else
867           [ -n "$BOOTID" ] || BOOTID="$(echo ${GRML_NAME}${VERSION} | tr -d ',./;\- ')"
868           [ -d "$BUILD_OUTPUT"/conf ] || mkdir "$BUILD_OUTPUT"/conf
869           einfo "Generating /conf/bootid.txt with entry ${BOOTID}."
870           log   "Generating /conf/bootid.txt with entry ${BOOTID}."
871           echo "$BOOTID" > "$BUILD_OUTPUT"/conf/bootid.txt
872           eend $?
873        fi
874
875        # adjust all variables in the templates with the according distribution information
876        for file in "${BUILD_OUTPUT}"/boot/isolinux/*.cfg "${BUILD_OUTPUT}"/boot/isolinux/*.msg \
877                    "${BUILD_OUTPUT}"/boot/grub/* ; do
878          if [ -r "${file}" ] ; then
879            sed -i "s/%ARCH%/$ARCH/g"                    "${file}"
880            sed -i "s/%DATE%/$DATE/g"                    "${file}"
881            sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/g"      "${file}"
882            sed -i "s/%DISTRI_NAME%/$DISTRI_NAME/g"      "${file}"
883            sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/g"  "${file}"
884            sed -i "s/%GRML_NAME%/$GRML_NAME/g"          "${file}"
885            sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/g"  "${file}"
886            sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/g"    "${file}"
887            sed -i "s/%SHORT_NAME%/$SHORT_NAME/g"        "${file}"
888            sed -i "s/%VERSION%/$VERSION/g"              "${file}"
889
890            [ -n "$DEFAULT_BOOTOPTIONS" ] && sed -i "s/ boot=live/ boot=live $DEFAULT_BOOTOPTIONS/"  "${file}"
891
892            if [ -n "$NO_BOOTID" ] ; then
893               sed -i "s/ bootid=%BOOTID%//g" "${file}" # drop bootid bootoption
894            else
895               sed -i "s/%BOOTID%/$BOOTID/g" "${file}" # adjust bootid=... argument
896            fi
897          fi
898        done
899
900        # adjust bootsplash accordingly but make sure the string has the according lenght
901        SQUASHFS_NAME="$(cut_string 20 "$SQUASHFS_NAME")"
902        SQUASHFS_NAME="$(extend_string_end 20 "$SQUASHFS_NAME")"
903        for file in f4 f5 ; do
904           if [ -r "${BUILD_OUTPUT}/boot/isolinux/${file}" ] ; then
905              sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
906              sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
907           fi
908        done
909
910        # generate addon list
911        rm -f "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
912        for name in "${BUILD_OUTPUT}"/boot/isolinux/addon_*.cfg ; do
913          include_name=$(basename "$name")
914          echo "include $include_name"  >> "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
915        done
916
917        if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
918           log "including grmlmain.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
919           echo "include grmlmain.cfg"    >  "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
920           echo "include default.cfg"     >  "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
921           echo "include menuoptions.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
922           echo "include grml.cfg"        >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
923
924           for f in "${BUILD_OUTPUT}"/boot/isolinux/submenu*.cfg ; do
925             echo "include $(basename $f)"     >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
926           done
927
928           echo "include options.cfg"     >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
929           if [ ! -n "$NO_ADDONS" ] ; then
930             echo "include addons.cfg"    >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
931           fi
932           echo "include isoprompt.cfg"   >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
933           echo "include hd.cfg"          >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
934           echo "include hidden.cfg"      >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
935        else # assume we are building a custom distribution:
936           log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
937           einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
938           if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
939             log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
940             eindent
941             einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
942             eoutdent
943             eend $?
944          else
945             log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
946             echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
947             [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
948           fi
949        fi
950
951        # use old style console based isolinux method only if requested:
952        if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
953           log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
954           einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
955           if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
956             einfo "include for console.cfg already found, nothing to do."
957             eend 0
958           else
959             log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
960             einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
961             echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
962             eend $?
963           fi
964        else
965           log 'Using graphical boot menu.'
966           if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
967             log "include for vesamenu.cfg already found, nothing to do."
968           else
969             log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
970             echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
971           fi
972        fi
973
974        if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
975           sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
976        fi
977
978        DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot
979        if ! [ -r "$DPKG_LIST" ] ; then
980           ewarn "$DPKG_LIST could not be read, ignoring to store package information on ISO therefore."
981        else
982           einfo "Storing package list information as /GRML/${GRML_NAME}-packages.txt on ISO."
983           cp "$DPKG_LIST" "${BUILD_OUTPUT}/GRML/${GRML_NAME}-packages.txt"
984           eend $?
985        fi
986
987        # autostart for Windows:
988        if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
989           cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
990        fi
991
992     FORCE_ISO_REBUILD=true
993     einfo "Finished execution of stage 'boot'" ; eend 0
994     fi
995   fi # BOOTSTRAP_ONLY
996 else
997    log    'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
998    eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
999    bailout
1000 fi
1001
1002 # support installation of local files into the chroot/ISO
1003 if [ -n "$CHROOT_INSTALL" ] ; then
1004   if ! [ -d "$CHROOT_INSTALL" ] ; then
1005      log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1006      ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1007   else
1008      log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1009      einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1010      rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
1011      eend $?
1012      einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
1013      FORCE_ISO_REBUILD=true
1014   fi
1015 fi
1016
1017 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
1018    log   "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
1019    ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
1020 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
1021    log   "Skipping stage 'squashfs' as requested via option -q or -N"
1022    ewarn "Skipping stage 'squashfs' as requested via option -q or -N" ; eend 0
1023 else
1024    [ -d "$BUILD_OUTPUT"/live ] || mkdir "$BUILD_OUTPUT"/live
1025    # make sure we don't leave (even an empty) base.tgz:
1026    [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
1027
1028    # if unconfigured default to squashfs-tools' mksquashfs binary
1029    if [ -z "$SQUASHFS_BINARY" ] ; then
1030       SQUASHFS_BINARY='mksquashfs'
1031    fi
1032
1033    if which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
1034       log    "Using mksquashfs binary ${SQUASHFS_BINARY}"
1035       einfo  "Using mksquashfs binary ${SQUASHFS_BINARY}" ; eend 0
1036    else
1037       log    "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
1038       eerror "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
1039       bailout
1040    fi
1041
1042    # use sane defaults if $SQUASHFS_OPTIONS isn't set
1043    if [ -z "$SQUASHFS_OPTIONS" ] ; then
1044      # use blocksize 256k as this gives best result with regards to time + compression
1045      SQUASHFS_OPTIONS="-b 256k"
1046
1047      # set lzma/xz compression by default, unless -z option has been specified on command line
1048      if [ -z "$SQUASHFS_ZLIB" ] ; then
1049         SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp xz"
1050      else
1051         SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp gzip"
1052      fi
1053    fi
1054
1055    # support exclusion of files via exclude-file:
1056    if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
1057       SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE -wildcards"
1058    fi
1059
1060    # get rid of unnecessary files when building grml-small for final release:
1061    if echo "$CLASSES" | grep -q GRML_SMALL ; then
1062       SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
1063    fi
1064
1065    # log stuff
1066    SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
1067
1068    # informational stuff
1069    [ -n "$SQUASHFS_OPTIONS" ]  && SQUASHFS_INFO_MSG="$SQUASHFS_OPTIONS"
1070    [ -n "$SQUASHFS_INFO_MSG" ] && SQUASHFS_INFO_MSG="using options: $SQUASHFS_INFO_MSG"
1071    einfo "Squashfs build information: running binary $SQUASHFS_BINARY $SQUASHFS_INFO_MSG"
1072
1073    log "$SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS"
1074
1075    if $SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/"${GRML_NAME}".squashfs \
1076       -noappend $SQUASHFS_OPTIONS 2>"${SQUASHFS_STDERR}" ; then
1077       echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/filesystem.module
1078       log "Finished execution of stage 'squashfs' [$(date)]"
1079       einfo "Finished execution of stage 'squashfs'" ; eend 0
1080    else
1081       log    "Error: there was a critical error executing stage 'squashfs' [$(date)]:"
1082       log    "$(cat $SQUASHFS_STDERR)"
1083       eerror "Error: there was a critical error executing stage 'squashfs':"
1084       cat    "${SQUASHFS_STDERR}"
1085       eend 1
1086       bailout
1087    fi
1088
1089    FORCE_ISO_REBUILD=true
1090 fi
1091
1092 # create md5sum file:
1093 if [ -z "$BOOTSTRAP_ONLY" ] ; then
1094   ( cd $BUILD_OUTPUT/GRML &&
1095   find .. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
1096 fi
1097 # }}}
1098
1099 # ISO_OUTPUT - mkisofs {{{
1100 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
1101 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
1102
1103 if [ "$BOOT_METHOD" = "isolinux" ] ; then
1104    BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
1105 elif [ "$BOOT_METHOD" = "grub2" ] ; then
1106    BOOT_ARGS="-no-emul-boot -boot-load-size 4 -b boot/grub/toriboot.bin"
1107 fi
1108
1109 # Just until http://bts.grml.org/grml/issue945 has been resolved.
1110 # HYBRID_METHOD defaults to manifold, so make sure the default works OOTB.
1111 if [[ $BOOT_METHOD != isolinux && ($HYBRID_METHOD = isohybrid || $HYBRID_METHOD = manifold) ]]; then
1112   log   "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1113   ewarn "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1114   HYBRID_METHOD='grub2'
1115   eend 0
1116 fi
1117
1118 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ]  ; then
1119    log   "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already."
1120    ewarn "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already." ; eend 0
1121 elif [ -n "$SKIP_MKISOFS" ] ; then
1122    log   "Skipping stage 'iso build' as requested via option -n or -N"
1123    ewarn "Skipping stage 'iso build' as requested via option -n or -N" ; eend 0
1124 else
1125    mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
1126
1127    if $FORCE_ISO_REBUILD && ! [ -f "${ISO_OUTPUT}/${ISO_NAME}" ] ; then
1128       log   "Forcing rebuild of ISO because files on ISO have been modified."
1129       einfo "Forcing rebuild of ISO because files on ISO have been modified."
1130    fi
1131
1132    # support mkisofs as well as genisoimage
1133    if which mkisofs >/dev/null 2>&1; then
1134       MKISOFS='mkisofs'
1135    elif which genisoimage >/dev/null 2>&1; then
1136       MKISOFS='genisoimage'
1137    else
1138       log    "Error: neither mkisofs nor genisoimage available - can not create ISO."
1139       eerror "Error: neither mkisofs nor genisoimage available - can not create ISO." ; eend 1
1140       bailout
1141    fi
1142
1143    CURRENT_DIR=$(pwd)
1144    if cd "$BUILD_OUTPUT" ; then
1145       if [ "$BOOT_METHOD" = "grub2" ]; then
1146          # make a 2048-byte bootsector for El Torito
1147          dd if=/dev/zero of=boot/grub/toriboot.bin bs=512 count=4 2>/dev/null
1148          # those are in 2048-byte sectors, so 1 16 matches 4 63 below
1149          echo 1 16 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -B 11 | \
1150             dd of=boot/grub/toriboot.bin conv=notrunc 2>/dev/null
1151       fi
1152       log "$MKISOFS -V '${GRML_NAME} ${VERSION}' -publisher 'grml-live | grml.org' -l -r -J $BOOT_ARGS -o ${ISO_OUTPUT}/${ISO_NAME} ."
1153       "$MKISOFS" -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
1154               -l -r -J $BOOT_ARGS -no-pad \
1155               -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
1156       # both of these need core.img there, so it’s easier to write it here
1157       if [ "$BOOT_METHOD" = "grub2" ] || [ "$HYBRID_METHOD" = "grub2" ]; then
1158          # must be <= 30720 bytes
1159          dd if=boot/grub/core.img of="${ISO_OUTPUT}/${ISO_NAME}" \
1160            conv=notrunc bs=512 seek=4 2>/dev/null
1161       fi
1162
1163       # pad the output ISO to multiples of 256 KiB for partition table support
1164       siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
1165       cyls=$((siz / 512 / 32 / 16 + 1))   # C=$cyls H=16 S=32
1166       siz=$((cyls * 16 * 32 * 512))   # size after padding
1167       dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
1168          of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
1169
1170       # support disabling hybrid ISO image
1171       if [ "$HYBRID_METHOD" = "disable" ] ; then\
1172          log   "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1173          einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1174          eend 0
1175       # use isohybrid only on request
1176       elif [ "$HYBRID_METHOD" = "isohybrid" ] ; then
1177          if ! which isohybrid >/dev/null 2>&1 ; then
1178            bailout 12 "isohybrid binary not found - please install syslinux/syslinux-common"
1179          else
1180            log "Creating hybrid ISO file with isohybrid method"
1181            einfo "Creating hybrid ISO file with isohybrid method"
1182            # Notes for consideration:
1183            # "-entry 4 -type 1c"
1184            # * using 4 as the partition number is supposed to help with BIOSes
1185            #   that only support USB-Zip boot
1186            # * using 1c (i.e. hidden FAT32 LBA), instead of the default 0x17
1187            #   (hidden NTFS, IIRC), as the partition type is sometimes needed
1188            #   to get the BIOS even look at the partition created by isohybrid
1189            isohybrid "${ISO_OUTPUT}/${ISO_NAME}"
1190            eend $?
1191          fi
1192       # by default use our manifold boot method:
1193       else
1194          # isoinfo is part of both mkisofs and genisoimage so we're good
1195          bootoff=$(isoinfo -l -i "${ISO_OUTPUT}/${ISO_NAME}" | \
1196            sed -n '/^.*\[ *\([0-9]*\)[] ].* ISOLINUX.BIN;1 *$/s//\1/p')
1197          if ! [ -r boot/grub/core.img ] ; then
1198            ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
1199          elif [ "${bootoff:-0}" -lt 1 ] ; then
1200            ewarn "isolinux.bin not found on the ISO file, disabling manifold boot"
1201          else
1202            log "Creating hybrid ISO file with manifold method"
1203            einfo "Creating hybrid ISO file with manifold method"
1204            if [ "$HYBRID_METHOD" = "grub2" ] ; then
1205                # 512 bytes: MBR, partition table, load GRUB 2
1206                echo 4 63 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 4:0x96 -g $cyls:16:32
1207            else
1208               # read only one but 2048-byte sized (scale: << 2) sector
1209               echo $bootoff $bootoff | \
1210                  mksh /usr/share/grml-live/scripts/bootilnx.mksh -A -M 4:0x96 -g $cyls:16:32 -S 2
1211            fi | dd of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
1212            eend $?
1213          fi
1214       fi
1215
1216       # generate md5sum and sha1sum of ISO if we are using class 'RELEASE':
1217       case $CLASSES in *RELEASE*)
1218          [ "$RC" = 0 ] && \
1219          (
1220            if cd $ISO_OUTPUT ; then
1221              md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
1222              touch -r ${ISO_NAME} ${ISO_NAME}.md5
1223              sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
1224              touch -r ${ISO_NAME} ${ISO_NAME}.sha1
1225            fi
1226          )
1227          ;;
1228       esac
1229
1230       cd "$CURRENT_DIR"
1231    fi
1232
1233    if [ "$RC" = 0 ] ; then
1234       log   "Finished execution of stage 'iso build' [$(date)]"
1235       einfo "Finished execution of stage 'iso build'" ; eend 0
1236    else
1237       log    "Error: there was a critical error ($RC) executing stage 'iso build' [$(date)]"
1238       eerror "Error: there was a critical error executing stage 'iso build'" ; eend 1
1239       bailout $RC
1240    fi
1241 fi
1242 # }}}
1243
1244 # pack artifacts {{{
1245 if [ -n "$PACK_ARTIFACTS" ]; then
1246   log "Packing artifcats"
1247   einfo "Packing artifacts"
1248   [ -f "${CHROOT_ARCHIVE}" ] && rm -r "${CHROOT_ARCHIVE}"
1249   tar -c -a -f ${CHROOT_ARCHIVE} --preserve-permissions -C "$(dirname ${CHROOT_OUTPUT})" "$(basename ${CHROOT_OUTPUT})"
1250   eend 0
1251 fi
1252 # }}}
1253
1254 # log build information to database if grml-live-db is installed and enabled {{{
1255 dpkg_to_db() {
1256 if [ -d /usr/share/grml-live-db ] ; then
1257
1258   # safe defaults
1259   DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot:
1260   [ -n "$DPKG_DATABASE" ]  || DPKG_DATABASE=/var/log/grml-live.db
1261   [ -n "$DPKG_DBSCRIPT" ]  || DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
1262   [ -n "$DPKG_DBOPTIONS" ] || DPKG_DBOPTIONS="--database $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME --dpkg $DPKG_LIST"
1263
1264   if ! [ -x "$DPKG_DBSCRIPT" ] ; then
1265     log "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information."
1266     eerror "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information." ; eend 1
1267     bailout 14
1268   fi
1269
1270   # disable by default for now, not sure whether really everyone is using a local db file
1271   #if ! touch "$DPKG_DATABASE" ; then
1272   #  eerror "Error: can not write to ${DPKG_DATABASE}, can not log dpkg information." ; eend 1
1273   #  bailout 14
1274   #fi
1275
1276   if ! [ -r "$DPKG_LIST" ] ; then
1277      log   "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)"
1278      ewarn "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)" ; eend 0
1279   else
1280      einfo "Logging $DPKG_LIST to database $DPKG_DATABASE"
1281      log "Logging $DPKG_LIST to database $DPKG_DATABASE"
1282      log "Executing $DPKG_DBSCRIPT $DPKG_DBOPTIONS"
1283      eindent
1284
1285      if DB_INFO=$("$DPKG_DBSCRIPT" $DPKG_DBOPTIONS 2>&1) ; then
1286        einfo "$DB_INFO"
1287        eend 0
1288      else
1289        eerror "$DB_INFO"
1290        eend 1
1291      fi
1292
1293      eoutdent
1294   fi
1295
1296 fi
1297 }
1298 # }}}
1299
1300 # finalize {{{
1301 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
1302 log "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]"
1303
1304 dpkg_to_db # make sure we catch the last log line as well, therefore execute between log + einfo
1305
1306 einfo "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]" ; eend 0
1307 bailout 0
1308 # }}}
1309
1310 ## END OF FILE #################################################################
1311 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=2