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