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