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