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