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