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