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