a0333e28e5331e30a1805222d19e1c5587b7b457
[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 | egrep \
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   if [[ "$ARCH" == "amd64" ]] ; then
919     # important: this depends on execution of ${GRML_FAI_CONFIG}/config/scripts/GRMLBASE/45-grub-images
920     if ! [ -r "${CHROOT_OUTPUT}/${BOOTX64}" ] ; then
921       log    "Can not access GRUB efi image ${CHROOT_OUTPUT}/${BOOTX64}, required for Secure Boot support"
922       eerror "Can not access GRUB efi image ${CHROOT_OUTPUT}/${BOOTX64}, required for Secure Boot support" ; eend 1
923       log    "Possible reason is failure to run ${GRML_FAI_CONFIG}/config/scripts/GRMLBASE/45-grub-images"
924       ewarn  "Possible reason is failure to run ${GRML_FAI_CONFIG}/config/scripts/GRMLBASE/45-grub-images"
925       bailout 50
926     fi
927
928     dd if=/dev/zero of="${CHROOT_OUTPUT}/${EFI_IMG}" bs=4M count=1 2>/dev/null || bailout 50
929     mkfs.vfat -n GRML "${CHROOT_OUTPUT}/${EFI_IMG}" >/dev/null || bailout 51
930     mmd -i "${CHROOT_OUTPUT}/${EFI_IMG}" ::EFI || bailout 52
931     mmd -i "${CHROOT_OUTPUT}/${EFI_IMG}" ::EFI/BOOT || bailout 52
932
933     if [ "${SECURE_BOOT:-}" = "disable" ] ; then
934       log   "Secure Boot is disabled."
935       einfo "Secure Boot is disabled." ; eend 0
936
937       # install "$BOOTX64" as ::EFI/BOOT/bootx64.efi inside image file "$EFI_IMG":
938       mcopy -i "${CHROOT_OUTPUT}/${EFI_IMG}" "${CHROOT_OUTPUT}/${BOOTX64}" ::EFI/BOOT/bootx64.efi >/dev/null || bailout 53
939
940       log   "Generated 64-bit EFI image $BOOTX64"
941       einfo "Generated 64-bit EFI image $BOOTX64" ; eend 0
942     else
943       case "${SECURE_BOOT}" in
944         disable*)
945           log   "Secure Boot is disabled [mode: ${SECURE_BOOT}]"
946           einfo "Secure Boot is disabled [mode: ${SECURE_BOOT}]" ; eend 0
947           ;;
948         debian|ubuntu)
949           log   "Secure Boot is enabled [mode: ${SECURE_BOOT}]"
950           einfo "Secure Boot is enabled [mode: ${SECURE_BOOT}]" ; eend 0
951
952           local GRUBCFG_TEMPLATE="${TEMPLATE_DIRECTORY}/secureboot/grub.cfg"
953           local GRUBCFG_TMP=$(mktemp)
954
955           if ! [ -r "${GRUBCFG_TEMPLATE}" ] ; then
956             log    "Secure Boot template for GRUB [${GRUBCFG_TEMPLATE}] not found."
957             eerror "Secure Boot template for GRUB [${GRUBCFG_TEMPLATE}] not found." ; eend 1
958             bailout 54
959           fi
960
961           cp "${GRUBCFG_TEMPLATE}" "${GRUBCFG_TMP}"
962           adjust_boot_files "${GRUBCFG_TMP}"
963
964           mmd -i "${CHROOT_OUTPUT}/${EFI_IMG}" ::boot      || bailout 55
965           mmd -i "${CHROOT_OUTPUT}/${EFI_IMG}" ::boot/grub || bailout 55
966           mcopy -i "${CHROOT_OUTPUT}/${EFI_IMG}" "${GRUBCFG_TMP}" ::boot/grub/grub.cfg || bailout 56
967
968           rm "${GRUBCFG_TMP}"
969
970           if [ -r "${TEMPLATE_DIRECTORY}/EFI/${SECURE_BOOT}/BOOT/grubx64.efi.signed" ] ; then
971             mcopy -i "${CHROOT_OUTPUT}/${EFI_IMG}" "${TEMPLATE_DIRECTORY}/EFI/${SECURE_BOOT}/BOOT/grubx64.efi.signed" ::EFI/BOOT/grubx64.efi >/dev/null || bailout 57
972           else
973             log    "Secure Boot GRUB binary '${TEMPLATE_DIRECTORY}/EFI/${SECURE_BOOT}/BOOT/grubx64.efi.signed' not found."
974             eerror "Secure Boot GRUB binary '${TEMPLATE_DIRECTORY}/EFI/${SECURE_BOOT}/BOOT/grubx64.efi.signed' not found." ; eend 1
975             bailout 57
976           fi
977
978           if [ -r "${TEMPLATE_DIRECTORY}/EFI/${SECURE_BOOT}/BOOT/shimx64.efi.signed" ] ; then
979             mcopy -i "${CHROOT_OUTPUT}/${EFI_IMG}" "${TEMPLATE_DIRECTORY}/EFI/${SECURE_BOOT}/BOOT/shimx64.efi.signed" ::EFI/BOOT/bootx64.efi >/dev/null || bailout 58
980           else
981             log    "Secure Boot GRUB binary '${TEMPLATE_DIRECTORY}/EFI/${SECURE_BOOT}/BOOT/shimx64.efi.signed' not found."
982             eerror "Secure Boot GRUB binary '${TEMPLATE_DIRECTORY}/EFI/${SECURE_BOOT}/BOOT/shimx64.efi.signed' not found." ; eend 1
983             bailout 57
984           fi
985
986           log   "Generated 64-bit Secure Boot (${SECURE_BOOT}) EFI image ${CHROOT_OUTPUT}/${EFI_IMG}"
987           einfo "Generated 64-bit Secure Boot (${SECURE_BOOT}) EFI image ${CHROOT_OUTPUT}/${EFI_IMG}" ; eend 0
988           ;;
989         *)
990           log   "Secure Boot method '${SECURE_BOOT}' is unsupported."
991           eerror "Secure Boot method '${SECURE_BOOT}' is unsupported." ; eend 1
992           bailout 59
993           ;;
994       esac
995     fi
996   fi
997
998   if [[ "$ARCH" == "i386" ]] ; then
999     if ! [ -r "${CHROOT_OUTPUT}/${BOOTX32}" ] ; then
1000       log    "Can not access GRUB efi image ${CHROOT_OUTPUT}/${BOOTX32}."
1001       eerror "Can not access GRUB efi image ${CHROOT_OUTPUT}/${BOOTX32}." ; eend 1
1002       log    "Possible reason is failure to run ${GRML_FAI_CONFIG}/config/scripts/GRMLBASE/45-grub-images"
1003       ewarn "Possible reason is failure to run ${GRML_FAI_CONFIG}/config/scripts/GRMLBASE/45-grub-images"
1004       bailout 50
1005     fi
1006
1007     dd if=/dev/zero of="${CHROOT_OUTPUT}/${EFI_IMG}" bs=4M count=1 2>/dev/null || bailout 50
1008     mkfs.vfat -n GRML "${CHROOT_OUTPUT}/${EFI_IMG}" >/dev/null || bailout 51
1009     mmd -i "${CHROOT_OUTPUT}/${EFI_IMG}" ::EFI || bailout 52
1010     mmd -i "${CHROOT_OUTPUT}/${EFI_IMG}" ::EFI/BOOT || bailout 52
1011     mcopy -i "${CHROOT_OUTPUT}/${EFI_IMG}" "${CHROOT_OUTPUT}/${BOOTX32}" ::EFI/BOOT/bootia32.efi >/dev/null || bailout 53
1012     log   "Generated 32-bit EFI image $BOOTX32"
1013     einfo "Generated 32-bit EFI image $BOOTX32" ; eend 0
1014   fi
1015 }
1016 # }}}
1017
1018 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
1019 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
1020 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
1021
1022 # prepare ISO
1023 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
1024   if [ -n "$BOOTSTRAP_ONLY" ] ; then
1025     log   "Skipping stage 'boot' as building with bootstrap only."
1026     ewarn "Skipping stage 'boot' as building with bootstrap only." ; eend 0
1027   else
1028     # booting stuff:
1029     mkdir -p "$BUILD_OUTPUT"/boot/isolinux
1030     mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"
1031
1032     # this is a variable we're using for adjusting boot templates, not only in
1033     # adjust_boot_files though, so set here
1034     RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
1035
1036     # if we don't have an initrd we a) can't boot and b) there was an error
1037     # during build, so check for the file:
1038     INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
1039     if [ -n "$INITRD" ] ; then
1040       cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/initrd.img
1041       find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
1042     else
1043       log    "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
1044       eerror "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
1045       bailout 10
1046     fi
1047
1048     KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
1049     if [ -n "$KERNEL_IMAGE" ] ; then
1050       cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/vmlinuz
1051     else
1052       log    "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
1053       eerror "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
1054       bailout 11
1055     fi
1056
1057     # we need to set "$BOOTID" before we invoke adjust_boot_files for the
1058     # first time, being inside grub_setup below
1059     if [ -n "$NO_BOOTID" ] ; then
1060       log   'Skipping bootid feature as requested via $NO_BOOTID.'
1061       einfo 'Skipping bootid feature as requested via $NO_BOOTID.'
1062     else
1063       [ -n "$BOOTID" ] || BOOTID="$(echo ${GRML_NAME}${VERSION} | tr -d ',./;\- ')"
1064       mkdir -p "$BUILD_OUTPUT"/conf
1065       einfo "Generating /conf/bootid.txt with entry ${BOOTID}."
1066       log   "Generating /conf/bootid.txt with entry ${BOOTID}."
1067       echo "$BOOTID" > "$BUILD_OUTPUT"/conf/bootid.txt
1068       eend $?
1069     fi
1070
1071     # every recent Grml ISO ships a /conf/bootid.txt, though GRUB might find
1072     # the /conf/bootid.txt of a different (Grml) ISO than the one that's
1073     # supposed to be running, so within scripts/GRMLBASE/45-grub-images
1074     # we generate a random filename, stored inside /boot/grub/bootfile.txt,
1075     # which we place on the resulting ISO here
1076     if [ -r "${CHROOT_OUTPUT}"/boot/grub/bootfile.txt ] ; then
1077       mkdir -p "${BUILD_OUTPUT}"/conf
1078       rm -f "${BUILD_OUTPUT}"/conf/bootfile*  # ensure we don't leave any old(er) files behind
1079
1080       einfo "Generating "${BUILD_OUTPUT}"/conf/bootfile* files"
1081       log   "Generating "${BUILD_OUTPUT}"/conf/bootfile* files"
1082
1083       BOOT_FILE="/conf/bootfile_$(cat "${CHROOT_OUTPUT}"/boot/grub/bootfile.txt)"
1084       echo "# This file is relevant for GRUB boot with the Grml ISO." > "${BUILD_OUTPUT}/${BOOT_FILE}"
1085       # save information about the random filename inside /conf/bootfile.txt
1086       echo "${BOOT_FILE}" > "${BUILD_OUTPUT}"/conf/bootfile.txt
1087       eend $?
1088     fi
1089
1090     grub_setup
1091
1092     # EFI boot files
1093     if [ -r "${CHROOT_OUTPUT}/boot/efi.img" -a -r "${CHROOT_OUTPUT}/boot/bootx64.efi" ] ; then
1094       einfo "Copying 64-bit EFI boot files into ISO path."
1095       log   "Copying 64-bit EFI boot files into ISO path."
1096       RC=$0
1097       cp "${CHROOT_OUTPUT}/boot/efi.img" "${BUILD_OUTPUT}/boot/" || RC=$?
1098       mkdir -p "${BUILD_OUTPUT}/EFI/BOOT/" || RC=$?
1099       cp "${CHROOT_OUTPUT}/boot/bootx64.efi" "${BUILD_OUTPUT}/EFI/BOOT/bootx64.efi" || RC=$?
1100       eend $?
1101     elif [ -r "${CHROOT_OUTPUT}/boot/efi.img" -a -r "${CHROOT_OUTPUT}/boot/bootia32.efi" ] ; then
1102       einfo "Copying 32-bit EFI boot files into ISO path."
1103       log "Copying 32-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/bootia32.efi" "${BUILD_OUTPUT}/EFI/BOOT/bootia32.efi" || RC=$?
1108       eend $?
1109     else
1110       ewarn "No EFI boot files found, skipping." ; eend 0
1111     fi
1112
1113     [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
1114     if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
1115       log    "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
1116       eerror "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
1117       bailout 8
1118     fi
1119
1120     # copy _required_ isolinux files
1121     if [ -d "${CHROOT_OUTPUT}/usr/lib/ISOLINUX" ] ; then
1122       copy_addon_file isolinux.bin /usr/lib/ISOLINUX isolinux
1123       for file in ${CHROOT_OUTPUT}/usr/lib/syslinux/modules/bios/*.c32 ; do
1124         copy_addon_file "$(basename "$file")"  /usr/lib/syslinux/modules/bios/ isolinux
1125       done
1126     else # syslinux versions <= 3:4.05+dfsg-6+deb8u1
1127       copy_addon_file isolinux.bin /usr/lib/syslinux isolinux
1128       copy_addon_file ifcpu64.c32  /usr/lib/syslinux isolinux
1129       copy_addon_file vesamenu.c32 /usr/lib/syslinux isolinux
1130     fi
1131
1132     # *always* copy files to output directory so the variables
1133     # get adjusted according to the build.
1134     cp ${TEMPLATE_DIRECTORY}/boot/isolinux/*  "$BUILD_OUTPUT"/boot/isolinux/
1135
1136     mkdir -p "${BUILD_OUTPUT}/boot/grub"
1137     cp -a ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
1138
1139     if [ -n "$NO_ADDONS" ] ; then
1140       rm -f "$BUILD_OUTPUT"/boot/grub/addons.cfg
1141       log   "Skipping installation of boot addons as requested via \$NO_ADDONS."
1142       einfo "Skipping installation of boot addons as requested via \$NO_ADDONS."; eend 0
1143     else
1144       if ! [ -r "$TEMPLATE_DIRECTORY"/boot/addons ] ; then
1145         log   "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)"
1146         ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
1147       else
1148         log   "Installing boot addons."
1149         einfo "Installing boot addons."
1150
1151         # copy addons from system packages or grml-live-addons
1152         copy_addon_file ipxe.lkrn /usr/lib/ipxe addons
1153         copy_addon_file ipxe.efi /usr/lib/ipxe addons
1154         copy_addon_file pci.ids /usr/share/misc addons
1155         copy_addon_file memtest86+.bin /boot addons
1156
1157         # since syslinux(-common) v3:6.03~pre1+dfsg-4 the files are in a
1158         # different directory :(
1159         if [ -d "${CHROOT_OUTPUT}/usr/lib/syslinux/modules/bios/" ] ; then
1160           syslinux_modules_dir=/usr/lib/syslinux/modules/bios/
1161         else
1162           syslinux_modules_dir=/usr/lib/syslinux
1163         fi
1164         for file in chain.c32 hdt.c32 mboot.c32 menu.c32; do
1165           copy_addon_file "${file}" "${syslinux_modules_dir}" addons
1166         done
1167
1168         copy_addon_file memdisk /usr/lib/syslinux addons
1169
1170         eend 0
1171
1172         # make memtest filename FAT16/8.3 compatible
1173         mv "${BUILD_OUTPUT}/boot/addons/memtest86+.bin" \
1174           "${BUILD_OUTPUT}/boot/addons/memtest"
1175
1176         # copy only files so we can handle bsd4grml on its own
1177         for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
1178           test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
1179         done
1180
1181         if [ -n "$NO_ADDONS_BSD4GRML" ] ; then
1182           log   "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."
1183           einfo "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."; eend 0
1184         else
1185           if [ -d "$TEMPLATE_DIRECTORY"/boot/addons/bsd4grml ] ; then
1186             cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
1187           else
1188             log   "Missing addon file: bsd4grml"
1189             ewarn "Missing addon file: bsd4grml" ; eend 0
1190           fi
1191         fi
1192
1193       fi # no "$TEMPLATE_DIRECTORY"/boot/addons
1194     fi # NO_ADDONS
1195
1196     # generate loopback.cfg config file without depending on grub's regexp module
1197     # which isn't available in Debian/squeeze
1198     echo "## grub2 loopback configuration" > "${BUILD_OUTPUT}"/boot/grub/loopback.cfg
1199     echo "source /boot/grub/header.cfg" >> "${BUILD_OUTPUT}"/boot/grub/loopback.cfg
1200     for config in "${BUILD_OUTPUT}"/boot/grub/*_default.cfg "${BUILD_OUTPUT}"/boot/grub/*_options.cfg ; do
1201       [ -r "$config" ] || continue
1202       echo "source ${config##$BUILD_OUTPUT}" >> "${BUILD_OUTPUT}"/boot/grub/loopback.cfg
1203     done
1204     if [ -z "$NO_ADDONS" ] ; then
1205       echo "source /boot/grub/addons.cfg" >> "${BUILD_OUTPUT}"/boot/grub/loopback.cfg
1206     fi
1207     echo "source /boot/grub/footer.cfg" >> "${BUILD_OUTPUT}"/boot/grub/loopback.cfg
1208
1209     # copy grub files from target
1210     mkdir -p "${BUILD_OUTPUT}"/boot/grub/i386-pc/
1211     cp -a "${CHROOT_OUTPUT}"/usr/lib/grub/*-pc/*.mod "${BUILD_OUTPUT}"/boot/grub/i386-pc/
1212     cp -a "${CHROOT_OUTPUT}"/usr/lib/grub/*-pc/*.o "${BUILD_OUTPUT}"/boot/grub/i386-pc/
1213     cp -a "${CHROOT_OUTPUT}"/usr/lib/grub/*-pc/*.lst "${BUILD_OUTPUT}"/boot/grub/i386-pc/
1214     cp -a "${CHROOT_OUTPUT}"/usr/share/grub/ascii.pf2 "${BUILD_OUTPUT}"/boot/grub/
1215     cp -a "${CHROOT_OUTPUT}"/boot/grub/core.img "${BUILD_OUTPUT}"/boot/grub/
1216     cp -a "${CHROOT_OUTPUT}"/boot/grub/grub.img "${BUILD_OUTPUT}"/boot/grub/
1217
1218     # copy modules for UEFI grub, 64-bit
1219     mkdir -p "${BUILD_OUTPUT}"/boot/grub/x86_64-efi/
1220     cp -a "${CHROOT_OUTPUT}"/usr/lib/grub/x86_64-efi/*.{mod,lst} "${BUILD_OUTPUT}"/boot/grub/x86_64-efi/
1221
1222     # copy modules for UEFI grub, 32-bit
1223     mkdir -p "${BUILD_OUTPUT}"/boot/grub/i386-efi/
1224     cp -a "${CHROOT_OUTPUT}"/usr/lib/grub/i386-efi/*.{mod,lst} "${BUILD_OUTPUT}"/boot/grub/i386-efi/
1225
1226     if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
1227       log    "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
1228       eerror "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
1229       bailout 9
1230     fi
1231
1232     mkdir -p "$BUILD_OUTPUT"/GRML/"${GRML_NAME}"/
1233     cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/"${GRML_NAME}"/
1234
1235     if [ -r "$BUILD_OUTPUT"/GRML/"${GRML_NAME}"/grml-version ] ; then
1236       sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/" "$BUILD_OUTPUT"/GRML/"${GRML_NAME}"/grml-version
1237       sed -i "s/%DATE%/$DATE/"                 "$BUILD_OUTPUT"/GRML/"${GRML_NAME}"/grml-version
1238     fi
1239
1240     # make sure the squashfs filename is set accordingly:
1241     SQUASHFS_NAME="$GRML_NAME.squashfs"
1242     # adjust bootsplash accordingly but make sure the string has the according length
1243     fixed_squashfs_name="$(cut_string 20 "$SQUASHFS_NAME")"
1244     fixed_squashfs_name="$(extend_string_end 20 "$fixed_squashfs_name")"
1245     for file in f4 f5 ; do
1246       if [ -r "${BUILD_OUTPUT}/boot/isolinux/${file}" ] ; then
1247         sed -i "s/%SQUASHFS_NAME%/${fixed_squashfs_name}/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
1248         sed -i "s/%SQUASHFS_NAME%/${fixed_squashfs_name}/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
1249       fi
1250     done
1251
1252     # adjust all variables in the templates with the according distribution information
1253     adjust_boot_files "${BUILD_OUTPUT}"/boot/isolinux/*.cfg \
1254       "${BUILD_OUTPUT}"/boot/isolinux/*.msg \
1255       "${BUILD_OUTPUT}"/boot/grub/*
1256
1257     for param in ARCH DATE DISTRI_INFO DISTRI_NAME DISTRI_SPLASH GRML_NAME SQUASHFS_NAME \
1258       RELEASE_INFO SHORT_NAME VERSION ; do
1259       for file in $(find "${BUILD_OUTPUT}" -name "*%$param%*") ; do
1260         value="$(eval echo '$'"$param")"
1261         mv ${file} ${file/\%${param}\%/$value}
1262       done
1263     done
1264
1265     # generate addon list
1266     rm -f "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
1267     for name in "${BUILD_OUTPUT}"/boot/isolinux/addon_*.cfg ; do
1268       include_name=$(basename "$name")
1269       echo "include $include_name"  >> "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
1270     done
1271
1272     if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
1273       log "including grmlmain.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1274       echo "include grmlmain.cfg"    >  "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1275       echo "include default.cfg"     >  "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1276       echo "include menuoptions.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1277       echo "include grml.cfg"        >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1278
1279       for f in "${BUILD_OUTPUT}"/boot/isolinux/submenu*.cfg ; do
1280         echo "include $(basename $f)"     >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1281       done
1282
1283       echo "include options.cfg"     >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1284       if [ -z "$NO_ADDONS" ] ; then
1285         echo "include addons.cfg"    >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1286       fi
1287       echo "include isoprompt.cfg"   >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1288       echo "include hd.cfg"          >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1289       echo "include hidden.cfg"      >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
1290     else # assume we are building a custom distribution:
1291       log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
1292       einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
1293       if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
1294         log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
1295         eindent
1296         einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
1297         eoutdent
1298         eend $?
1299       else
1300         log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1301         echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1302         if [ -z "$NO_ADDONS" ] ; then
1303           echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1304         fi
1305       fi
1306     fi
1307
1308     # use old style console based isolinux method only if requested:
1309     if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
1310       log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
1311       einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
1312       if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
1313         einfo "include for console.cfg already found, nothing to do."
1314         eend 0
1315       else
1316         log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1317         einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1318         echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1319         eend $?
1320       fi
1321     else
1322       log 'Using graphical boot menu.'
1323       if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
1324         log "include for vesamenu.cfg already found, nothing to do."
1325       else
1326         log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1327         echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1328       fi
1329     fi
1330
1331     if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
1332       sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
1333     fi
1334
1335     DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot
1336     if ! [ -r "$DPKG_LIST" ] ; then
1337       ewarn "$DPKG_LIST could not be read, ignoring to store package information on ISO therefore."
1338     else
1339       einfo "Storing package list information as /GRML/${GRML_NAME}/packages.txt on ISO."
1340       cp "$DPKG_LIST" "${BUILD_OUTPUT}"/GRML/"${GRML_NAME}"/packages.txt
1341       eend $?
1342     fi
1343
1344     # autostart for Windows:
1345     if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
1346       cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
1347     fi
1348
1349     FORCE_ISO_REBUILD=true
1350     einfo "Finished execution of stage 'boot'" ; eend 0
1351   fi # BOOTSTRAP_ONLY
1352 else
1353   log    'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
1354   eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
1355   bailout
1356 fi
1357
1358 # support installation of local files into the chroot/ISO
1359 if [ -n "$CHROOT_INSTALL" ] ; then
1360   if ! [ -d "$CHROOT_INSTALL" ] ; then
1361      log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1362      ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1363   else
1364      log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1365      einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1366      rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
1367      eend $?
1368      einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
1369      FORCE_ISO_REBUILD=true
1370   fi
1371 fi
1372
1373 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
1374    log   "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
1375    ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
1376 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
1377    log   "Skipping stage 'squashfs' as requested via option -q or -N"
1378    ewarn "Skipping stage 'squashfs' as requested via option -q or -N" ; eend 0
1379 else
1380    mkdir -p "$BUILD_OUTPUT"/live/"${GRML_NAME}"/
1381    # make sure we don't leave (even an empty) base.tgz:
1382    [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
1383
1384    if which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
1385       log    "Using mksquashfs binary ${SQUASHFS_BINARY}"
1386       einfo  "Using mksquashfs binary ${SQUASHFS_BINARY}" ; eend 0
1387    else
1388       log    "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
1389       eerror "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
1390       bailout
1391    fi
1392
1393    # use sane defaults if $SQUASHFS_OPTIONS isn't set
1394    if [ -z "$SQUASHFS_OPTIONS" ] ; then
1395      # use block size 1m as this gives good result with regards to time + compression
1396      SQUASHFS_OPTIONS="-b 1m"
1397
1398      # set lzma/xz compression by default, unless -z option has been specified on command line
1399      if [ -z "$SQUASHFS_ZLIB" ] ; then
1400         SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp xz"
1401      else
1402         SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp gzip"
1403      fi
1404    fi
1405
1406    # support exclusion of files via exclude-file:
1407    if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
1408       SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE -wildcards"
1409    fi
1410
1411    # get rid of unnecessary files when building grml-small for final release:
1412    if echo "$CLASSES" | grep -q GRML_SMALL ; then
1413       SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
1414    fi
1415
1416    # log stuff
1417    SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
1418
1419    # informational stuff
1420    [ -n "$SQUASHFS_OPTIONS" ]  && SQUASHFS_INFO_MSG="$SQUASHFS_OPTIONS"
1421    [ -n "$SQUASHFS_INFO_MSG" ] && SQUASHFS_INFO_MSG="using options: $SQUASHFS_INFO_MSG"
1422    einfo "Squashfs build information: running binary $SQUASHFS_BINARY $SQUASHFS_INFO_MSG"
1423
1424    log "$SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/${GRML_NAME}/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS"
1425
1426    if $SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/"${GRML_NAME}"/"${GRML_NAME}".squashfs \
1427       -noappend $SQUASHFS_OPTIONS 2>"${SQUASHFS_STDERR}" ; then
1428       echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/"${GRML_NAME}"/filesystem.module
1429       log "Finished execution of stage 'squashfs' [$(date)]"
1430       einfo "Finished execution of stage 'squashfs'" ; eend 0
1431    else
1432       log    "Error: there was a critical error executing stage 'squashfs' [$(date)]:"
1433       log    "$(cat $SQUASHFS_STDERR)"
1434       eerror "Error: there was a critical error executing stage 'squashfs':"
1435       cat    "${SQUASHFS_STDERR}"
1436       eend 1
1437       bailout
1438    fi
1439
1440    FORCE_ISO_REBUILD=true
1441 fi
1442
1443 # create md5sum file:
1444 if [ -z "$BOOTSTRAP_ONLY" ] ; then
1445   ( cd $BUILD_OUTPUT/GRML/"${GRML_NAME}" &&
1446   find ../.. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
1447 fi
1448 # }}}
1449
1450 # information how the ISO was generated {{{
1451 # shellcheck disable=SC2034
1452 generate_build_info() {
1453   jo -p \
1454     boot_method="${BOOT_METHOD}" \
1455     bootstrap_only="${BOOTSTRAP_ONLY}" \
1456     build_date="${DATE}" \
1457     build_dirty="${BUILD_DIRTY}" \
1458     build_only="${BUILD_ONLY}" \
1459     chroot_install="${CHROOT_INSTALL}" \
1460     classes="${CLASSES}" \
1461     clean_artifacts="${CLEAN_ARTIFACTS}" \
1462     default_bootoptions="${DEFAULT_BOOTOPTIONS}" \
1463     distri_info="${DISTRI_INFO}" \
1464     distri_name="${DISTRI_NAME}" \
1465     extract_iso_name="${EXTRACT_ISO_NAME}" \
1466     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}" \
1467     fai_version="$(fai --help 2>/dev/null | head -1 | awk '{print $2}' | sed 's/\.$//' || true)" \
1468     grml_architecture="${ARCH}" \
1469     grml_bootid="${BOOTID}" \
1470     grml_build_output="${BUILD_OUTPUT}" \
1471     grml_chroot_output="${CHROOT_OUTPUT}" \
1472     grml_debian_version="${SUITE}" \
1473     grml_iso_name="${ISO_NAME}" \
1474     grml_iso_output="${ISO_OUTPUT}" \
1475     grml_live_cmdline="${CMDLINE}" \
1476     grml_live_config_file="${LIVE_CONF}" \
1477     grml_live_scripts_directory="${SCRIPTS_DIRECTORY}" \
1478     grml_live_template_directory="${TEMPLATE_DIRECTORY}" \
1479     grml_live_version="${GRML_LIVE_VERSION}" \
1480     grml_local_config="${LOCAL_CONFIG}" \
1481     grml_name="${GRML_NAME}" \
1482     grml_short_name="${SHORT_NAME}" \
1483     grml_username="${USERNAME}" \
1484     grml_version="${VERSION}" \
1485     host_architecture="$(dpkg --print-architecture || true)" \
1486     host_debian_version="$(cat /etc/debian_version 2>/dev/null || true)" \
1487     host_kernel_version="$(uname -a)" \
1488     hybrid_method="${HYBRID_METHOD}" \
1489     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}" \
1490     mkisofs_version="$(${MKISOFS} --version 2>/dev/null | head -1 || true)" \
1491     mksquashfs_cmdline="${SQUASHFS_BINARY} ${CHROOT_OUTPUT}/ ${BUILD_OUTPUT}/live/${GRML_NAME}/${GRML_NAME}.squashfs -noappend ${SQUASHFS_OPTIONS}" \
1492     mksquashfs_version="$(${SQUASHFS_BINARY} -version | head -1 || true)" \
1493     output_owner="${CHOWN_USER}" \
1494     release_info="${RELEASE_INFO}" \
1495     release_name="${RELEASENAME}" \
1496     secure_boot="${SECURE_BOOT}" \
1497     skip_mkisofs="${SKIP_MKISOFS}" \
1498     skip_mksquashfs_="${SKIP_MKSQUASHFS}" \
1499     skip_netboot="${SKIP_NETBOOT}" \
1500     squashfs_name="${SQUASHFS_NAME}" \
1501     template_directory="${TEMPLATE_DIRECTORY}" \
1502     timestamp="$(TZ=UTC date +%s)" \
1503     update_only="${UPDATE}" \
1504     wayback_date="${WAYBACK_DATE}" \
1505   --
1506 }
1507 # }}}
1508
1509 # ISO_OUTPUT - mkisofs {{{
1510 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
1511 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
1512
1513 if [ "$BOOT_METHOD" = "isolinux" ] ; then
1514    BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
1515    if [ "$HYBRID_METHOD" = "isohybrid" ] ; then
1516      EFI_ARGS="-isohybrid-mbr /usr/lib/ISOLINUX/isohdpfx.bin -eltorito-alt-boot -e boot/efi.img -no-emul-boot -isohybrid-gpt-basdat"
1517    fi
1518 elif [ "$BOOT_METHOD" = "grub2" ] ; then
1519    BOOT_ARGS="-no-emul-boot -boot-load-size 4 -b boot/grub/toriboot.bin"
1520 fi
1521
1522 # Work around http://bts.grml.org/grml/issue945
1523 if [[ $BOOT_METHOD != isolinux && ($HYBRID_METHOD = isohybrid || $HYBRID_METHOD = manifold) ]]; then
1524   log   "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1525   ewarn "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1526   HYBRID_METHOD='grub2'
1527   eend 0
1528 fi
1529
1530 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ]  ; then
1531    log   "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already."
1532    ewarn "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already." ; eend 0
1533 elif [ -n "$SKIP_MKISOFS" ] ; then
1534    log   "Skipping stage 'iso build' as requested via option -n or -N"
1535    ewarn "Skipping stage 'iso build' as requested via option -n or -N" ; eend 0
1536 else
1537    mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
1538
1539    if $FORCE_ISO_REBUILD && ! [ -f "${ISO_OUTPUT}/${ISO_NAME}" ] ; then
1540       log   "Forcing rebuild of ISO because files on ISO have been modified."
1541       einfo "Forcing rebuild of ISO because files on ISO have been modified."
1542    fi
1543
1544    # support xorriso as well mkisofs and genisoimage
1545    if which xorriso >/dev/null 2>&1 ; then
1546       MKISOFS='xorriso -as mkisofs'
1547     elif which mkisofs >/dev/null 2>&1; then
1548       MKISOFS='mkisofs'
1549    elif which genisoimage >/dev/null 2>&1; then
1550       MKISOFS='genisoimage'
1551    else
1552       log    "Error: neither xorriso nor mkisofs nor genisoimage available - can not create ISO."
1553       eerror "Error: neither xorriso nor mkisofs nor genisoimage available - can not create ISO." ; eend 1
1554       bailout
1555    fi
1556
1557    einfo "Using ${MKISOFS} to build ISO." ;  eend 0
1558    case "${ARCH}-${MKISOFS}" in
1559      # using -eltorito-alt-boot is limited to xorriso for now
1560      amd64-xorriso*)
1561        eindent
1562
1563        if ! dpkg --compare-versions $(dpkg-query -W -f='${Version}\n' xorriso 2>/dev/null) gt-nl 1.1.6-1 ; then
1564          log   "Disabling (U)EFI boot support because xorriso version is too old."
1565          ewarn "Disabling (U)EFI boot support because xorriso version is too old." ; eend 0
1566        else
1567          if [ -r "${BUILD_OUTPUT}"/boot/efi.img ] ; then
1568            einfo "Enabling (U)EFI boot."
1569            log   "Enabling (U)EFI boot."
1570            BOOT_ARGS="$BOOT_ARGS -boot-info-table -eltorito-alt-boot -e boot/efi.img -no-emul-boot"
1571            eend $?
1572          else
1573            log   "Disabling (U)EFI boot support because /boot/efi.img is missing."
1574            ewarn "Disabling (U)EFI boot support because /boot/efi.img is missing." ; eend 0
1575          fi
1576        fi
1577
1578        eoutdent
1579        ;;
1580    esac
1581
1582    CURRENT_DIR=$(pwd)
1583    if cd "$BUILD_OUTPUT" ; then
1584       if [ "$BOOT_METHOD" = "grub2" ]; then
1585          # make a 2048-byte bootsector for El Torito
1586          dd if=/dev/zero of=boot/grub/toriboot.bin bs=512 count=4 2>/dev/null
1587          # those are in 2048-byte sectors, so 1 16 matches 4 63 below
1588          echo 1 16 | mksh "${SCRIPTS_DIRECTORY}/bootgrub.mksh" -B 11 | \
1589             dd of=boot/grub/toriboot.bin conv=notrunc 2>/dev/null
1590       fi
1591
1592       log   "Generating build information in conf/buildinfo.json"
1593       einfo "Generating build information in conf/buildinfo.json"
1594       mkdir -p conf/
1595       generate_build_info > conf/buildinfo.json
1596       eend $?
1597
1598       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} ."
1599       einfo "Generating ISO file..."
1600       $MKISOFS -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
1601               -l -r -J $BOOT_ARGS $EFI_ARGS -no-pad \
1602               -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
1603       eend $RC
1604
1605       # do not continue on errors, otherwise we might generate/overwrite the ISO with dd if=... stuff
1606       if [ "$RC" != 0 ] ; then
1607         log    "Error: critical error while generating ISO [exit code ${RC}]. Exiting."
1608         eerror "Error: critical error while generating ISO [exit code ${RC}]. Exiting." ; eend 1
1609         bailout $RC
1610       fi
1611
1612       # both of these need core.img there, so it’s easier to write it here
1613       if [ "$BOOT_METHOD" = "grub2" ] || [ "$HYBRID_METHOD" = "grub2" ]; then
1614          # must be <= 30720 bytes
1615          dd if=boot/grub/core.img of="${ISO_OUTPUT}/${ISO_NAME}" \
1616            conv=notrunc bs=512 seek=4 2>/dev/null
1617       fi
1618
1619       # pad the output ISO to multiples of 256 KiB for partition table support
1620       siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
1621       cyls=$((siz / 512 / 32 / 16 + 1))   # C=$cyls H=16 S=32
1622       siz=$((cyls * 16 * 32 * 512))   # size after padding
1623       dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
1624          of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
1625
1626       # support disabling hybrid ISO image
1627       if [ "$HYBRID_METHOD" = "disable" ] ; then
1628         log   "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1629         einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1630         eend 0
1631       elif [ "$HYBRID_METHOD" = "manifold" ] || [ "$HYBRID_METHOD" = "grub2" ] ; then
1632         # isoinfo is part of both mkisofs and genisoimage so we're good
1633         bootoff=$(isoinfo -l -i "${ISO_OUTPUT}/${ISO_NAME}" | \
1634           sed -n '/^.*\[ *\([0-9]*\)[] ].* ISOLINUX.BIN[;1]* *$/s//\1/p')
1635
1636         if ! [ -r boot/grub/core.img ] ; then
1637           log   "boot/grub/core.img not found, not creating manifold boot ISO file"
1638           ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
1639         elif [ "${bootoff:-0}" -lt 1 ] ; then
1640           log   "isolinux.bin not found on the ISO file, disabling manifold boot"
1641           ewarn "isolinux.bin not found on the ISO file, disabling manifold boot"
1642         else
1643           if [ "$HYBRID_METHOD" = "grub2" ] ; then
1644             log   "Creating hybrid ISO file with manifold/grub2 method"
1645             einfo "Creating hybrid ISO file with manifold/grub2 method"
1646             # 512 bytes: MBR, partition table, load GRUB 2
1647             echo 4 63 | mksh "${SCRIPTS_DIRECTORY}/bootgrub.mksh" -A -M 4:0x96 -g $cyls:16:32
1648           else
1649             log   "Creating hybrid ISO file with manifold method"
1650             einfo "Creating hybrid ISO file with manifold method"
1651             # read only one but 2048-byte sized (scale: << 2) sector
1652             echo $bootoff $bootoff | \
1653               mksh ${SCRIPTS_DIRECTORY}/bootilnx.mksh -A -M 4:0x96 -g $cyls:16:32 -S 2
1654           fi | dd of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
1655           eend $?
1656         fi
1657       elif [ "$HYBRID_METHOD" = "isohybrid" ] ; then
1658         : # nothing to do, handled via $MKISOFS $EFI_ARGS already
1659       else
1660         bailout 12 "Unknown HYBRID_METHOD [${HYBRID_METHOD}]. Supported values: disable, isohybrid, grub2, manifold"
1661       fi
1662
1663       # generate ISO checksums if we are using class 'RELEASE':
1664       case $CLASSES in *RELEASE*)
1665          [ "$RC" = 0 ] && \
1666          (
1667            if cd $ISO_OUTPUT ; then
1668              sha256sum ${ISO_NAME} > ${ISO_NAME}.sha256 && \
1669              touch -r ${ISO_NAME} ${ISO_NAME}.sha256
1670            fi
1671          )
1672          ;;
1673       esac
1674
1675       cd "$CURRENT_DIR"
1676    fi
1677
1678    if [ "$RC" = 0 ] ; then
1679       log   "Finished execution of stage 'iso build' [$(date)]"
1680       einfo "Finished execution of stage 'iso build'" ; eend 0
1681    else
1682       log    "Error: there was a critical error ($RC) executing stage 'iso build' [$(date)]"
1683       eerror "Error: there was a critical error executing stage 'iso build'" ; eend 1
1684       bailout $RC
1685    fi
1686 fi
1687 # }}}
1688
1689 # netboot package {{{
1690 create_netbootpackage() {
1691   local OUTPUT_FILE="${NETBOOT}/grml_netboot_package_${GRML_NAME}_${VERSION}.tar"
1692
1693   if [ -f "${OUTPUT_FILE}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
1694     log   "Skipping stage 'netboot' as $OUTPUT_FILE exists already."
1695     ewarn "Skipping stage 'netboot' as $OUTPUT_FILE exists already." ; eend 0
1696     return 0
1697   elif [ -n "$SKIP_NETBOOT" ] ; then
1698     log   "Skipping stage 'netboot' as requested via option -Q"
1699     ewarn "Skipping stage 'netboot' as requested via option -Q" ; eend 0
1700     return 0
1701   fi
1702
1703   mkdir -p "$NETBOOT"
1704
1705   # since syslinux v3:6.03~pre1+dfsg-4 the pxelinux.0 has been split into a
1706   # separate pxelinux package
1707   if [ -d "${CHROOT_OUTPUT}/usr/lib/PXELINUX/" ] ; then
1708     local pxelinux_dir=/usr/lib/PXELINUX
1709   else
1710     local pxelinux_dir=/usr/lib/syslinux
1711   fi
1712
1713   if ! [ -r "${CHROOT_OUTPUT}/${pxelinux_dir}/pxelinux.0" ] ; then
1714     ewarn "File ${pxelinux_dir}/pxelinux.0 not found in build chroot." ; eend 0
1715     eindent
1716     einfo "Install syslinux[-common]/pxelinux package in chroot to get a netboot package."
1717     eoutdent
1718     return 0
1719   fi
1720
1721   local OUTPUTDIR="${NETBOOT}/build_tmp"
1722   local WORKING_DIR="${OUTPUTDIR}/grml_netboot_package_${GRML_NAME}_${VERSION}/tftpboot/"
1723
1724   mkdir -p "$WORKING_DIR"
1725
1726   cp "${CHROOT_OUTPUT}"/boot/vmlinuz-*    "$WORKING_DIR"/vmlinuz
1727   cp "${CHROOT_OUTPUT}"/boot/initrd.img-* "$WORKING_DIR"/initrd.img
1728   cp "${CHROOT_OUTPUT}/${pxelinux_dir}/pxelinux.0" "${WORKING_DIR}/pxelinux.0"
1729
1730   if [ -r "${CHROOT_OUTPUT}"/usr/lib/syslinux/modules/bios/ldlinux.c32 ] ; then
1731     cp "${CHROOT_OUTPUT}"/usr/lib/syslinux/modules/bios/ldlinux.c32 "${WORKING_DIR}"/
1732   fi
1733
1734   mkdir -p "${WORKING_DIR}/pxelinux.cfg"
1735   if [ -r "${BUILD_OUTPUT}/boot/isolinux/netboot.cfg" ] ; then
1736     cp "${BUILD_OUTPUT}/boot/isolinux/netboot.cfg" "${WORKING_DIR}/pxelinux.cfg/default"
1737   else
1738     log   "File ${BUILD_OUTPUT}/boot/isolinux/netboot.cfg not found."
1739     ewarn "File ${BUILD_OUTPUT}/boot/isolinux/netboot.cfg not found."
1740     eindent
1741     log   "Hint: Are you using custom templates which do not provide netboot.cfg?"
1742     ewarn "Hint: Are you using custom templates which do not provide netboot.cfg?" ; eend 0
1743     eoutdent
1744   fi
1745
1746   # don't include shim + grubnetx64 + grub files in i386 netboot packages,
1747   # as those don't make much sense there
1748   if [ "$ARCH" = amd64 ] ; then
1749     if ! [ -r "${BUILD_OUTPUT}/boot/grub/netboot.cfg" ] ; then
1750       log   "File ${BUILD_OUTPUT}/boot/grub/netboot.cfg not found."
1751       ewarn "File ${BUILD_OUTPUT}/boot/grub/netboot.cfg not found."
1752       eindent
1753       log   "Hint: Are you using custom templates which do not provide grub.cfg?"
1754       ewarn "Hint: Are you using custom templates which do not provide grub.cfg?" ; eend 0
1755       eoutdent
1756     else
1757       cp "${BUILD_OUTPUT}/boot/grub/netboot.cfg" "${WORKING_DIR}/grub.cfg"
1758       adjust_boot_files "${WORKING_DIR}/grub.cfg"
1759
1760       if [ -r "${CHROOT_OUTPUT}"/usr/lib/shim/shimx64.efi.signed ] ; then
1761         log "Installing ${CHROOT_OUTPUT}/usr/lib/shim/shimx64.efi.signed as shim.efi in netboot package"
1762         cp "${CHROOT_OUTPUT}"/usr/lib/shim/shimx64.efi.signed "${WORKING_DIR}"/shim.efi
1763       elif [ -r "${CHROOT_OUTPUT}"/usr/lib/shim/shimx64.efi ] ; then
1764         log "Installing ${CHROOT_OUTPUT}/usr/lib/shim/shimx64.efi as shim.efi in netboot package"
1765         cp "${CHROOT_OUTPUT}"/usr/lib/shim/shimx64.efi "${WORKING_DIR}"/shim.efi
1766       else
1767         log   "No shimx64.efi for usage with PXE boot found (shim-signed not present?)"
1768         ewarn "No shimx64.efi for usage with PXE boot found (shim-signed not present?)" ; eend 0
1769       fi
1770
1771       if [ -r "${CHROOT_OUTPUT}"/usr/lib/grub/x86_64-efi-signed/grubnetx64.efi.signed ] ; then
1772         log "Installing /usr/lib/grub/x86_64-efi-signed/grubnetx64.efi.signed as grubx64.efi in netboot package"
1773         cp "${CHROOT_OUTPUT}"/usr/lib/grub/x86_64-efi-signed/grubnetx64.efi.signed "${WORKING_DIR}"/grubx64.efi
1774       elif [ -r "${CHROOT_OUTPUT}"/usr/lib/grub/x86_64-efi/monolithic/grubnetx64.efi ] ; then
1775         log "Installing /usr/lib/grub/x86_64-efi/monolithic/grubnetx64.efi as grubx64.efi in netboot package"
1776         cp "${CHROOT_OUTPUT}"/usr/lib/grub/x86_64-efi/monolithic/grubnetx64.efi "${WORKING_DIR}"/grubx64.efi
1777       else
1778         log   "No grubnetx64.efi for usage with PXE boot found (grub-efi-amd64-signed not present?)"
1779         ewarn "No grubnetx64.efi for usage with PXE boot found (grub-efi-amd64-signed not present?)." ; eend 0
1780       fi
1781
1782       if [ -r "${CHROOT_OUTPUT}"/usr/share/grub/unicode.pf2 ] ; then
1783         log "Installing ${CHROOT_OUTPUT}/usr/share/grub/unicode.pf2 as grub/fonts/unicode.pf2 in netboot package"
1784         mkdir -p "${WORKING_DIR}"/grub/fonts/
1785         cp "${CHROOT_OUTPUT}"/usr/share/grub/unicode.pf2 "${WORKING_DIR}"/grub/fonts/
1786       else
1787         log   "No unicode.pf2 for usage with PXE boot found (grub-common not present?)"
1788         ewarn "No unicode.pf2 for usage with PXE boot found (grub-common not present?)" ; eend 0
1789       fi
1790     fi
1791   fi
1792
1793   if tar -C "$OUTPUTDIR" -cf "${OUTPUT_FILE}" "grml_netboot_package_${GRML_NAME}_${VERSION}" ; then
1794     (
1795       cd $(dirname "${OUTPUT_FILE}")
1796       sha256sum $(basename "${OUTPUT_FILE}") > "${OUTPUT_FILE}.sha256"
1797     )
1798     einfo "Generated netboot package ${OUTPUT_FILE}" ; eend 0
1799     rm -rf "${OUTPUTDIR}"
1800   else
1801     rm -rf "${OUTPUTDIR}"
1802     eerror "Could not generate netboot package ${OUTPUT_FILE}" ; eend 1
1803     bailout 21
1804   fi
1805 }
1806
1807 create_netbootpackage
1808 # }}}
1809
1810 # log build information to database if grml-live-db is installed and enabled {{{
1811 dpkg_to_db() {
1812 if [ -d /usr/share/grml-live-db ] ; then
1813
1814   # safe defaults
1815   DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot:
1816   [ -n "$DPKG_DATABASE" ]  || DPKG_DATABASE=/var/log/grml-live.db
1817   [ -n "$DPKG_DBSCRIPT" ]  || DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
1818   [ -n "$DPKG_DBOPTIONS" ] || DPKG_DBOPTIONS="--database $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME --dpkg $DPKG_LIST"
1819
1820   if ! [ -x "$DPKG_DBSCRIPT" ] ; then
1821     log "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information."
1822     eerror "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information." ; eend 1
1823     bailout 14
1824   fi
1825
1826   # disable by default for now, not sure whether really everyone is using a local db file
1827   #if ! touch "$DPKG_DATABASE" ; then
1828   #  eerror "Error: can not write to ${DPKG_DATABASE}, can not log dpkg information." ; eend 1
1829   #  bailout 14
1830   #fi
1831
1832   if ! [ -r "$DPKG_LIST" ] ; then
1833      log   "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)"
1834      ewarn "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)" ; eend 0
1835   else
1836      einfo "Logging $DPKG_LIST to database $DPKG_DATABASE"
1837      log "Logging $DPKG_LIST to database $DPKG_DATABASE"
1838      log "Executing $DPKG_DBSCRIPT $DPKG_DBOPTIONS"
1839      eindent
1840
1841      if DB_INFO=$("$DPKG_DBSCRIPT" $DPKG_DBOPTIONS 2>&1) ; then
1842        einfo "$DB_INFO"
1843        eend 0
1844      else
1845        eerror "$DB_INFO"
1846        eend 1
1847      fi
1848
1849      eoutdent
1850   fi
1851
1852 fi
1853 }
1854 # }}}
1855
1856 # finalize {{{
1857 if [ -n "${start_seconds}" ] ; then
1858   end_seconds="$(date +%s)"
1859   SECONDS="$(( end_seconds - start_seconds ))"
1860 fi
1861 log "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]"
1862
1863 dpkg_to_db # make sure we catch the last log line as well, therefore execute between log + einfo
1864
1865 einfo "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]" ; eend 0
1866 bailout 0
1867 # }}}
1868
1869 ## END OF FILE #################################################################
1870 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=2