Support BOOT_FILE variable for usage within secureboot templates
[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 # avoid leaking into chroots
16 unset TMPDIR
17
18 # define function getfilesize before "set -e"
19 if stat --help >/dev/null 2>&1; then
20   getfilesize='stat -c %s'  # GNU stat
21 else
22   getfilesize='stat -f %z'  # BSD stat
23 fi
24
25 # exit on any error:
26 # disable for now since it seems to cause some problems
27 # set -e
28
29 # The line following this line is patched by debian/rules.
30 GRML_LIVE_VERSION='***UNRELEASED***'
31
32 # global variables
33 PN="$(basename $0)"
34 CMDLINE="$0 $@"
35 ADDONS_LIST_FILE='/boot/isolinux/addons_list.cfg'
36 # }}}
37
38 # usage information {{{
39 usage()
40 {
41   echo "
42 $PN - build process script for generating a (grml based) Linux Live-ISO
43
44 Usage: $PN [options, see as follows]
45
46    -a <architecture>       architecture; available values: i386 and amd64
47    -A                      clean build directories before and after running
48    -b                      build the ISO without updating the chroot via FAI
49    -B                      build the ISO without touching the chroot (skips cleanup)
50    -c <classe[s]>          classes to be used for building the ISO via FAI
51    -C <configfile>         configuration file for grml-live
52    -d <date>               use specified date instead of build time as date of release
53    -D <configdir>          use specified configuration directory instead of /etc/grml/fai
54    -e <iso_name>           extract ISO and squashfs contents from iso_name
55    -F                      force execution without prompting
56    -g <grml_name>          set the grml flavour name
57    -h                      display short usage information and exit
58    -i <iso_name>           name of ISO
59    -I <src_directory>      directory which provides files that should become
60                            part of the chroot/ISO
61    -n                      skip generation of ISO
62    -N                      bootstrap (build chroot) only, do not create files for ISO
63    -o <output_directory>   main output directory of the build process
64    -q                      skip mksquashfs
65    -Q                      skip netboot package build
66    -r <release_name>       release name
67    -s <suite>              Debian suite/release, like: stable, testing, unstable
68    -S <script_directory>   place of scripts (defaults to /usr/share/grml-live/scripts)
69    -t <template_directory> place of the templates
70    -u                      update existing chroot instead of rebuilding it from scratch
71    -U <username>           arrange output to be owned by specified username
72    -v <version_number>     specify version number of the release
73    -V                      increase verbosity in the build process
74    -w <date>               wayback machine, build system using Debian archives
75                            from specified date
76    -z                      use ZLIB instead of LZMA/XZ compression
77
78 Usage examples:
79
80     $PN
81     $PN -c GRMLBASE,GRML_FULL,AMD64 -o /dev/shm/grml
82     $PN -c GRMLBASE,GRML_FULL,AMD64 -i grml_0.0-1.iso -v 0.0-1
83     $PN -c GRMLBASE,GRML_FULL,AMD64 -s stable -V -r 'grml-ftw'
84
85 More details: man grml-live + /usr/share/doc/grml-live/grml-live.html
86               http://grml.org/grml-live/
87
88 Please send your bug reports and feedback to the grml-team: http://grml.org/bugs/
89 "
90    [ "$(id -u 2>/dev/null)" != 0 ] && echo "Please notice that this script requires root permissions."
91 }
92
93 # make sure it's possible to get usage information without being
94 # root or actually executing the script
95 if [ "$1" = '-h' -o "$1" = '--help' ] ; then
96    usage
97    exit 0
98 fi
99 # }}}
100
101 # some runtime checks {{{
102 # we need root permissions for the build-process:
103 if [ "$(id -u 2>/dev/null)" != 0 ] ; then
104    echo "Error: please run this script with uid 0 (root)." >&2
105    exit 1
106 fi
107
108 if [ -r /var/run/fai/FAI_INSTALLATION_IN_PROGRESS ] ; then
109    echo "/usr/sbin/fai already running or was aborted before.">&2
110    echo "You may remove /var/run/fai/FAI_INSTALLATION_IN_PROGRESS and try again.">&2
111    exit 1
112 fi
113
114 # see #449236
115 if [ -r /var/run/fai/fai_softupdate_is_running ] ; then
116    echo "/usr/sbin/fai softupdate already running or was aborted before.">&2
117    echo "You may remove /var/run/fai/fai_softupdate_is_running and try again.">&2
118    exit 1
119 fi
120 # }}}
121
122 # lsb-functions and configuration stuff {{{
123 # make sure they are not set by default
124 VERBOSE=''
125 FORCE=''
126 UPDATE=''
127 BUILD_ONLY=''
128 BUILD_DIRTY=''
129 BOOTSTRAP_ONLY=''
130 HOSTNAME=''
131 USERNAME=''
132 CONFIGDUMP=''
133
134 # don't use colors/escape sequences
135 if [ -r /lib/lsb/init-functions ] ; then
136   . /lib/lsb/init-functions
137   ! log_use_fancy_output && NOCOLORS=true
138 fi
139
140 if [ -r /etc/grml/lsb-functions ] ; then
141    . /etc/grml/lsb-functions
142 else
143    einfo()  { echo "  [*] $*" ;}
144    eerror() { echo "  [!] $*">&2 ;}
145    ewarn()  { echo "  [x] $*" ;}
146    eend()   { return 0 ;}
147    eindent()  { return 0 ;}
148    eoutdent() { return 0 ;}
149 fi
150
151 # source main configuration file:
152 [ -z "$LIVE_CONF" ] && LIVE_CONF='/etc/grml/grml-live.conf'
153 if ! [ -r "$LIVE_CONF" ] ; then
154   ewarn "Configuration file $LIVE_CONF can not be read, ignoring"
155 else
156   einfo "Sourcing configuration file $LIVE_CONF"
157   . $LIVE_CONF
158   eend $?
159 fi
160 # }}}
161
162 # umount all directories {{{
163 umount_all() {
164    # make sure we don't leave any mounts - FAI doesn't remove them always
165    umount $CHROOT_OUTPUT/proc/sys/fs/binfmt_misc 2>/dev/null || /bin/true
166    umount $CHROOT_OUTPUT/proc 2>/dev/null || /bin/true
167    umount $CHROOT_OUTPUT/run  2>/dev/null || /bin/true
168    umount $CHROOT_OUTPUT/sys  2>/dev/null || /bin/true
169    umount $CHROOT_OUTPUT/dev/pts 2>/dev/null || /bin/true
170    umount $CHROOT_OUTPUT/dev 2>/dev/null || /bin/true
171
172    if [ -n "$EXTRACT_ISO_NAME" ] ; then
173      umount "$EXTRACT_ISO_NAME" 2>/dev/null || /bin/true
174    fi
175
176    # certain FAI versions sadly leave a ramdisk behind, so better safe than sorry
177    if [ -x /usr/lib/fai/mkramdisk ] ; then
178      /usr/lib/fai/mkramdisk -u "$(readlink -f ${CHROOT_OUTPUT}/var/lib/dpkg)" >/dev/null 2>&1 || /bin/true
179    fi
180
181    umount "${CHROOT_OUTPUT}/grml-live/sources/" 2>/dev/null || /bin/true
182    [ -n "$MIRROR_DIRECTORY" ] && umount "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
183 }
184 # }}}
185
186 # clean exit {{{
187 bailout() {
188   rm -f /var/run/fai/fai_softupdate_is_running \
189         /var/run/fai/FAI_INSTALLATION_IN_PROGRESS
190   [ -n "$CONFIGDUMP"      ]  && rm -f  "$CONFIGDUMP"
191   [ -n "$SQUASHFS_STDERR" ]  && rm -rf "$SQUASHFS_STDERR"
192   umount_all
193   [ -n "$1" ] && EXIT="$1" || EXIT="1"
194   [ -n "$2" ] && eerror "$2">&2
195   if [ -n "$CLEAN_ARTIFACTS" ]; then
196     log "Cleaning up"
197     einfo "Cleaning up"
198     [ -n "${BUILD_OUTPUT}"  -a -d "${BUILD_OUTPUT}"  ] && rm -r "${BUILD_OUTPUT}"
199     [ -n "${CHROOT_OUTPUT}" -a -d "${CHROOT_OUTPUT}" ] && rm -r "${CHROOT_OUTPUT}"
200     eend 0
201   fi
202
203   # get rid of automatically generated conffiles
204   rm -f ${GRML_FAI_CONFIG}/nfsroot.conf
205   rm -f ${GRML_FAI_CONFIG}/make-fai-nfsroot.conf
206
207   if [ -n "$CHOWN_USER" ]; then
208     log "Setting ownership"
209     einfo "Setting ownership"
210     [ -n "${OUTPUT}"         -a -d "${OUTPUT}"         ] && chown -R "${CHOWN_USER}:" "${OUTPUT}"
211     [ -n "${BUILD_OUTPUT}"   -a -d "${BUILD_OUTPUT}"   ] && chown -R "${CHOWN_USER}:" "${BUILD_OUTPUT}"
212     [ -n "${CHROOT_OUTPUT}"  -a -d "${CHROOT_OUTPUT}"  ] && chown -R "${CHOWN_USER}:" "${CHROOT_OUTPUT}"
213     [ -n "${ISO_OUTPUT}"     -a -d "${ISO_OUTPUT}"     ] && chown -R "${CHOWN_USER}:" "${ISO_OUTPUT}"
214     [ -n "${LOG_OUTPUT}"     -a -d "${LOG_OUTPUT}"     ] && chown -R "${CHOWN_USER}:" "${LOG_OUTPUT}"
215     [ -n "${NETBOOT}"        -a -d "${NETBOOT}"        ] && chown -R "${CHOWN_USER}:" "${NETBOOT}"
216     eend 0
217   fi
218   log "------------------------------------------------------------------------------"
219   exit "$EXIT"
220 }
221 trap bailout 1 2 3 3 6 9 14 15
222 trap umount_all EXIT
223 # }}}
224
225 # some important functions {{{
226
227 # log output:
228 # usage: log "string to log"
229 log() { [ -n "$LOGFILE" ] && echo "$*" >> $LOGFILE ; }
230
231 # cut string at character number int = $1
232 # usage: cut_string 5 "1234567890" will output "12345"
233 cut_string() {
234   [ -n "$2" ] || return 1
235   echo "$2" | head -c "$1"; echo -ne "\n"
236 }
237
238 # prepend int = $1 spaces before string = $2
239 # usage: extend_string_begin 5 "123" will output "  123"
240 extend_string_begin() {
241   [ -n "$2" ] || return 1
242   local COUNT="$(echo $2 | wc -c)"
243   local FILL="$(expr $COUNT - $1)"
244   while [ "$FILL" -gt 1 ] ; do
245     echo -n " "
246     local FILL=$(expr $FILL - 1)
247   done
248   while [ "$FILL" -lt 1 ] ; do
249     echo -n " "
250     local FILL=$(expr $FILL + 1)
251   done
252   echo "$2" | head -c "$1"; echo -ne "\n"
253 }
254
255 # append int = $1 spaces to string = $2
256 # usage: extend_string_begin 5 "123" will output "123  "
257 extend_string_end() {
258   [ -n "$2" ] || return 1
259   echo -n "$2" | head -c "$1"
260   local COUNT="$(echo $2 | wc -c)"
261   local FILL="$(expr $COUNT - $1)"
262   while [ "$FILL" -gt 1 ] ; do
263     echo -n " "
264     local FILL=$(expr $FILL - 1)
265   done
266   while [ "$FILL" -lt 1 ] ; do
267     echo -n " "
268     local FILL=$(expr $FILL + 1)
269   done
270   echo -ne "\n"
271 }
272
273 # Copy addonfile $1 from either
274 #   * the chroot (via $2, the system path),
275 #   * or from TEMPLATE_DIRECTORY/compat (if exists),
276 #   * or from the host system (again, using $2),
277 # or warn about the missing file.
278 #
279 # This is because:
280 #   * We assume that the chroot always has a "good" version of
281 #     the file. Also it makes sources handling easier.
282 #   * On unstable, we recommend the Debian packages containing
283 #     these files. The user can override them by putting his
284 #     "better" version into the chroot.
285 #   * With older releases the Debian packages are probably
286 #     not available, so we look in TEMPLATE_DIRECTORY/compat,
287 #     where a (custom) package might install current file versions.
288 copy_addon_file() {
289   DEST="${BUILD_OUTPUT}/boot/$3"
290   if [ ! -d "${DEST}/" ]; then
291     mkdir -p "${DEST}"
292   fi
293   if [ -e "$CHROOT_OUTPUT/$2/$1" ]; then
294     log   "Copying $1 from chroot"
295     cp "$CHROOT_OUTPUT/$2/$1" "${DEST}/"
296     return $?
297   fi
298   if [ -e "${TEMPLATE_DIRECTORY}/compat/$3/$1" ]; then
299     log   "Copying $1 from ${TEMPLATE_DIRECTORY}/compat"
300     cp "${TEMPLATE_DIRECTORY}/compat/$3/$1" "${DEST}/"
301     return $?
302   fi
303   if [ -e "$2/$1" ]; then
304     log   "Copying $1 from system"
305     cp "$2/$1" "${DEST}/"
306     return $?
307   fi
308
309   msg="Missing addon file: \"$1\""
310   ewarn "$msg" ; eend 1
311   log "copy_addon_file: $msg"
312 }
313
314 # replace placeholders in template files with actual information
315 adjust_boot_files() {
316   if [ -z "$1" ] ; then
317     echo "Usage: adjust_boot_files <template_file>" >&2
318     exit 1
319   fi
320
321   for file in "$@" ; do
322     if [ -r "${file}" ] && [ -f "${file}" ] ; then
323       sed -i "s/%ARCH%/$ARCH/g"                    "${file}"
324       sed -i "s/%DATE%/$DATE/g"                    "${file}"
325       sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/g"      "${file}"
326       sed -i "s/%DISTRI_NAME%/$DISTRI_NAME/g"      "${file}"
327       sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/g"  "${file}"
328       sed -i "s/%GRML_NAME%/$GRML_NAME/g"          "${file}"
329       sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/g"  "${file}"
330       sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/g"    "${file}"
331       sed -i "s/%SHORT_NAME%/$SHORT_NAME/g"        "${file}"
332       sed -i "s/%VERSION%/$VERSION/g"              "${file}"
333       if [ -n "${BOOT_FILE}" ] ; then
334         sed -i "s;%BOOT_FILE%;$BOOT_FILE;g"        "${file}"
335       fi
336
337       [ -n "$DEFAULT_BOOTOPTIONS" ] && sed -i "s; boot=live; boot=live $DEFAULT_BOOTOPTIONS;"  "${file}"
338
339       if [ -n "$NO_BOOTID" ] ; then
340         sed -i "s/ bootid=%BOOTID%//g" "${file}" # drop bootid bootoption
341       else
342         sed -i "s/%BOOTID%/$BOOTID/g" "${file}" # adjust bootid=... argument
343       fi
344     fi
345   done
346 }
347 # }}}
348
349 # command line parsing {{{
350 while getopts "a:C:c:d:D:e:g:i:I:o:r:s:S:t:U:v:w:AbBFhnNqQuVz" opt; do
351   case "$opt" in
352     a) ARCH="$OPTARG" ;;
353     A) CLEAN_ARTIFACTS=1 ;;
354     b) BUILD_ONLY=1 ;;
355     B) BUILD_DIRTY=1 ;;
356     c) CLASSES="$OPTARG" ;;
357     C) LOCAL_CONFIG="$(readlink -f $OPTARG)" ;;
358     d) DATE="$OPTARG" ;;
359     D) GRML_FAI_CONFIG="$(readlink -f $OPTARG)" ;;
360     e) EXTRACT_ISO_NAME="$(readlink -f $OPTARG)" ;;
361     g) GRML_NAME="$OPTARG" ;;
362     h) usage ; bailout 0 ;;
363     i) ISO_NAME="$OPTARG" ;;
364     I) CHROOT_INSTALL="$OPTARG" ;;
365     n) SKIP_MKISOFS=1 ;;
366     N) BOOTSTRAP_ONLY=1; SKIP_MKISOFS=1; SKIP_MKSQUASHFS=1 ;;
367     o) OUTPUT="$(readlink -f $OPTARG)" ;;
368     q) SKIP_MKSQUASHFS=1 ;;
369     Q) SKIP_NETBOOT=1 ;;
370     r) RELEASENAME="$OPTARG" ;;
371     s) SUITE="$OPTARG" ;;
372     S) SCRIPTS_DIRECTORY="$OPTARG";;
373     t) TEMPLATE_DIRECTORY="$OPTARG";;
374     v) VERSION="$OPTARG" ;;
375     F) FORCE=1 ;;
376     u) UPDATE=1 ;;
377     U) CHOWN_USER="$OPTARG" ;;
378     V) VERBOSE="-v" ;;
379     w) export WAYBACK_DATE="$OPTARG" ;;
380     z) SQUASHFS_ZLIB=1 ;;
381     ?) echo "invalid option -$OPTARG" >&2; usage; bailout 1 ;;
382   esac
383 done
384 shift $(($OPTIND - 1))  # set ARGV to the first not parsed commandline parameter
385
386 if [ -n "$1" ] ; then
387   echo "Error: unknown argument '$1' in options. Exiting to avoid possible data loss." >&2
388   bailout 1
389 fi
390 # }}}
391
392 # read local (non-packaged) configuration {{{
393 if [ -z "$LOCAL_CONFIG" ]; then
394   if [ -r "/etc/grml/grml-live.local" ]; then
395     LOCAL_CONFIG="/etc/grml/grml-live.local"
396   fi
397 fi
398 if [ -n "$LOCAL_CONFIG" ]; then
399   if [ -r "$LOCAL_CONFIG" ]; then
400     . $LOCAL_CONFIG
401   else
402     eerror "Could not read specified local configuration file \"$LOCAL_CONFIG\"."
403     bailout 1
404   fi
405   LOCAL_CONFIG=$(readlink -f "$LOCAL_CONFIG")
406 else
407   LOCAL_CONFIG=''
408 fi
409
410 if [ -n "${GRML_LIVE_SOURCES:-}" ] ; then
411   eerror "Config variable \$GRML_LIVE_SOURCES is set. This variable has been deprecated."
412   ewarn  "Please set up \${GRML_FAI_CONFIG}/config/files/etc/apt/sources.list.d/* instead."
413   bailout 1
414 fi
415 # }}}
416
417 # assume sane defaults (if not set already) {{{
418 [ -n "$ARCH" ]                    || ARCH="$(dpkg --print-architecture)"
419 [ -n "$BOOT_METHOD" ]             || BOOT_METHOD='isolinux'
420 [ -n "$CLASSES" ]                 || CLASSES="GRMLBASE,GRML_FULL,$(echo ${ARCH} | tr 'a-z' 'A-Z')"
421 [ -n "$DATE" ]                    || DATE="$(date +%Y-%m-%d)"
422 [ -n "$DISTRI_INFO" ]             || DISTRI_INFO='Grml - Live Linux for system administrators'
423 [ -n "$DISTRI_NAME" ]             || DISTRI_NAME="grml"
424 [ -n "$DISTRI_SPLASH" ]           || DISTRI_SPLASH='grml.png'
425 [ -n "$FORCE_ISO_REBUILD" ]       || FORCE_ISO_REBUILD="false"
426 [ -n "$GRML_FAI_CONFIG" ]         || GRML_FAI_CONFIG='/etc/grml/fai'
427 [ -n "$GRML_NAME" ]               || GRML_NAME='grml'
428 [ -n "$HOSTNAME" ]                || HOSTNAME='grml'
429 [ -n "$HYBRID_METHOD" ]           || HYBRID_METHOD='isohybrid'
430 [ -n "$RELEASENAME" ]             || RELEASENAME='grml-live rocks'
431 [ -n "$SECURE_BOOT" ]             || SECURE_BOOT='ubuntu'
432 [ -n "$SQUASHFS_EXCLUDES_FILE" ]  || SQUASHFS_EXCLUDES_FILE="${GRML_FAI_CONFIG}/config/grml/squashfs-excludes"
433 [ -n "$SUITE" ]                   || SUITE='testing'
434 [ -n "$TEMPLATE_DIRECTORY" ]      || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
435 [ -n "$SCRIPTS_DIRECTORY" ]       || SCRIPTS_DIRECTORY='/usr/share/grml-live/scripts'
436 [ -n "$USERNAME" ]                || USERNAME='grml'
437 [ -n "$VERSION" ]                 || VERSION='0.0.1'
438
439 # output specific stuff, depends on $OUTPUT (iff not set):
440 [ -n "$OUTPUT" ]           || OUTPUT="$PWD/grml/"
441 [ -n "$BUILD_OUTPUT" ]     || BUILD_OUTPUT="$OUTPUT/grml_cd"
442 [ -n "$CHROOT_OUTPUT" ]    || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
443 [ -n "$ISO_OUTPUT" ]       || ISO_OUTPUT="$OUTPUT/grml_isos"
444 [ -n "$LOG_OUTPUT" ]       || LOG_OUTPUT="$OUTPUT/grml_logs"
445 [ -n "$REPORTS" ]          || REPORTS="${LOG_OUTPUT}/reports/"
446 [ -n "$NETBOOT" ]          || NETBOOT="${OUTPUT}/netboot/"
447 # }}}
448
449 # some misc checks before executing FAI {{{
450 [ -n "$CLASSES" ] || bailout 1 "Error: \$CLASSES unset, please set it in $LIVE_CONF or
451 specify it on the command line using the -c option."
452 [ -n "$OUTPUT" ] || bailout 1 "Error: \$OUTPUT unset, please set it in $LIVE_CONF or
453 specify it on the command line using the -o option."
454
455 # trim characters that are known to cause problems inside $GRML_NAME;
456 # for example isolinux does not like '-' inside the directory name
457 [ -n "$GRML_NAME" ] && export SHORT_NAME="$(echo $GRML_NAME | tr -d ',./;\- ')"
458
459 # export variables to have them available in fai scripts:
460 [ -n "$GRML_NAME" ]   && export GRML_NAME="$GRML_NAME"
461 [ -n "$RELEASENAME" ] && export RELEASENAME="$RELEASENAME"
462 # }}}
463
464 # ZERO_LOGFILE - check for backwards compatibility reasons {{{
465 # this was default behaviour until grml-live 0.9.34:
466 if [ -n "$ZERO_LOGFILE" ] ; then
467    PRESERVE_LOGFILE='' # make sure it's cleaned then
468    ewarn "Please consider disabling the \$ZERO_LOGFILE option as grml-live clears..."
469    ewarn "... the logfile $LOGFILE by default (unless \$PRESERVE_LOGFILE is set) nowadays."
470    eend 0
471 fi
472 # }}}
473
474 # ask user whether the setup is ok {{{
475 if [ -z "$FORCE" ] ; then
476    echo
477    echo "${PN} [${GRML_LIVE_VERSION}]: check your configuration (or use -F to force execution):"
478    echo
479    echo "  FAI classes:       $CLASSES"
480    [ -n "$LOCAL_CONFIG" ]        && echo "  Configuration:     $LOCAL_CONFIG"
481    [ -n "$GRML_FAI_CONFIG" ]     && echo "  Config directory:  $GRML_FAI_CONFIG"
482    echo "  main directory:    $OUTPUT"
483    [ -n "$EXTRACT_ISO_NAME" ]    && echo "  Extract ISO:       $EXTRACT_ISO_NAME"
484    [ -n "$CHROOT_OUTPUT" ]       && echo "  Chroot target:     $CHROOT_OUTPUT"
485    [ -n "$BUILD_OUTPUT" ]        && echo "  Build target:      $BUILD_OUTPUT"
486    [ -n "$ISO_OUTPUT" ]          && echo "  ISO target:        $ISO_OUTPUT"
487    [ -n "$GRML_NAME" ]           && echo "  Grml name:         $GRML_NAME"
488    [ -n "$RELEASENAME" ]         && echo "  Release name:      $RELEASENAME"
489    [ -n "$DATE" ]                && echo "  Build date:        $DATE"
490    [ -n "$VERSION" ]             && echo "  Grml version:      $VERSION"
491    [ -n "$SUITE" ]               && echo "  Debian suite:      $SUITE"
492    [ -n "$ARCH" ]                && echo "  Architecture:      $ARCH"
493    [ -n "$BOOT_METHOD" ]         && echo "  Boot method:       $BOOT_METHOD"
494    [ -n "$HYBRID_METHOD" ]       && echo "  Hybrid method:     $HYBRID_METHOD"
495    [ -n "$TEMPLATE_DIRECTORY" ]  && echo "  Template files:    $TEMPLATE_DIRECTORY"
496    [ -n "$CHROOT_INSTALL" ]      && echo "  Install files from directory to chroot:  $CHROOT_INSTALL"
497    [ -n "$BOOTID" ]              && echo "  Boot identifier:   $BOOTID"
498    [ -n "$NO_BOOTID" ]           && echo "  Skipping bootid feature."
499    [ -n "$CHOWN_USER" ]          && echo "  Output owner:      $CHOWN_USER"
500    [ -n "$DEFAULT_BOOTOPTIONS" ] && echo "  Adding default bootoptions: \"$DEFAULT_BOOTOPTIONS\""
501    [ -n "$FAI_ARGS" ]            && echo "  Additional arguments for FAI: $FAI_ARGS"
502    [ -n "$LOGFILE" ]             && echo "  Logging to file:   $LOGFILE"
503    [ -n "$SQUASHFS_ZLIB" ]       && echo "  Using ZLIB (instead of LZMA/XZ) compression."
504    [ -n "$SQUASHFS_OPTIONS" ]    && echo "  Using SQUASHFS_OPTIONS ${SQUASHFS_OPTIONS}"
505    [ -n "$VERBOSE" ]             && echo "  Using VERBOSE mode."
506    [ -n "$CLEAN_ARTIFACTS" ]     && echo "  Will clean output before and after running."
507    [ -n "$UPDATE" ]              && echo "  Executing UPDATE instead of fresh installation."
508    if [ -n "$BOOTSTRAP_ONLY" ] ; then
509      echo "  Bootstrapping only and not building (files for) ISO."
510    else
511      [ -n "$SKIP_MKSQUASHFS" ]     && echo "  Skipping creation of SQUASHFS file."
512      [ -n "$SKIP_NETBOOT" ]        && echo "  Skipping creation of NETBOOT package."
513      [ -n "$SKIP_MKISOFS" ]        && echo "  Skipping creation of ISO file."
514      [ -n "$BUILD_ONLY" ]          && echo "  Executing BUILD_ONLY instead of fresh installation or UPDATE."
515      [ -n "$BUILD_DIRTY" ]         && echo "  Executing BUILD_DIRTY to leave chroot untouched."
516    fi
517    echo
518    echo -n "Is this ok for you? [y/N] "
519    read a
520    if ! [ "$a" = 'y' -o "$a" = 'Y' ] ; then
521       CLEAN_ARTIFACTS=0
522       echo "Exiting as requested."
523       exit 0
524    fi
525    echo
526 fi
527 # }}}
528
529 # clean up before start {{{
530 if [ -n "${CLEAN_ARTIFACTS}" ]; then
531   echo "Wiping old artifacts"
532   [ -n "${CHROOT_OUTPUT}"  -a -d "${CHROOT_OUTPUT}"  ] && rm -r "${CHROOT_OUTPUT}"
533   [ -n "${BUILD_OUTPUT}"   -a -d "${BUILD_OUTPUT}"   ] && rm -r "${BUILD_OUTPUT}"
534   [ -n "${ISO_OUTPUT}"     -a -d "${ISO_OUTPUT}"     ] && rm -r "${ISO_OUTPUT}"
535   [ -n "${LOG_OUTPUT}"     -a -d "${LOG_OUTPUT}"     ] && rm -r "${LOG_OUTPUT}"
536   [ -n "${NETBOOT}"        -a -d "${NETBOOT}"        ] && rm -r "${NETBOOT}"
537 fi
538 # }}}
539
540 # create log file {{{
541 [ -n "$LOGFILE" ] || LOGFILE=${LOG_OUTPUT}/grml-live.log
542 mkdir -p $(dirname "${LOGFILE}")
543 touch $LOGFILE
544 chown root:adm $LOGFILE
545 chmod 664 $LOGFILE
546 # }}}
547
548 # clean/zero/remove logfiles {{{
549
550 if [ -n "$PRESERVE_LOGFILE" ] ; then
551    echo "Preserving logfile $LOGFILE as requested via \$PRESERVE_LOGFILE"
552 else
553    # make sure it is empty (as it is e.g. appended to grml-live-db)
554    echo -n > $LOGFILE
555 fi
556
557 if [ -n "$ZERO_FAI_LOGFILE" ] ; then
558    if [ -d /var/log/fai/"$HOSTNAME" ] ; then
559       rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last)"
560       rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-dirinstall)"
561       rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-softupdate)"
562       rm -f /var/log/fai/"$HOSTNAME"/last \
563             /var/log/fai/"$HOSTNAME"/last-dirinstall \
564             /var/log/fai/"$HOSTNAME"/last-softupdate
565    fi
566 fi
567 # }}}
568
569 # source config and startup {{{
570 if [ -n "$CONFIG" ] ; then
571    if ! [ -f "$CONFIG" ] ; then
572       log    "Error: $CONFIG could not be read. Exiting. [$(date)]"
573       eerror "Error: $CONFIG could not be read. Exiting." ; eend 1
574       bailout 1
575    else
576       log "Sourcing $CONFIG"
577       . $CONFIG
578    fi
579 fi
580
581 start_seconds=$(cut -d . -f 1 /proc/uptime)
582 log "------------------------------------------------------------------------------"
583 log "Starting grml-live [${GRML_LIVE_VERSION}] run on $(date)"
584 log "Using local config file: $LOCAL_CONFIG"
585 log "Executed grml-live command line:"
586 log "$CMDLINE"
587
588 einfo "Logging actions to logfile $LOGFILE"
589 # }}}
590
591 # dump config variables into file, for script access {{{
592 CONFIGDUMP=$(mktemp)
593 set | egrep \
594   '^(GRML_NAME|RELEASENAME|DATE|VERSION|SUITE|ARCH|DISTRI_NAME|USERNAME|HOSTNAME|APT_PROXY)=' \
595   > ${CONFIGDUMP}
596 # }}}
597
598 # unpack iso/squashfs {{{
599 extract_iso() {
600 if [ -n "$EXTRACT_ISO_NAME" ]; then
601   log "Unpacking ISO from ${EXTRACT_ISO_NAME}"
602   einfo "Unpacking ISO from ${EXTRACT_ISO_NAME}"
603   local mountpoint=$(mktemp -d)
604   local rc=0
605   mount -o loop "${EXTRACT_ISO_NAME}" "$mountpoint" ; rc=$?
606   if [ "$rc" != 0 ]; then
607     rmdir "$mountpoint"
608     log "mount failed"
609     eerror "mount failed"
610     eend 1
611     bailout 1
612   fi
613
614   if ls "${mountpoint}"/live/*/*.squashfs 2>/dev/null | grep -q . ; then # ISOs >=2011.12
615     log "Using ${mountpoint}/live/*/*.squashfs for unsquashfs"
616     unsquashfs -d "${CHROOT_OUTPUT}" "${mountpoint}"/live/*/*.squashfs ; rc=$?
617   elif ls "${mountpoint}"/live/*.squashfs 2>/dev/null | grep -q . ; then # ISOs before 2011.12
618     log "Using ${mountpoint}/live/*.squashfs for unsquashfs"
619     unsquashfs -d "${CHROOT_OUTPUT}" "${mountpoint}"/live/*.squashfs ; rc=$?
620   else
621     log "Error: Could not find any *.squashfs files on the ISO"
622     eerror "Error: Could not find any *.squashfs files on the ISO"
623     eend 1
624     bailout 1
625   fi
626
627   umount "$mountpoint"
628   rmdir "$mountpoint"
629   if [ "$rc" != 0 ]; then
630     log "unsquashfs failed"
631     eerror "unsquashfs failed"
632     eend 1
633     bailout 1
634   fi
635 fi
636 }
637 extract_iso
638 # }}}
639
640 # on-the-fly configuration {{{
641
642 # does this suck? YES!
643 # /usr/share/debootstrap/scripts/unstable does not exist, instead use 'sid':
644 case $SUITE in
645    unstable) SUITE='sid' ; CLASSES="DEBIAN_UNSTABLE,$CLASSES" ;;
646    *) CLASSES="DEBIAN_$(echo $SUITE | tr 'a-z' 'A-Z'),$CLASSES";;
647 esac
648 export SUITE # make sure it's available in FAI scripts
649
650 # validate whether the specified architecture class matches the
651 # architecture (option), otherwise installation of kernel will fail
652 if echo $CLASSES | grep -qw I386 ; then
653    if ! [[ "$ARCH" == "i386" ]] ; then
654       log    "Error: You specified the I386 class but are trying to build something else (AMD64?)."
655       eerror "Error: You specified the I386 class but are trying to build something else (AMD64?)."
656       eerror "Tip:   Either invoke grml-live with '-a i386' or adjust the architecture class. Exiting."
657       eend 1
658       bailout
659    fi
660 elif echo $CLASSES | grep -qi amd64 ; then
661    if ! [[ "$ARCH" == "amd64" ]] ; then
662       log    "Error: You specified the AMD64 class but are trying to build something else (I386?)."
663       eerror "Error: You specified the AMD64 class but are trying to build something else (I386?)."
664       eerror "Tip:   Either invoke grml-live with '-a amd64' or adjust the architecture class. Exiting."
665       eend 1
666       bailout
667    fi
668 fi
669
670 # generate nfsroot configuration for FAI on the fly
671 if [ -z "$FAI_DEBOOTSTRAP" ] ; then
672   if [ -n "$WAYBACK_DATE" ] ; then
673     FAI_DEBOOTSTRAP="$SUITE http://snapshot.debian.org/archive/debian/$WAYBACK_DATE/"
674   else
675     FAI_DEBOOTSTRAP="$SUITE http://ftp.debian.org/debian"
676   fi
677 fi
678
679 if [ -z "$FAI_DEBOOTSTRAP_OPTS" ] ; then
680   FAI_DEBOOTSTRAP_OPTS="--exclude=info,tasksel,tasksel-data --include=aptitude --arch $ARCH"
681 fi
682
683 # create backup of old (not yet automatically generated) config file
684 if [ -f "${GRML_FAI_CONFIG}/make-fai-nfsroot.conf" ] ; then
685   if ! grep -q 'This is an automatically generated file by grml-live' "${GRML_FAI_CONFIG}/make-fai-nfsroot.conf" ; then
686     ewarn "Found old ${GRML_FAI_CONFIG}/make-fai-nfsroot.conf - moving to ${GRML_FAI_CONFIG}/make-fai-nfsroot.conf.outdated"
687     mv "${GRML_FAI_CONFIG}/make-fai-nfsroot.conf" "${GRML_FAI_CONFIG}/make-fai-nfsroot.conf.outdated"
688     eend $?
689   fi
690 fi
691
692 echo "# This is an automatically generated file by grml-live.
693 # Do NOT edit this file, your changes will be lost.
694 FAI_DEBOOTSTRAP=\"$FAI_DEBOOTSTRAP\"
695 FAI_DEBOOTSTRAP_OPTS=\"$FAI_DEBOOTSTRAP_OPTS\"
696 # EOF " > "${GRML_FAI_CONFIG}/nfsroot.conf"
697 # support FAI <=3.4.8, versions >=4.0 use nfsroot.conf
698 ( cd ${GRML_FAI_CONFIG} && ln -sf nfsroot.conf make-fai-nfsroot.conf )
699 # }}}
700
701 # CHROOT_OUTPUT - execute FAI {{{
702 if [ -n "$BUILD_DIRTY" ]; then
703    log   "Skipping stage 'fai' as requested via option -B"
704    ewarn "Skipping stage 'fai' as requested via option -B" ; eend 0
705 else
706    [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
707
708    if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
709       FAI_ACTION=softupdate
710    else
711       FAI_ACTION=dirinstall
712    fi
713
714    if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
715       if ! [ -r "$CHROOT_OUTPUT/etc/debian_version" ] ; then
716          log    "Error: does not look like you have a working chroot. Updating/building not possible."
717          eerror "Error: does not look like you have a working chroot. Updating/building not possible. (Drop -u/-b option?)"
718          eend 1
719          bailout 20
720       fi
721    fi
722
723    if [ -d "$CHROOT_OUTPUT/bin" -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
724       log   "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already."
725       ewarn "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already." ; eend 0
726    else
727       mkdir -p "$CHROOT_OUTPUT" || bailout 5 "Problem with creating $CHROOT_OUTPUT for FAI"
728
729       if [ -n "${MIRROR_DIRECTORY}" ] ; then
730          mkdir -p "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
731          mount --bind "${MIRROR_DIRECTORY}" "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
732       fi
733
734       mkdir -p "${OUTPUT}/grml_sources/" "${CHROOT_OUTPUT}/grml-live/sources/"
735       mount --bind "${OUTPUT}/grml_sources/" "${CHROOT_OUTPUT}/grml-live/sources/"
736
737       log "Executed FAI command line:"
738       log "BUILD_ONLY=$BUILD_ONLY BOOTSTRAP_ONLY=$BOOTSTRAP_ONLY GRML_LIVE_CONFIG=$CONFIGDUMP WAYBACK_DATE=$WAYBACK_DATE fai $VERBOSE -C $GRML_FAI_CONFIG -s file:///$GRML_FAI_CONFIG/config -c$CLASSES -u $HOSTNAME $FAI_ACTION $CHROOT_OUTPUT $FAI_ARGS"
739       BUILD_ONLY="$BUILD_ONLY" BOOTSTRAP_ONLY="$BOOTSTRAP_ONLY" GRML_LIVE_CONFIG="$CONFIGDUMP" fai $VERBOSE \
740                   -C "$GRML_FAI_CONFIG" -s "file:///$GRML_FAI_CONFIG/config" -c"$CLASSES" \
741                   -u "$HOSTNAME" "$FAI_ACTION" "$CHROOT_OUTPUT" $FAI_ARGS | tee -a $LOGFILE
742       RC="$PIPESTATUS" # notice: bash-only
743
744       if [ "$RC" != 0 ] ; then
745          log    "Error: critical error while executing fai [exit code ${RC}]. Exiting."
746          eerror "Error: critical error while executing fai [exit code ${RC}]. Exiting." ; eend 1
747          bailout 1
748       fi
749
750       # provide inform fai about the ISO we build, needs to be provided
751       # *after* FAI stage, otherwise FAI skips the debootstrap stage if
752       # there is not BASEFILE (as it checks for presence of /etc) :(
753       echo '# This file has been generated by grml-live.' > "$CHROOT_OUTPUT/etc/grml_live_version"
754       [ -n "$GRML_LIVE_VERSION" ] && echo "GRML_LIVE_VERSION=$GRML_LIVE_VERSION" >> "$CHROOT_OUTPUT/etc/grml_live_version"
755       [ -n "$SUITE" ] && echo "SUITE=$SUITE" >> "$CHROOT_OUTPUT/etc/grml_live_version"
756
757       FORCE_ISO_REBUILD=true
758
759       # move fai logs into grml_logs directory
760       mkdir -p "$LOG_OUTPUT"/fai/
761       cp -r "$CHROOT_OUTPUT"/var/log/fai/"$HOSTNAME"/last/* "$LOG_OUTPUT"/fai/
762       rm -rf "$CHROOT_OUTPUT"/var/log/fai
763
764       # store copy of autogenerated configuration file
765       cp ${GRML_FAI_CONFIG}/nfsroot.conf "$LOG_OUTPUT"/fai/
766
767       # copy fai package list
768       cp "$CHROOT_OUTPUT"/var/log/install_packages.list "$LOG_OUTPUT"/fai/
769       # fixup owners
770       chown root:adm "$LOG_OUTPUT"/fai/*
771       chmod 664 "$LOG_OUTPUT"/fai/*
772
773       umount_all
774
775       # notice: 'fai dirinstall' does not seem to exit appropriate, so:
776       ERROR=''
777       CHECKLOG="$LOG_OUTPUT"/fai/
778       if [ -r "$CHECKLOG/software.log" ] ; then
779          # 1 errors during executing of commands
780          grep 'dpkg: error processing' $CHECKLOG/software.log >> $LOGFILE && ERROR=1
781          grep 'E: Method http has died unexpectedly!' $CHECKLOG/software.log >> $LOGFILE && ERROR=2
782          grep 'ERROR: chroot' $CHECKLOG/software.log >> $LOGFILE && ERROR=3
783          grep 'E: Failed to fetch' $CHECKLOG/software.log >> $LOGFILE && ERROR=4
784          grep 'Unable to write mmap - msync (28 No space left on device)' $CHECKLOG/software.log >> $LOGFILE && ERROR=5
785       fi
786
787       if [ -r "$CHECKLOG/shell.log" ] ; then
788          grep 'FAILED with exit code' $CHECKLOG/shell.log >> $LOGFILE && ERROR=6
789       fi
790
791       if [ -r "$CHECKLOG/fai.log" ] ; then
792         grep 'updatebase.*FAILED with exit code' "$CHECKLOG/fai.log" >> "$LOGFILE" && ERROR=7
793         grep 'instsoft.*FAILED with exit code'   "$CHECKLOG/fai.log" >> "$LOGFILE" && ERROR=8
794       fi
795
796       if [ -n "$ERROR" ] ; then
797          log    "Error: there was a critical error [${ERROR}] during execution of stage 'fai dirinstall' [$(date)]"
798          eerror "Error: there was a critical error during execution of stage 'fai dirinstall'"
799          eerror "Note:  check out ${CHECKLOG}/ for details. [exit ${ERROR}]"
800          eend 1
801          bailout 1
802       else
803          log "Finished execution of stage 'fai dirinstall' [$(date)]"
804          einfo "Finished execution of stage 'fai dirinstall'"
805       fi
806    fi
807 fi # BUILD_DIRTY?
808 # }}}
809
810 # package validator {{{
811 CHECKLOG=/var/log/fai/$HOSTNAME/last
812 if [ -r "$CHECKLOG/dpkg.selections" ] ; then
813   package_count=$(wc -l "$CHECKLOG/dpkg.selections" | awk '{print $1}')
814 else
815   package_count="unknown"
816 fi
817
818 mkdir -p "$REPORTS"
819 REPORT_MISSING_PACKAGES="${REPORTS}/TEST-MissingPackages.xml"
820
821 # check for missing packages
822 if ! [ -s "$CHECKLOG/package_errors.log" ] ; then
823   einfo "No missing packages found, generating empty junit report."
824
825   cat > "${REPORT_MISSING_PACKAGES}" << EOF
826 <?xml version="1.0" encoding="UTF-8"?>
827 <testsuite name="grml-live-missing-packages" tests="${package_count}" time="1" failures="0" errors="0" skipped="0" assertions="0">
828   <testcase name="test_missing_packages" time="0" assertions="0">
829   </testcase>
830   <system-out>
831   </system-out>
832   <system-err>
833   </system-err>
834 </testsuite>
835 EOF
836   eend 0
837 else
838   einfo "Missing packages found, generating junit report."
839
840   if [ -r "$CHECKLOG/package_errors.log" ] ; then
841     package_errors=$(wc -l "$CHECKLOG/package_errors.log" | awk '{print $1}')
842   else
843     package_errors="unknown"
844   fi
845
846   mkdir -p "$REPORTS"
847   REPORT_MISSING_PACKAGES="${REPORTS}/TEST-MissingPackages.xml"
848
849   cat > "${REPORT_MISSING_PACKAGES}" << EOF
850 <?xml version="1.0" encoding="UTF-8"?>
851 <testsuite name="grml-live-missing-packages" tests="${package_count}" time="1" failures="${package_errors}" errors="${package_errors}" skipped="0" assertions="0">
852 EOF
853
854   for package in $(awk '{print $1}' "${CHECKLOG}/package_errors.log" | sed 's;/;\\/;') ; do
855     failure_reason="$(awk "/$package/ {print \$2}" "${CHECKLOG}/package_errors.log")"
856     cat >> "${REPORT_MISSING_PACKAGES}" << EOF
857   <testcase name="test_missing_packages_${package}" time="0" assertions="0">
858     <failure type="${failure_reason}" message="Package ${package} is missing">
859 Package $package is missing in chroot (${failure_reason})
860   </failure>
861   </testcase>
862 EOF
863   done
864
865   cat >> "${REPORT_MISSING_PACKAGES}" << EOF
866   <system-out>
867   </system-out>
868   <system-err>
869   </system-err>
870 </testsuite>
871 EOF
872   eend 0
873
874   if [ -n "$EXIT_ON_MISSING_PACKAGES" -a -z "$BUILD_DIRTY" ] ; then
875     eerror "The following packages were requested for installation but could not be processed:"
876     cat "$CHECKLOG/package_errors.log"
877     eerror "... exiting as requested via \$EXIT_ON_MISSING_PACKAGES."
878     eend 1
879     bailout 13
880   else
881     ewarn "The following packages were requested for installation but could not be processed:"
882     cat "$CHECKLOG/package_errors.log"
883     eend 0
884   fi
885 fi
886 # }}}
887
888 # grub boot {{{
889 grub_setup() {
890   BOOTX64="/boot/bootx64.efi"
891   BOOTX32="/boot/bootia32.efi"
892   EFI_IMG="/boot/efi.img"
893
894   if [[ "$ARCH" == "amd64" ]] ; then
895     # important: this depends on execution of ${GRML_FAI_CONFIG}/config/scripts/GRMLBASE/45-grub-images
896     if ! [ -r "${CHROOT_OUTPUT}/${BOOTX64}" ] ; then
897       log    "Can not access GRUB efi image ${CHROOT_OUTPUT}/${BOOTX64}, required for Secure Boot support"
898       eerror "Can not access GRUB efi image ${CHROOT_OUTPUT}/${BOOTX64}, required for Secure Boot support" ; eend 1
899       log    "Possible reason is failure to run ${GRML_FAI_CONFIG}/config/scripts/GRMLBASE/45-grub-images"
900       ewarn  "Possible reason is failure to run ${GRML_FAI_CONFIG}/config/scripts/GRMLBASE/45-grub-images"
901       bailout 50
902     fi
903
904     dd if=/dev/zero of="${CHROOT_OUTPUT}/${EFI_IMG}" bs=4M count=1 2>/dev/null || bailout 50
905     mkfs.vfat -n GRML "${CHROOT_OUTPUT}/${EFI_IMG}" >/dev/null || bailout 51
906     mmd -i "${CHROOT_OUTPUT}/${EFI_IMG}" ::EFI || bailout 52
907     mmd -i "${CHROOT_OUTPUT}/${EFI_IMG}" ::EFI/BOOT || bailout 52
908
909     if [ "${SECURE_BOOT:-}" = "disable" ] ; then
910       log   "Secure Boot is disabled."
911       einfo "Secure Boot is disabled." ; eend 0
912
913       # install "$BOOTX64" as ::EFI/BOOT/bootx64.efi inside image file "$EFI_IMG":
914       mcopy -i "${CHROOT_OUTPUT}/${EFI_IMG}" "${CHROOT_OUTPUT}/${BOOTX64}" ::EFI/BOOT/bootx64.efi >/dev/null || bailout 53
915
916       log   "Generated 64-bit EFI image $BOOTX64"
917       einfo "Generated 64-bit EFI image $BOOTX64" ; eend 0
918     else
919       log   "Secure Boot is enabled [mode: $SECURE_BOOT]"
920       einfo "Secure Boot is enabled [mode: $SECURE_BOOT]" ; eend 0
921
922       if [ "${SECURE_BOOT}" = "ubuntu" ] ; then
923         local GRUBCFG_TEMPLATE="${TEMPLATE_DIRECTORY}/secureboot/grub.cfg"
924         local GRUBCFG_TMP=$(mktemp)
925
926         if ! [ -r "${GRUBCFG_TEMPLATE}" ] ; then
927           log    "Secure Boot template for GRUB [${GRUBCFG_TEMPLATE}] not found."
928           eerror "Secure Boot template for GRUB [${GRUBCFG_TEMPLATE}] not found." ; eend 1
929           bailout 54
930         fi
931
932         cp "${GRUBCFG_TEMPLATE}" "${GRUBCFG_TMP}"
933         adjust_boot_files "${GRUBCFG_TMP}"
934
935         mmd -i "${CHROOT_OUTPUT}/${EFI_IMG}" ::EFI/ubuntu || bailout 55
936         mcopy -i "${CHROOT_OUTPUT}/${EFI_IMG}" "${GRUBCFG_TMP}" ::EFI/ubuntu/grub.cfg || bailout 56
937         rm "${GRUBCFG_TMP}"
938
939         mcopy -i "${CHROOT_OUTPUT}/${EFI_IMG}" "${TEMPLATE_DIRECTORY}"/EFI/BOOT/grubx64.efi.signed ::EFI/BOOT/grubx64.efi >/dev/null || bailout 57
940         mcopy -i "${CHROOT_OUTPUT}/${EFI_IMG}" "${TEMPLATE_DIRECTORY}"/EFI/BOOT/shimx64.efi.signed ::EFI/BOOT/bootx64.efi >/dev/null || bailout 58
941
942         log   "Generated 64-bit Secure Boot (ubuntu) EFI image ${CHROOT_OUTPUT}/${EFI_IMG}"
943         einfo "Generated 64-bit Secure Boot (ubuntu) EFI image ${CHROOT_OUTPUT}/${EFI_IMG}" ; eend 0
944       fi
945     fi
946   fi
947
948   if [[ "$ARCH" == "i386" ]] ; then
949     if ! [ -r "${CHROOT_OUTPUT}/${BOOTX32}" ] ; then
950       log    "Can not access GRUB efi image ${CHROOT_OUTPUT}/${BOOTX32}."
951       eerror "Can not access GRUB efi image ${CHROOT_OUTPUT}/${BOOTX32}." ; eend 1
952       log    "Possible reason is failure to run ${GRML_FAI_CONFIG}/config/scripts/GRMLBASE/45-grub-images"
953       ewarn "Possible reason is failure to run ${GRML_FAI_CONFIG}/config/scripts/GRMLBASE/45-grub-images"
954       bailout 50
955     fi
956
957     dd if=/dev/zero of="${CHROOT_OUTPUT}/${EFI_IMG}" bs=4M count=1 2>/dev/null || bailout 50
958     mkfs.vfat -n GRML "${CHROOT_OUTPUT}/${EFI_IMG}" >/dev/null || bailout 51
959     mmd -i "${CHROOT_OUTPUT}/${EFI_IMG}" ::EFI || bailout 52
960     mmd -i "${CHROOT_OUTPUT}/${EFI_IMG}" ::EFI/BOOT || bailout 52
961     mcopy -i "${CHROOT_OUTPUT}/${EFI_IMG}" "${CHROOT_OUTPUT}/${BOOTX32}" ::EFI/BOOT/bootia32.efi >/dev/null || bailout 53
962     log   "Generated 32-bit EFI image $BOOTX32"
963     einfo "Generated 32-bit EFI image $BOOTX32" ; eend 0
964   fi
965 }
966 # }}}
967
968 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
969 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
970 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
971
972 # prepare ISO
973 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
974   if [ -n "$BOOTSTRAP_ONLY" ] ; then
975     log   "Skipping stage 'boot' as building with bootstrap only."
976     ewarn "Skipping stage 'boot' as building with bootstrap only." ; eend 0
977   else
978     # booting stuff:
979     mkdir -p "$BUILD_OUTPUT"/boot/isolinux
980     mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"
981
982     # if we don't have an initrd we a) can't boot and b) there was an error
983     # during build, so check for the file:
984     INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
985     if [ -n "$INITRD" ] ; then
986       cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/initrd.img
987       find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
988     else
989       log    "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
990       eerror "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
991       bailout 10
992     fi
993
994     KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
995     if [ -n "$KERNEL_IMAGE" ] ; then
996       cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/vmlinuz
997     else
998       log    "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
999       eerror "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
1000       bailout 11
1001     fi
1002
1003     # we need to set "$BOOTID" before we invoke adjust_boot_files for the
1004     # first time, being inside grub_setup below
1005     if [ -n "$NO_BOOTID" ] ; then
1006       log   'Skipping bootid feature as requested via $NO_BOOTID.'
1007       einfo 'Skipping bootid feature as requested via $NO_BOOTID.'
1008     else
1009       [ -n "$BOOTID" ] || BOOTID="$(echo ${GRML_NAME}${VERSION} | tr -d ',./;\- ')"
1010       mkdir -p "$BUILD_OUTPUT"/conf
1011       einfo "Generating /conf/bootid.txt with entry ${BOOTID}."
1012       log   "Generating /conf/bootid.txt with entry ${BOOTID}."
1013       echo "$BOOTID" > "$BUILD_OUTPUT"/conf/bootid.txt
1014       eend $?
1015     fi
1016
1017     # every recent Grml ISO ships a /conf/bootid.txt, though GRUB might find
1018     # the /conf/bootid.txt of a different (Grml) ISO than the one that's
1019     # supposed to be running, so within scripts/GRMLBASE/45-grub-images
1020     # we generate a random filename, stored inside /boot/grub/bootfile.txt,
1021     # which we place on the resulting ISO here
1022     if [ -r "${CHROOT_OUTPUT}"/boot/grub/bootfile.txt ] ; then
1023       mkdir -p "${BUILD_OUTPUT}"/conf
1024       rm -f "${BUILD_OUTPUT}"/conf/bootfile*  # ensure we don't leave any old(er) files behind
1025
1026       einfo "Generating "${BUILD_OUTPUT}"/conf/bootfile* files"
1027       log   "Generating "${BUILD_OUTPUT}"/conf/bootfile* files"
1028
1029       BOOT_FILE="/conf/bootfile_$(cat "${CHROOT_OUTPUT}"/boot/grub/bootfile.txt)"
1030       echo "# This file is relevant for GRUB boot with the Grml ISO." > "${BUILD_OUTPUT}/${BOOT_FILE}"
1031       # save information about the random filename inside /conf/bootfile.txt
1032       echo "${BOOT_FILE}" > "${BUILD_OUTPUT}"/conf/bootfile.txt
1033       eend $?
1034     fi
1035
1036     grub_setup
1037
1038     # EFI boot files
1039     if [ -r "${CHROOT_OUTPUT}/boot/efi.img" -a -r "${CHROOT_OUTPUT}/boot/bootx64.efi" ] ; then
1040       einfo "Copying 64-bit EFI boot files into ISO path."
1041       log   "Copying 64-bit EFI boot files into ISO path."
1042       RC=$0
1043       cp "${CHROOT_OUTPUT}/boot/efi.img" "${BUILD_OUTPUT}/boot/" || RC=$?
1044       mkdir -p "${BUILD_OUTPUT}/EFI/BOOT/" || RC=$?
1045       cp "${CHROOT_OUTPUT}/boot/bootx64.efi" "${BUILD_OUTPUT}/EFI/BOOT/bootx64.efi" || RC=$?
1046       eend $?
1047     elif [ -r "${CHROOT_OUTPUT}/boot/efi.img" -a -r "${CHROOT_OUTPUT}/boot/bootia32.efi" ] ; then
1048       einfo "Copying 32-bit EFI boot files into ISO path."
1049       log "Copying 32-bit EFI boot files into ISO path."
1050       RC=$0
1051       cp "${CHROOT_OUTPUT}/boot/efi.img" "${BUILD_OUTPUT}/boot/" || RC=$?
1052       mkdir -p "${BUILD_OUTPUT}/EFI/BOOT/" || RC=$?
1053       cp "${CHROOT_OUTPUT}/boot/bootia32.efi" "${BUILD_OUTPUT}/EFI/BOOT/bootia32.efi" || RC=$?
1054       eend $?
1055     else
1056       ewarn "No EFI boot files found, skipping." ; eend 0
1057     fi
1058
1059     [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
1060     if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
1061       log    "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
1062       eerror "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
1063       bailout 8
1064     fi
1065
1066     # copy _required_ isolinux files
1067     if [ -d "${CHROOT_OUTPUT}/usr/lib/ISOLINUX" ] ; then
1068       copy_addon_file isolinux.bin /usr/lib/ISOLINUX isolinux
1069       for file in ${CHROOT_OUTPUT}/usr/lib/syslinux/modules/bios/*.c32 ; do
1070         copy_addon_file "$(basename "$file")"  /usr/lib/syslinux/modules/bios/ isolinux
1071       done
1072     else # syslinux versions <= 3:4.05+dfsg-6+deb8u1
1073       copy_addon_file isolinux.bin /usr/lib/syslinux isolinux
1074       copy_addon_file ifcpu64.c32  /usr/lib/syslinux isolinux
1075       copy_addon_file vesamenu.c32 /usr/lib/syslinux isolinux
1076     fi
1077
1078     # *always* copy files to output directory so the variables
1079     # get adjusted according to the build.
1080     cp ${TEMPLATE_DIRECTORY}/boot/isolinux/*  "$BUILD_OUTPUT"/boot/isolinux/
1081
1082     mkdir -p "${BUILD_OUTPUT}/boot/grub"
1083     cp -a ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
1084
1085     if [ -n "$NO_ADDONS" ] ; then
1086       rm -f "$BUILD_OUTPUT"/boot/grub/addons.cfg
1087       log   "Skipping installation of boot addons as requested via \$NO_ADDONS."
1088       einfo "Skipping installation of boot addons as requested via \$NO_ADDONS."; eend 0
1089     else
1090       if ! [ -d "$TEMPLATE_DIRECTORY"/boot/addons ] ; then
1091         log   "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)"
1092         ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
1093       else
1094         # copy addons from system packages or grml-live-addons
1095         copy_addon_file ipxe.lkrn /usr/lib/ipxe addons
1096         copy_addon_file pci.ids /usr/share/misc addons
1097         copy_addon_file memtest86+.bin /boot addons
1098
1099         # since syslinux(-common) v3:6.03~pre1+dfsg-4 the files are in a
1100         # different directory :(
1101         if [ -d "${CHROOT_OUTPUT}/usr/lib/syslinux/modules/bios/" ] ; then
1102           syslinux_modules_dir=/usr/lib/syslinux/modules/bios/
1103         else
1104           syslinux_modules_dir=/usr/lib/syslinux
1105         fi
1106         for file in chain.c32 hdt.c32 mboot.c32 menu.c32; do
1107           copy_addon_file "${file}" "${syslinux_modules_dir}" addons
1108         done
1109
1110         copy_addon_file memdisk /usr/lib/syslinux addons
1111
1112         # make memtest filename FAT16/8.3 compatible
1113         mv "${BUILD_OUTPUT}/boot/addons/memtest86+.bin" \
1114           "${BUILD_OUTPUT}/boot/addons/memtest"
1115
1116         # copy only files so we can handle bsd4grml on its own
1117         for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
1118           test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
1119         done
1120
1121         if [ -n "$NO_ADDONS_BSD4GRML" ] ; then
1122           log   "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."
1123           einfo "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."; eend 0
1124         else
1125           if [ -d "$TEMPLATE_DIRECTORY"/boot/addons/bsd4grml ] ; then
1126             cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
1127           else
1128             log   "Missing addon file: bsd4grml"
1129             ewarn "Missing addon file: bsd4grml" ; eend 0
1130           fi
1131         fi
1132
1133       fi # no "$TEMPLATE_DIRECTORY"/boot/addons
1134     fi # NO_ADDONS
1135
1136     # generate loopback.cfg config file without depending on grub's regexp module
1137     # which isn't available in Debian/squeeze
1138     echo "## grub2 loopback configuration" > "${BUILD_OUTPUT}"/boot/grub/loopback.cfg
1139     echo "source /boot/grub/header.cfg" >> "${BUILD_OUTPUT}"/boot/grub/loopback.cfg
1140     for config in "${BUILD_OUTPUT}"/boot/grub/*_default.cfg "${BUILD_OUTPUT}"/boot/grub/*_options.cfg ; do
1141       [ -r "$config" ] || continue
1142       echo "source ${config##$BUILD_OUTPUT}" >> "${BUILD_OUTPUT}"/boot/grub/loopback.cfg
1143     done
1144     if [ -z "$NO_ADDONS" ] ; then
1145       echo "source /boot/grub/addons.cfg" >> "${BUILD_OUTPUT}"/boot/grub/loopback.cfg
1146     fi
1147     echo "source /boot/grub/footer.cfg" >> "${BUILD_OUTPUT}"/boot/grub/loopback.cfg
1148
1149     # copy grub files from target
1150     mkdir -p "${BUILD_OUTPUT}"/boot/grub/i386-pc/
1151     cp -a "${CHROOT_OUTPUT}"/usr/lib/grub/*-pc/*.mod "${BUILD_OUTPUT}"/boot/grub/i386-pc/
1152     cp -a "${CHROOT_OUTPUT}"/usr/lib/grub/*-pc/*.o "${BUILD_OUTPUT}"/boot/grub/i386-pc/
1153     cp -a "${CHROOT_OUTPUT}"/usr/lib/grub/*-pc/*.lst "${BUILD_OUTPUT}"/boot/grub/i386-pc/
1154     cp -a "${CHROOT_OUTPUT}"/usr/share/grub/ascii.pf2 "${BUILD_OUTPUT}"/boot/grub/
1155     cp -a "${CHROOT_OUTPUT}"/boot/grub/core.img "${BUILD_OUTPUT}"/boot/grub/
1156     cp -a "${CHROOT_OUTPUT}"/boot/grub/grub.img "${BUILD_OUTPUT}"/boot/grub/
1157
1158     # copy modules for UEFI grub, 64-bit
1159     mkdir -p "${BUILD_OUTPUT}"/boot/grub/x86_64-efi/
1160     cp -a "${CHROOT_OUTPUT}"/usr/lib/grub/x86_64-efi/*.{mod,lst} "${BUILD_OUTPUT}"/boot/grub/x86_64-efi/
1161
1162     # copy modules for UEFI grub, 32-bit
1163     mkdir -p "${BUILD_OUTPUT}"/boot/grub/i386-efi/
1164     cp -a "${CHROOT_OUTPUT}"/usr/lib/grub/i386-efi/*.{mod,lst} "${BUILD_OUTPUT}"/boot/grub/i386-efi/
1165
1166     if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
1167       log    "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
1168       eerror "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
1169       bailout 9
1170     fi
1171
1172     mkdir -p "$BUILD_OUTPUT"/GRML/"${GRML_NAME}"/
1173     cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/"${GRML_NAME}"/
1174
1175     # adjust boot splash information:
1176     RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
1177     RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
1178     RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
1179
1180     if [ -r "$BUILD_OUTPUT"/GRML/"${GRML_NAME}"/grml-version ] ; then
1181       sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/"${GRML_NAME}"/grml-version
1182       sed -i "s/%DATE%/$DATE/"                                      "$BUILD_OUTPUT"/GRML/"${GRML_NAME}"/grml-version
1183     fi
1184
1185     # make sure the squashfs filename is set accordingly:
1186     SQUASHFS_NAME="$GRML_NAME.squashfs"
1187
1188     # adjust all variables in the templates with the according distribution information
1189     adjust_boot_files "${BUILD_OUTPUT}"/boot/isolinux/*.cfg \
1190       "${BUILD_OUTPUT}"/boot/isolinux/*.msg \
1191       "${BUILD_OUTPUT}"/boot/grub/* \
1192       "${BUILD_OUTPUT}"/boot/ubuntu/*
1193
1194     for param in ARCH DATE DISTRI_INFO DISTRI_NAME DISTRI_SPLASH GRML_NAME SQUASHFS_NAME \
1195       RELEASE_INFO SHORT_NAME VERSION ; do
1196       for file in $(find "${BUILD_OUTPUT}" -name "*%$param%*") ; do
1197         value="$(eval echo '$'"$param")"
1198         mv ${file} ${file/\%${param}\%/$value}
1199       done
1200     done
1201
1202     # adjust bootsplash accordingly but make sure the string has the according length
1203     SQUASHFS_NAME="$(cut_string 20 "$SQUASHFS_NAME")"
1204     SQUASHFS_NAME="$(extend_string_end 20 "$SQUASHFS_NAME")"
1205     for file in f4 f5 ; do
1206       if [ -r "${BUILD_OUTPUT}/boot/isolinux/${file}" ] ; then
1207         sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
1208         sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
1209       fi
1210     done
1211
1212     # generate addon list
1213     rm -f "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
1214     for name in "${BUILD_OUTPUT}"/boot/isolinux/addon_*.cfg ; do
1215       include_name=$(basename "$name")
1216       echo "include $include_name"  >> "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
1217     done
1218
1219     if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
1220       log "including grmlmain.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1221       echo "include grmlmain.cfg"    >  "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1222       echo "include default.cfg"     >  "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1223       echo "include menuoptions.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1224       echo "include grml.cfg"        >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1225
1226       for f in "${BUILD_OUTPUT}"/boot/isolinux/submenu*.cfg ; do
1227         echo "include $(basename $f)"     >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1228       done
1229
1230       echo "include options.cfg"     >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1231       if [ -z "$NO_ADDONS" ] ; then
1232         echo "include addons.cfg"    >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1233       fi
1234       echo "include isoprompt.cfg"   >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1235       echo "include hd.cfg"          >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1236       echo "include hidden.cfg"      >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1237     else # assume we are building a custom distribution:
1238       log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
1239       einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
1240       if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
1241         log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
1242         eindent
1243         einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
1244         eoutdent
1245         eend $?
1246       else
1247         log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1248         echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1249         if [ -z "$NO_ADDONS" ] ; then
1250           echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1251         fi
1252       fi
1253     fi
1254
1255     # use old style console based isolinux method only if requested:
1256     if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
1257       log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
1258       einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
1259       if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
1260         einfo "include for console.cfg already found, nothing to do."
1261         eend 0
1262       else
1263         log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1264         einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1265         echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1266         eend $?
1267       fi
1268     else
1269       log 'Using graphical boot menu.'
1270       if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
1271         log "include for vesamenu.cfg already found, nothing to do."
1272       else
1273         log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1274         echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1275       fi
1276     fi
1277
1278     if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
1279       sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
1280     fi
1281
1282     DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot
1283     if ! [ -r "$DPKG_LIST" ] ; then
1284       ewarn "$DPKG_LIST could not be read, ignoring to store package information on ISO therefore."
1285     else
1286       einfo "Storing package list information as /GRML/${GRML_NAME}/packages.txt on ISO."
1287       cp "$DPKG_LIST" "${BUILD_OUTPUT}"/GRML/"${GRML_NAME}"/packages.txt
1288       eend $?
1289     fi
1290
1291     # autostart for Windows:
1292     if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
1293       cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
1294     fi
1295
1296     FORCE_ISO_REBUILD=true
1297     einfo "Finished execution of stage 'boot'" ; eend 0
1298   fi # BOOTSTRAP_ONLY
1299 else
1300   log    'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
1301   eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
1302   bailout
1303 fi
1304
1305 # support installation of local files into the chroot/ISO
1306 if [ -n "$CHROOT_INSTALL" ] ; then
1307   if ! [ -d "$CHROOT_INSTALL" ] ; then
1308      log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1309      ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1310   else
1311      log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1312      einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1313      rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
1314      eend $?
1315      einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
1316      FORCE_ISO_REBUILD=true
1317   fi
1318 fi
1319
1320 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
1321    log   "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
1322    ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
1323 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
1324    log   "Skipping stage 'squashfs' as requested via option -q or -N"
1325    ewarn "Skipping stage 'squashfs' as requested via option -q or -N" ; eend 0
1326 else
1327    mkdir -p "$BUILD_OUTPUT"/live/"${GRML_NAME}"/
1328    # make sure we don't leave (even an empty) base.tgz:
1329    [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
1330
1331    # if unconfigured default to squashfs-tools' mksquashfs binary
1332    if [ -z "$SQUASHFS_BINARY" ] ; then
1333       SQUASHFS_BINARY='mksquashfs'
1334    fi
1335
1336    if which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
1337       log    "Using mksquashfs binary ${SQUASHFS_BINARY}"
1338       einfo  "Using mksquashfs binary ${SQUASHFS_BINARY}" ; eend 0
1339    else
1340       log    "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
1341       eerror "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
1342       bailout
1343    fi
1344
1345    # use sane defaults if $SQUASHFS_OPTIONS isn't set
1346    if [ -z "$SQUASHFS_OPTIONS" ] ; then
1347      # use blocksize 256k as this gives best result with regards to time + compression
1348      SQUASHFS_OPTIONS="-b 256k"
1349
1350      # set lzma/xz compression by default, unless -z option has been specified on command line
1351      if [ -z "$SQUASHFS_ZLIB" ] ; then
1352         SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp xz"
1353      else
1354         SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp gzip"
1355      fi
1356    fi
1357
1358    # support exclusion of files via exclude-file:
1359    if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
1360       SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE -wildcards"
1361    fi
1362
1363    # get rid of unnecessary files when building grml-small for final release:
1364    if echo "$CLASSES" | grep -q GRML_SMALL ; then
1365       SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
1366    fi
1367
1368    # log stuff
1369    SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
1370
1371    # informational stuff
1372    [ -n "$SQUASHFS_OPTIONS" ]  && SQUASHFS_INFO_MSG="$SQUASHFS_OPTIONS"
1373    [ -n "$SQUASHFS_INFO_MSG" ] && SQUASHFS_INFO_MSG="using options: $SQUASHFS_INFO_MSG"
1374    einfo "Squashfs build information: running binary $SQUASHFS_BINARY $SQUASHFS_INFO_MSG"
1375
1376    log "$SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/${GRML_NAME}/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS"
1377
1378    if $SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/"${GRML_NAME}"/"${GRML_NAME}".squashfs \
1379       -noappend $SQUASHFS_OPTIONS 2>"${SQUASHFS_STDERR}" ; then
1380       echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/"${GRML_NAME}"/filesystem.module
1381       log "Finished execution of stage 'squashfs' [$(date)]"
1382       einfo "Finished execution of stage 'squashfs'" ; eend 0
1383    else
1384       log    "Error: there was a critical error executing stage 'squashfs' [$(date)]:"
1385       log    "$(cat $SQUASHFS_STDERR)"
1386       eerror "Error: there was a critical error executing stage 'squashfs':"
1387       cat    "${SQUASHFS_STDERR}"
1388       eend 1
1389       bailout
1390    fi
1391
1392    FORCE_ISO_REBUILD=true
1393 fi
1394
1395 # create md5sum file:
1396 if [ -z "$BOOTSTRAP_ONLY" ] ; then
1397   ( cd $BUILD_OUTPUT/GRML/"${GRML_NAME}" &&
1398   find ../.. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
1399 fi
1400 # }}}
1401
1402 # ISO_OUTPUT - mkisofs {{{
1403 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
1404 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
1405
1406 if [ "$BOOT_METHOD" = "isolinux" ] ; then
1407    BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
1408    if [ "$HYBRID_METHOD" = "isohybrid" ] ; then
1409      EFI_ARGS="-isohybrid-mbr /usr/lib/ISOLINUX/isohdpfx.bin -eltorito-alt-boot -e boot/efi.img -no-emul-boot -isohybrid-gpt-basdat"
1410    fi
1411 elif [ "$BOOT_METHOD" = "grub2" ] ; then
1412    BOOT_ARGS="-no-emul-boot -boot-load-size 4 -b boot/grub/toriboot.bin"
1413 fi
1414
1415 # Work around http://bts.grml.org/grml/issue945
1416 if [[ $BOOT_METHOD != isolinux && ($HYBRID_METHOD = isohybrid || $HYBRID_METHOD = manifold) ]]; then
1417   log   "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1418   ewarn "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1419   HYBRID_METHOD='grub2'
1420   eend 0
1421 fi
1422
1423 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ]  ; then
1424    log   "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already."
1425    ewarn "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already." ; eend 0
1426 elif [ -n "$SKIP_MKISOFS" ] ; then
1427    log   "Skipping stage 'iso build' as requested via option -n or -N"
1428    ewarn "Skipping stage 'iso build' as requested via option -n or -N" ; eend 0
1429 else
1430    mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
1431
1432    if $FORCE_ISO_REBUILD && ! [ -f "${ISO_OUTPUT}/${ISO_NAME}" ] ; then
1433       log   "Forcing rebuild of ISO because files on ISO have been modified."
1434       einfo "Forcing rebuild of ISO because files on ISO have been modified."
1435    fi
1436
1437    # support xorriso as well mkisofs and genisoimage
1438    if which xorriso >/dev/null 2>&1 ; then
1439       MKISOFS='xorriso -as mkisofs'
1440     elif which mkisofs >/dev/null 2>&1; then
1441       MKISOFS='mkisofs'
1442    elif which genisoimage >/dev/null 2>&1; then
1443       MKISOFS='genisoimage'
1444    else
1445       log    "Error: neither xorriso nor mkisofs nor genisoimage available - can not create ISO."
1446       eerror "Error: neither xorriso nor mkisofs nor genisoimage available - can not create ISO." ; eend 1
1447       bailout
1448    fi
1449
1450    einfo "Using ${MKISOFS} to build ISO." ;  eend 0
1451    case "${ARCH}-${MKISOFS}" in
1452      # using -eltorito-alt-boot is limited to xorriso for now
1453      amd64-xorriso*)
1454        eindent
1455
1456        if ! dpkg --compare-versions $(dpkg-query -W -f='${Version}\n' xorriso 2>/dev/null) gt-nl 1.1.6-1 ; then
1457          log   "Disabling (U)EFI boot support because xorriso version is too old."
1458          ewarn "Disabling (U)EFI boot support because xorriso version is too old." ; eend 0
1459        else
1460          if [ -r "${BUILD_OUTPUT}"/boot/efi.img ] ; then
1461            einfo "Enabling (U)EFI boot."
1462            log   "Enabling (U)EFI boot."
1463            BOOT_ARGS="$BOOT_ARGS -boot-info-table -eltorito-alt-boot -e boot/efi.img -no-emul-boot"
1464            eend $?
1465          else
1466            log   "Disabling (U)EFI boot support because /boot/efi.img is missing."
1467            ewarn "Disabling (U)EFI boot support because /boot/efi.img is missing." ; eend 0
1468          fi
1469        fi
1470
1471        eoutdent
1472        ;;
1473    esac
1474
1475    CURRENT_DIR=$(pwd)
1476    if cd "$BUILD_OUTPUT" ; then
1477       if [ "$BOOT_METHOD" = "grub2" ]; then
1478          # make a 2048-byte bootsector for El Torito
1479          dd if=/dev/zero of=boot/grub/toriboot.bin bs=512 count=4 2>/dev/null
1480          # those are in 2048-byte sectors, so 1 16 matches 4 63 below
1481          echo 1 16 | mksh "${SCRIPTS_DIRECTORY}/bootgrub.mksh" -B 11 | \
1482             dd of=boot/grub/toriboot.bin conv=notrunc 2>/dev/null
1483       fi
1484       log "$MKISOFS -V '${GRML_NAME} ${VERSION}' -publisher 'grml-live | grml.org' -l -r -J $BOOT_ARGS $EFI_ARGS -no-pad -o ${ISO_OUTPUT}/${ISO_NAME} ."
1485       $MKISOFS -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
1486               -l -r -J $BOOT_ARGS $EFI_ARGS -no-pad \
1487               -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
1488       # both of these need core.img there, so it’s easier to write it here
1489       if [ "$BOOT_METHOD" = "grub2" ] || [ "$HYBRID_METHOD" = "grub2" ]; then
1490          # must be <= 30720 bytes
1491          dd if=boot/grub/core.img of="${ISO_OUTPUT}/${ISO_NAME}" \
1492            conv=notrunc bs=512 seek=4 2>/dev/null
1493       fi
1494
1495       # pad the output ISO to multiples of 256 KiB for partition table support
1496       siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
1497       cyls=$((siz / 512 / 32 / 16 + 1))   # C=$cyls H=16 S=32
1498       siz=$((cyls * 16 * 32 * 512))   # size after padding
1499       dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
1500          of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
1501
1502       # support disabling hybrid ISO image
1503       if [ "$HYBRID_METHOD" = "disable" ] ; then
1504         log   "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1505         einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1506         eend 0
1507       elif [ "$HYBRID_METHOD" = "manifold" ] || [ "$HYBRID_METHOD" = "grub2" ] ; then
1508         # isoinfo is part of both mkisofs and genisoimage so we're good
1509         bootoff=$(isoinfo -l -i "${ISO_OUTPUT}/${ISO_NAME}" | \
1510           sed -n '/^.*\[ *\([0-9]*\)[] ].* ISOLINUX.BIN[;1]* *$/s//\1/p')
1511
1512         if ! [ -r boot/grub/core.img ] ; then
1513           log   "boot/grub/core.img not found, not creating manifold boot ISO file"
1514           ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
1515         elif [ "${bootoff:-0}" -lt 1 ] ; then
1516           log   "isolinux.bin not found on the ISO file, disabling manifold boot"
1517           ewarn "isolinux.bin not found on the ISO file, disabling manifold boot"
1518         else
1519           if [ "$HYBRID_METHOD" = "grub2" ] ; then
1520             log   "Creating hybrid ISO file with manifold/grub2 method"
1521             einfo "Creating hybrid ISO file with manifold/grub2 method"
1522             # 512 bytes: MBR, partition table, load GRUB 2
1523             echo 4 63 | mksh "${SCRIPTS_DIRECTORY}/bootgrub.mksh" -A -M 4:0x96 -g $cyls:16:32
1524           else
1525             log   "Creating hybrid ISO file with manifold method"
1526             einfo "Creating hybrid ISO file with manifold method"
1527             # read only one but 2048-byte sized (scale: << 2) sector
1528             echo $bootoff $bootoff | \
1529               mksh ${SCRIPTS_DIRECTORY}/bootilnx.mksh -A -M 4:0x96 -g $cyls:16:32 -S 2
1530           fi | dd of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
1531           eend $?
1532         fi
1533       elif [ "$HYBRID_METHOD" = "isohybrid" ] ; then
1534         : # nothing to do, handled via $MKISOFS $EFI_ARGS already
1535       else
1536         bailout 12 "Unknown HYBRID_METHOD [${HYBRID_METHOD}]. Supported values: disable, isohybrid, grub2, manifold"
1537       fi
1538
1539       # generate ISO checksums if we are using class 'RELEASE':
1540       case $CLASSES in *RELEASE*)
1541          [ "$RC" = 0 ] && \
1542          (
1543            if cd $ISO_OUTPUT ; then
1544              md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
1545              touch -r ${ISO_NAME} ${ISO_NAME}.md5
1546              sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
1547              touch -r ${ISO_NAME} ${ISO_NAME}.sha1
1548              sha256sum ${ISO_NAME} > ${ISO_NAME}.sha256 && \
1549              touch -r ${ISO_NAME} ${ISO_NAME}.sha256
1550              sha512sum ${ISO_NAME} > ${ISO_NAME}.sha512 && \
1551              touch -r ${ISO_NAME} ${ISO_NAME}.sha512
1552            fi
1553          )
1554          ;;
1555       esac
1556
1557       cd "$CURRENT_DIR"
1558    fi
1559
1560    if [ "$RC" = 0 ] ; then
1561       log   "Finished execution of stage 'iso build' [$(date)]"
1562       einfo "Finished execution of stage 'iso build'" ; eend 0
1563    else
1564       log    "Error: there was a critical error ($RC) executing stage 'iso build' [$(date)]"
1565       eerror "Error: there was a critical error executing stage 'iso build'" ; eend 1
1566       bailout $RC
1567    fi
1568 fi
1569 # }}}
1570
1571 # netboot package {{{
1572 create_netbootpackage() {
1573   local OUTPUT_FILE="${NETBOOT}/grml_netboot_package_${GRML_NAME}_${VERSION}.tar.bz2"
1574
1575   if [ -f "${OUTPUT_FILE}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
1576     log   "Skipping stage 'netboot' as $OUTPUT_FILE exists already."
1577     ewarn "Skipping stage 'netboot' as $OUTPUT_FILE exists already." ; eend 0
1578     return 0
1579   elif [ -n "$SKIP_NETBOOT" ] ; then
1580     log   "Skipping stage 'netboot' as requested via option -Q"
1581     ewarn "Skipping stage 'netboot' as requested via option -Q" ; eend 0
1582     return 0
1583   fi
1584
1585   mkdir -p "$NETBOOT"
1586
1587   # since syslinux v3:6.03~pre1+dfsg-4 the pxelinux.0 has been split into a
1588   # separate pxelinux package
1589   if [ -d "${CHROOT_OUTPUT}/usr/lib/PXELINUX/" ] ; then
1590     local pxelinux_dir=/usr/lib/PXELINUX
1591   else
1592     local pxelinux_dir=/usr/lib/syslinux
1593   fi
1594
1595   if ! [ -r "${CHROOT_OUTPUT}/${pxelinux_dir}/pxelinux.0" ] ; then
1596     ewarn "File ${pxelinux_dir}/pxelinux.0 not found in build chroot." ; eend 0
1597     eindent
1598     einfo "Install syslinux[-common]/pxelinux package in chroot to get a netboot package."
1599     eoutdent
1600     return 0
1601   fi
1602
1603   local OUTPUTDIR="${NETBOOT}/build_tmp"
1604   local WORKING_DIR="${OUTPUTDIR}/grml_netboot_package_${GRML_NAME}_${VERSION}/tftpboot/"
1605
1606   mkdir -p "$WORKING_DIR"
1607
1608   cp "${CHROOT_OUTPUT}"/boot/vmlinuz-*    "$WORKING_DIR"/vmlinuz
1609   cp "${CHROOT_OUTPUT}"/boot/initrd.img-* "$WORKING_DIR"/initrd.img
1610   cp "${CHROOT_OUTPUT}/${pxelinux_dir}/pxelinux.0" "${WORKING_DIR}/pxelinux.0"
1611
1612   if [ -r "${CHROOT_OUTPUT}"/usr/lib/syslinux/modules/bios/ldlinux.c32 ] ; then
1613     cp "${CHROOT_OUTPUT}"/usr/lib/syslinux/modules/bios/ldlinux.c32 "${WORKING_DIR}"/
1614   fi
1615
1616   mkdir -p "${WORKING_DIR}/pxelinux.cfg"
1617   if [ -r "${BUILD_OUTPUT}/boot/isolinux/netboot.cfg" ] ; then
1618     cp "${BUILD_OUTPUT}/boot/isolinux/netboot.cfg" "${WORKING_DIR}/pxelinux.cfg/default"
1619   else
1620     log   "File ${BUILD_OUTPUT}/boot/isolinux/netboot.cfg not found."
1621     ewarn "File ${BUILD_OUTPUT}/boot/isolinux/netboot.cfg not found."
1622     eindent
1623     log   "Hint: Are you using custom templates which do not provide netboot.cfg?"
1624     ewarn "Hint: Are you using custom templates which do not provide netboot.cfg?" ; eend 0
1625     eoutdent
1626   fi
1627
1628   if tar -C "$OUTPUTDIR" -jcf "${OUTPUT_FILE}" "grml_netboot_package_${GRML_NAME}_${VERSION}" ; then
1629     (
1630       cd $(dirname "${OUTPUT_FILE}")
1631       sha1sum $(basename "${OUTPUT_FILE}") > "${OUTPUT_FILE}.sha1"
1632       sha256sum $(basename "${OUTPUT_FILE}") > "${OUTPUT_FILE}.sha256"
1633       sha512sum $(basename "${OUTPUT_FILE}") > "${OUTPUT_FILE}.sha512"
1634     )
1635     einfo "Generated netboot package ${OUTPUT_FILE}" ; eend 0
1636     rm -rf "${OUTPUTDIR}"
1637   else
1638     rm -rf "${OUTPUTDIR}"
1639     eerror "Could not generate netboot package ${OUTPUT_FILE}" ; eend 1
1640     bailout 21
1641   fi
1642 }
1643
1644 create_netbootpackage
1645 # }}}
1646
1647 # log build information to database if grml-live-db is installed and enabled {{{
1648 dpkg_to_db() {
1649 if [ -d /usr/share/grml-live-db ] ; then
1650
1651   # safe defaults
1652   DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot:
1653   [ -n "$DPKG_DATABASE" ]  || DPKG_DATABASE=/var/log/grml-live.db
1654   [ -n "$DPKG_DBSCRIPT" ]  || DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
1655   [ -n "$DPKG_DBOPTIONS" ] || DPKG_DBOPTIONS="--database $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME --dpkg $DPKG_LIST"
1656
1657   if ! [ -x "$DPKG_DBSCRIPT" ] ; then
1658     log "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information."
1659     eerror "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information." ; eend 1
1660     bailout 14
1661   fi
1662
1663   # disable by default for now, not sure whether really everyone is using a local db file
1664   #if ! touch "$DPKG_DATABASE" ; then
1665   #  eerror "Error: can not write to ${DPKG_DATABASE}, can not log dpkg information." ; eend 1
1666   #  bailout 14
1667   #fi
1668
1669   if ! [ -r "$DPKG_LIST" ] ; then
1670      log   "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)"
1671      ewarn "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)" ; eend 0
1672   else
1673      einfo "Logging $DPKG_LIST to database $DPKG_DATABASE"
1674      log "Logging $DPKG_LIST to database $DPKG_DATABASE"
1675      log "Executing $DPKG_DBSCRIPT $DPKG_DBOPTIONS"
1676      eindent
1677
1678      if DB_INFO=$("$DPKG_DBSCRIPT" $DPKG_DBOPTIONS 2>&1) ; then
1679        einfo "$DB_INFO"
1680        eend 0
1681      else
1682        eerror "$DB_INFO"
1683        eend 1
1684      fi
1685
1686      eoutdent
1687   fi
1688
1689 fi
1690 }
1691 # }}}
1692
1693 # finalize {{{
1694 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
1695 log "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]"
1696
1697 dpkg_to_db # make sure we catch the last log line as well, therefore execute between log + einfo
1698
1699 einfo "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]" ; eend 0
1700 bailout 0
1701 # }}}
1702
1703 ## END OF FILE #################################################################
1704 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=2