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