Add basic grml theme to grub
[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 # define function getfilesize before "set -e"
16 if stat --help >/dev/null 2>&1; then
17   getfilesize='stat -c %s'  # GNU stat
18 else
19   getfilesize='stat -f %z'  # BSD stat
20 fi
21
22 # exit on any error:
23 # disable for now since it seems to cause some problems
24 # set -e
25
26 # The line following this line is patched by debian/rules.
27 GRML_LIVE_VERSION='***UNRELEASED***'
28
29 # global variables
30 PN="$(basename $0)"
31 CMDLINE="$0 $@"
32 ADDONS_LIST_FILE='/boot/isolinux/addons_list.cfg'
33 # }}}
34
35 # usage information {{{
36 usage()
37 {
38   echo "
39 $PN - build process script for generating a (grml based) Linux Live-ISO
40
41 Usage: $PN [options, see as follows]
42
43    -a <architecture>       architecture; available values: i386 and amd64
44    -A                      clean build directories before and after running
45    -b                      build the ISO without updating the chroot via FAI
46    -B                      build the ISO without touching the chroot (skips cleanup)
47    -c <classe[s]>          classes to be used for building the ISO via FAI
48    -C <configfile>         configuration file for grml-live
49    -d <date>               use specified date instead of build time as date of release
50    -D <configdir>          use specified configuration directory instead of /etc/grml/fai
51    -e <iso_name>           extract ISO and squashfs contents from iso_name
52    -F                      force execution without prompting
53    -g <grml_name>          set the grml flavour name
54    -h                      display short usage information and exit
55    -i <iso_name>           name of ISO
56    -I <src_directory>      directory which provides files that should become
57                            part of the chroot/ISO
58    -n                      skip generation of ISO
59    -N                      bootstrap (build chroot) only, do not create files for ISO
60    -o <output_directory>   main output directory of the build process
61    -q                      skip mksquashfs
62    -Q                      skip netboot package build
63    -r <release_name>       release name
64    -s <suite>              Debian suite; values: etch, lenny, squeeze, sid
65    -t <template_directory> place of the templates
66    -u                      update existing chroot instead of rebuilding it from scratch
67    -U <username>           arrange output to be owned by specified username
68    -v <version_number>     specify version number of the release
69    -V                      increase verbosity in the build process
70    -z                      use ZLIB instead of LZMA/XZ compression
71
72 Usage examples:
73
74     $PN
75     $PN -c GRMLBASE,GRML_FULL,AMD64 -o /dev/shm/grml
76     $PN -c GRMLBASE,GRML_FULL,AMD64 -i grml_0.0-1.iso -v 0.0-1
77     $PN -c GRMLBASE,GRML_FULL,AMD64 -s sid -V -r 'grml-live rocks'
78
79 More details: man grml-live + /usr/share/doc/grml-live/grml-live.html
80               http://grml.org/grml-live/
81
82 Please send your bug reports and feedback to the grml-team: http://grml.org/bugs/
83 "
84 }
85
86 # make sure it's possible to get usage information without being
87 # root or actually executing the script
88 if [ "$1" = '-h' -o "$1" = '--help' ] ; then
89    usage
90    [ "$(id -u 2>/dev/null)" != 0 ] && echo "Please notice that this script requires root permissions."
91    exit 0
92 fi
93 # }}}
94
95 # some runtime checks {{{
96 # we need root permissions for the build-process:
97 if [ "$(id -u 2>/dev/null)" != 0 ] ; then
98    echo "Error: please run this script with uid 0 (root)." >&2
99    exit 1
100 fi
101
102 if [ -r /var/run/fai/FAI_INSTALLATION_IN_PROGRESS ] ; then
103    echo "/usr/sbin/fai already running or was aborted before.">&2
104    echo "You may remove /var/run/fai/FAI_INSTALLATION_IN_PROGRESS and try again.">&2
105    exit 1
106 fi
107
108 # see #449236
109 if [ -r /var/run/fai/fai_softupdate_is_running ] ; then
110    echo "/usr/sbin/fai softupdate already running or was aborted before.">&2
111    echo "You may remove /var/run/fai/fai_softupdate_is_running and try again.">&2
112    exit 1
113 fi
114 # }}}
115
116 # lsb-functions and configuration stuff {{{
117 # make sure they are not set by default
118 VERBOSE=''
119 FORCE=''
120 UPDATE=''
121 BUILD_ONLY=''
122 BUILD_DIRTY=''
123 BOOTSTRAP_ONLY=''
124 HOSTNAME=''
125 USERNAME=''
126 CONFIGDUMP=''
127
128 # don't use colors/escape sequences
129 if [ -r /lib/lsb/init-functions ] ; then
130   . /lib/lsb/init-functions
131   ! log_use_fancy_output && NOCOLORS=true
132 fi
133
134 if [ -r /etc/grml/lsb-functions ] ; then
135    . /etc/grml/lsb-functions
136 else
137    einfo()  { echo "  [*] $*" ;}
138    eerror() { echo "  [!] $*">&2 ;}
139    ewarn()  { echo "  [x] $*" ;}
140    eend()   { return 0 ;}
141    eindent()  { return 0 ;}
142    eoutdent() { return 0 ;}
143 fi
144
145 # source main configuration file:
146 LIVE_CONF=/etc/grml/grml-live.conf
147 . $LIVE_CONF
148 # }}}
149
150 # umount all directories {{{
151 umount_all() {
152    # make sure we don't leave any mounts - FAI doesn't remove them always
153    umount $CHROOT_OUTPUT/proc/sys/fs/binfmt_misc 2>/dev/null || /bin/true
154    umount $CHROOT_OUTPUT/proc 2>/dev/null || /bin/true
155    umount $CHROOT_OUTPUT/sys  2>/dev/null || /bin/true
156    umount $CHROOT_OUTPUT/dev/pts 2>/dev/null || /bin/true
157    umount $CHROOT_OUTPUT/dev 2>/dev/null || /bin/true
158
159    # certain FAI versions sadly leave a ramdisk behind, so better safe than sorry
160    if [ -x /usr/lib/fai/mkramdisk ] ; then
161      /usr/lib/fai/mkramdisk -u "$(readlink -f ${CHROOT_OUTPUT}/var/lib/dpkg)" >/dev/null 2>&1 || /bin/true
162    fi
163
164    umount "${CHROOT_OUTPUT}/grml-live/sources/" 2>/dev/null || /bin/true
165    [ -n "$MIRROR_DIRECTORY" ] && umount "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
166 }
167 # }}}
168
169 # clean exit {{{
170 bailout() {
171   rm -f /var/run/fai/fai_softupdate_is_running \
172         /var/run/fai/FAI_INSTALLATION_IN_PROGRESS
173   [ -n "$CONFIGDUMP"      ]  && rm -f  "$CONFIGDUMP"
174   [ -n "$SQUASHFS_STDERR" ]  && rm -rf "$SQUASHFS_STDERR"
175   umount_all
176   [ -n "$1" ] && EXIT="$1" || EXIT="1"
177   [ -n "$2" ] && eerror "$2">&2
178   if [ -n "$CLEAN_ARTIFACTS" ]; then
179     log "Cleaning up"
180     einfo "Cleaning up"
181     [ -n "${BUILD_OUTPUT}"  -a -d "${BUILD_OUTPUT}"  ] && rm -r "${BUILD_OUTPUT}"
182     [ -n "${CHROOT_OUTPUT}" -a -d "${CHROOT_OUTPUT}" ] && rm -r "${CHROOT_OUTPUT}"
183     eend 0
184   fi
185   if [ -n "$CHOWN_USER" ]; then
186     log "Setting ownership"
187     einfo "Setting ownership"
188     [ -n "${OUTPUT}"         -a -d "${OUTPUT}"         ] && chown -R "${CHOWN_USER}:" "${OUTPUT}"
189     [ -n "${BUILD_OUTPUT}"   -a -d "${BUILD_OUTPUT}"   ] && chown -R "${CHOWN_USER}:" "${BUILD_OUTPUT}"
190     [ -n "${CHROOT_OUTPUT}"  -a -d "${CHROOT_OUTPUT}"  ] && chown -R "${CHOWN_USER}:" "${CHROOT_OUTPUT}"
191     [ -n "${ISO_OUTPUT}"     -a -d "${ISO_OUTPUT}"     ] && chown -R "${CHOWN_USER}:" "${ISO_OUTPUT}"
192     [ -n "${LOG_OUTPUT}"     -a -d "${LOG_OUTPUT}"     ] && chown -R "${CHOWN_USER}:" "${LOG_OUTPUT}"
193     [ -n "${NETBOOT}"        -a -d "${NETBOOT}"        ] && chown -R "${CHOWN_USER}:" "${NETBOOT}"
194     eend 0
195   fi
196   log "------------------------------------------------------------------------------"
197   exit "$EXIT"
198 }
199 trap bailout 1 2 3 3 6 9 14 15
200 trap umount_all EXIT
201 # }}}
202
203 # some important functions {{{
204
205 # log output:
206 # usage: log "string to log"
207 log() { [ -n "$LOGFILE" ] && echo "$*" >> $LOGFILE ; }
208
209 # cut string at character number int = $1
210 # usage: cut_string 5 "1234567890" will output "12345"
211 cut_string() {
212   [ -n "$2" ] || return 1
213   echo "$2" | head -c "$1"; echo -ne "\n"
214 }
215
216 # prepend int = $1 spaces before string = $2
217 # usage: extend_string_begin 5 "123" will output "  123"
218 extend_string_begin() {
219   [ -n "$2" ] || return 1
220   local COUNT="$(echo $2 | wc -c)"
221   local FILL="$(expr $COUNT - $1)"
222   while [ "$FILL" -gt 1 ] ; do
223     echo -n " "
224     local FILL=$(expr $FILL - 1)
225   done
226   while [ "$FILL" -lt 1 ] ; do
227     echo -n " "
228     local FILL=$(expr $FILL + 1)
229   done
230   echo "$2" | head -c "$1"; echo -ne "\n"
231 }
232
233 # append int = $1 spaces to string = $2
234 # usage: extend_string_begin 5 "123" will output "123  "
235 extend_string_end() {
236   [ -n "$2" ] || return 1
237   echo -n "$2" | head -c "$1"
238   local COUNT="$(echo $2 | wc -c)"
239   local FILL="$(expr $COUNT - $1)"
240   while [ "$FILL" -gt 1 ] ; do
241     echo -n " "
242     local FILL=$(expr $FILL - 1)
243   done
244   while [ "$FILL" -lt 1 ] ; do
245     echo -n " "
246     local FILL=$(expr $FILL + 1)
247   done
248   echo -ne "\n"
249 }
250
251 # Copy addonfile $1 from either
252 #   * the chroot (via $2, the system path),
253 #   * or from TEMPLATE_DIRECTORY/compat (if exists),
254 #   * or from the host system (again, using $2),
255 # or warn about the missing file.
256 #
257 # This is because:
258 #   * We assume that the chroot always has a "good" version of
259 #     the file. Also it makes sources handling easier.
260 #   * On unstable, we Recommend the Debian packages containing
261 #     these files. The user can override them by putting his
262 #     "better" version into the chroot.
263 #   * On stable, the Debian packages are probably not available,
264 #     or outdated, so we look in TEMPLATE_DIRECTORY/compat first, where
265 #     our grml-live-compat package installs current file versions.
266 copy_addon_file() {
267   DEST="${BUILD_OUTPUT}/boot/$3"
268   if [ ! -d "${DEST}/" ]; then
269     mkdir -p "${DEST}"
270   fi
271   if [ -e "$CHROOT_OUTPUT/$2/$1" ]; then
272     log   "Copying $1 from chroot"
273     cp "$CHROOT_OUTPUT/$2/$1" "${DEST}/"
274     return $?
275   fi
276   if [ -e "${TEMPLATE_DIRECTORY}/compat/$3/$1" ]; then
277     log   "Copying $1 from grml-live-compat"
278     cp "${TEMPLATE_DIRECTORY}/compat/$3/$1" "${DEST}/"
279     return $?
280   fi
281   if [ -e "$2/$1" ]; then
282     log   "Copying $1 from system"
283     cp "$2/$1" "${DEST}/"
284     return $?
285   fi
286
287   msg="Missing addon file: \"$1\""
288   ewarn "$msg" ; eend 1
289   log "copy_addon_file: $msg"
290 }
291 # }}}
292
293 # command line parsing {{{
294 while getopts "a:C:c:d:D:e:g:i:I:o:r:s:t:U:v:AbBFnNqQuVz" opt; do
295   case "$opt" in
296     a) ARCH="$OPTARG" ;;
297     A) CLEAN_ARTIFACTS=1 ;;
298     b) BUILD_ONLY=1 ;;
299     B) BUILD_DIRTY=1 ;;
300     c) CLASSES="$OPTARG" ;;
301     C) LOCAL_CONFIG="$(readlink -f $OPTARG)" ;;
302     d) DATE="$OPTARG" ;;
303     D) GRML_FAI_CONFIG="$(readlink -f $OPTARG)" ;;
304     e) EXTRACT_ISO_NAME="$(readlink -f $OPTARG)" ;;
305     g) GRML_NAME="$OPTARG" ;;
306     i) ISO_NAME="$OPTARG" ;;
307     I) CHROOT_INSTALL="$OPTARG" ;;
308     n) SKIP_MKISOFS=1 ;;
309     N) BOOTSTRAP_ONLY=1; SKIP_MKISOFS=1; SKIP_MKSQUASHFS=1 ;;
310     o) OUTPUT="$(readlink -f $OPTARG)" ;;
311     q) SKIP_MKSQUASHFS=1 ;;
312     Q) SKIP_NETBOOT=1 ;;
313     r) RELEASENAME="$OPTARG" ;;
314     s) SUITE="$OPTARG" ;;
315     t) TEMPLATE_DIRECTORY="$OPTARG";;
316     v) VERSION="$OPTARG" ;;
317     F) FORCE=1 ;;
318     u) UPDATE=1 ;;
319     U) CHOWN_USER="$OPTARG" ;;
320     V) VERBOSE="-v" ;;
321     z) SQUASHFS_ZLIB=1 ;;
322     ?) echo "invalid option -$OPTARG" >&2; bailout 1 ;;
323   esac
324 done
325 shift $(($OPTIND - 1))  # set ARGV to the first not parsed commandline parameter
326 # }}}
327
328 # read local (non-packaged) configuration {{{
329 if [ -z "$LOCAL_CONFIG" ]; then
330   if [ -r "/etc/grml/grml-live.local" ]; then
331     LOCAL_CONFIG="/etc/grml/grml-live.local"
332   fi
333 fi
334 if [ -n "$LOCAL_CONFIG" ]; then
335   if [ -r "$LOCAL_CONFIG" ]; then
336     . $LOCAL_CONFIG
337   else
338     eerror "Could not read specified local configuration file \"$LOCAL_CONFIG\"."
339     bailout 1
340   fi
341   LOCAL_CONFIG=$(readlink -f "$LOCAL_CONFIG")
342 else
343   LOCAL_CONFIG=''
344 fi
345
346 if [ -n "${GRML_LIVE_SOURCES:-}" ] ; then
347   eerror "Config variable \$GRML_LIVE_SOURCES is set. This variable has been deprecated."
348   ewarn  "Please set up \${GRML_FAI_CONFIG}/config/files/etc/apt/sources.list.d/* instead."
349   bailout 1
350 fi
351 # }}}
352
353 # assume sane defaults (if not set already) {{{
354 [ -n "$ARCH" ]                    || ARCH="$(dpkg --print-architecture)"
355 [ -n "$BOOT_METHOD" ]             || BOOT_METHOD='isolinux'
356 [ -n "$CLASSES" ]                 || CLASSES="GRMLBASE,GRML_FULL,$(echo ${ARCH} | tr 'a-z' 'A-Z')"
357 [ -n "$DATE" ]                    || DATE="$(date +%Y-%m-%d)"
358 [ -n "$DISTRI_INFO" ]             || DISTRI_INFO='Grml - Live Linux for system administrators   '
359 [ -n "$DISTRI_NAME" ]             || DISTRI_NAME="grml"
360 [ -n "$DISTRI_SPLASH" ]           || DISTRI_SPLASH='grml.png'
361 [ -n "$FORCE_ISO_REBUILD" ]       || FORCE_ISO_REBUILD="false"
362 [ -n "$GRML_FAI_CONFIG" ]         || GRML_FAI_CONFIG='/etc/grml/fai'
363 [ -n "$GRML_NAME" ]               || GRML_NAME='grml'
364 [ -n "$HOSTNAME" ]                || HOSTNAME='grml'
365 [ -n "$HYBRID_METHOD" ]           || HYBRID_METHOD='manifold'
366 [ -n "$NFSROOT_CONF" ]            || NFSROOT_CONF="${GRML_FAI_CONFIG}/make-fai-nfsroot.conf"
367 [ -n "$RELEASENAME" ]             || RELEASENAME='grml-live rocks'
368 [ -n "$SQUASHFS_EXCLUDES_FILE" ]  || SQUASHFS_EXCLUDES_FILE="${GRML_FAI_CONFIG}/config/grml/squashfs-excludes"
369 [ -n "$SUITE" ]                   || SUITE='squeeze'
370 [ -n "$TEMPLATE_DIRECTORY" ]      || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
371 [ -n "$USERNAME" ]                || USERNAME='grml'
372 [ -n "$VERSION" ]                 || VERSION='0.0.1'
373
374 # output specific stuff, depends on $OUTPUT (iff not set):
375 [ -n "$OUTPUT" ]           || OUTPUT='/grml/grml-live'
376 [ -n "$BUILD_OUTPUT" ]     || BUILD_OUTPUT="$OUTPUT/grml_cd"
377 [ -n "$CHROOT_OUTPUT" ]    || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
378 [ -n "$ISO_OUTPUT" ]       || ISO_OUTPUT="$OUTPUT/grml_isos"
379 [ -n "$LOG_OUTPUT" ]       || LOG_OUTPUT="$OUTPUT/grml_logs"
380 [ -n "$REPORTS" ]          || REPORTS="${LOG_OUTPUT}/reports/"
381 [ -n "$NETBOOT" ]          || NETBOOT="${OUTPUT}/netboot/"
382 # }}}
383
384 # some misc checks before executing FAI {{{
385 [ -n "$CLASSES" ] || bailout 1 "Error: \$CLASSES unset, please set it in $LIVE_CONF or
386 specify it on the command line using the -c option."
387 [ -n "$OUTPUT" ] || bailout 1 "Error: \$OUTPUT unset, please set it in $LIVE_CONF or
388 specify it on the command line using the -o option."
389
390 # trim characters that are known to cause problems inside $GRML_NAME;
391 # for example isolinux does not like '-' inside the directory name
392 [ -n "$GRML_NAME" ] && export SHORT_NAME="$(echo $GRML_NAME | tr -d ',./;\- ')"
393
394 # export variables to have them available in fai scripts:
395 [ -n "$GRML_NAME" ]   && export GRML_NAME="$GRML_NAME"
396 [ -n "$RELEASENAME" ] && export RELEASENAME="$RELEASENAME"
397 # }}}
398
399 # ZERO_LOGFILE - check for backwards compatibility reasons {{{
400 # this was default behaviour until grml-live 0.9.34:
401 if [ -n "$ZERO_LOGFILE" ] ; then
402    PRESERVE_LOGFILE='' # make sure it's cleaned then
403    ewarn "Please consider disabling the \$ZERO_LOGFILE option as grml-live clears..."
404    ewarn "... the logfile $LOGFILE by default (unless \$PRESERVE_LOGFILE is set) nowadays."
405    eend 0
406 fi
407 # }}}
408
409 # ask user whether the setup is ok {{{
410 if [ -z "$FORCE" ] ; then
411    echo
412    echo "${PN} [${GRML_LIVE_VERSION}]: check your configuration (or use -F to force execution):"
413    echo
414    echo "  FAI classes:       $CLASSES"
415    [ -n "$LOCAL_CONFIG" ]        && echo "  Configuration:     $LOCAL_CONFIG"
416    [ -n "$GRML_FAI_CONFIG" ]     && echo "  Config directory:  $GRML_FAI_CONFIG"
417    echo "  main directory:    $OUTPUT"
418    [ -n "$EXTRACT_ISO_NAME" ]    && echo "  Extract ISO:       $EXTRACT_ISO_NAME"
419    [ -n "$CHROOT_OUTPUT" ]       && echo "  Chroot target:     $CHROOT_OUTPUT"
420    [ -n "$BUILD_OUTPUT" ]        && echo "  Build target:      $BUILD_OUTPUT"
421    [ -n "$ISO_OUTPUT" ]          && echo "  ISO target:        $ISO_OUTPUT"
422    [ -n "$GRML_NAME" ]           && echo "  Grml name:         $GRML_NAME"
423    [ -n "$RELEASENAME" ]         && echo "  Release name:      $RELEASENAME"
424    [ -n "$DATE" ]                && echo "  Build date:        $DATE"
425    [ -n "$VERSION" ]             && echo "  Grml version:      $VERSION"
426    [ -n "$SUITE" ]               && echo "  Debian suite:      $SUITE"
427    [ -n "$ARCH" ]                && echo "  Architecture:      $ARCH"
428    [ -n "$BOOT_METHOD" ]         && echo "  Boot method:       $BOOT_METHOD"
429    [ -n "$HYBRID_METHOD" ]       && echo "  Hybrid method:     $HYBRID_METHOD"
430    [ -n "$TEMPLATE_DIRECTORY" ]  && echo "  Template files:    $TEMPLATE_DIRECTORY"
431    [ -n "$CHROOT_INSTALL" ]      && echo "  Install files from directory to chroot:  $CHROOT_INSTALL"
432    [ -n "$BOOTID" ]              && echo "  Boot identifier:   $BOOTID"
433    [ -n "$NO_BOOTID" ]           && echo "  Skipping bootid feature."
434    [ -n "$CHOWN_USER" ]          && echo "  Output owner:      $CHOWN_USER"
435    [ -n "$DEFAULT_BOOTOPTIONS" ] && echo "  Adding default bootoptions: \"$DEFAULT_BOOTOPTIONS\""
436    [ -n "$FAI_ARGS" ]            && echo "  Additional arguments for FAI: $FAI_ARGS"
437    [ -n "$LOGFILE" ]             && echo "  Logging to file:   $LOGFILE"
438    [ -n "$SQUASHFS_ZLIB" ]       && echo "  Using ZLIB (instead of LZMA/XZ) compression."
439    [ -n "$SQUASHFS_OPTIONS" ]    && echo "  Using SQUASHFS_OPTIONS ${SQUASHFS_OPTIONS}"
440    [ -n "$VERBOSE" ]             && echo "  Using VERBOSE mode."
441    [ -n "$CLEAN_ARTIFACTS" ]     && echo "  Will clean output before and after running."
442    [ -n "$UPDATE" ]              && echo "  Executing UPDATE instead of fresh installation."
443    if [ -n "$BOOTSTRAP_ONLY" ] ; then
444      echo "  Bootstrapping only and not building (files for) ISO."
445    else
446      [ -n "$SKIP_MKSQUASHFS" ]     && echo "  Skipping creation of SQUASHFS file."
447      [ -n "$SKIP_NETBOOT" ]        && echo "  Skipping creation of NETBOOT package."
448      [ -n "$SKIP_MKISOFS" ]        && echo "  Skipping creation of ISO file."
449      [ -n "$BUILD_ONLY" ]          && echo "  Executing BUILD_ONLY instead of fresh installation or UPDATE."
450      [ -n "$BUILD_DIRTY" ]         && echo "  Executing BUILD_DIRTY to leave chroot untouched."
451    fi
452    echo
453    echo -n "Is this ok for you? [y/N] "
454    read a
455    if ! [ "$a" = 'y' -o "$a" = 'Y' ] ; then
456       bailout 1 "Exiting as requested."
457    fi
458    echo
459 fi
460 # }}}
461
462 # clean up before start {{{
463 if [ -n "${CLEAN_ARTIFACTS}" ]; then
464   echo "Wiping old artifacts"
465   [ -n "${CHROOT_OUTPUT}"  -a -d "${CHROOT_OUTPUT}"  ] && rm -r "${CHROOT_OUTPUT}"
466   [ -n "${BUILD_OUTPUT}"   -a -d "${BUILD_OUTPUT}"   ] && rm -r "${BUILD_OUTPUT}"
467   [ -n "${ISO_OUTPUT}"     -a -d "${ISO_OUTPUT}"     ] && rm -r "${ISO_OUTPUT}"
468   [ -n "${LOG_OUTPUT}"     -a -d "${LOG_OUTPUT}"     ] && rm -r "${LOG_OUTPUT}"
469   [ -n "${NETBOOT}"        -a -d "${NETBOOT}"        ] && rm -r "${NETBOOT}"
470 fi
471 # }}}
472
473 # create log file {{{
474 [ -n "$LOGFILE" ] || LOGFILE=${LOG_OUTPUT}/grml-live.log
475 mkdir -p $(dirname "${LOGFILE}")
476 touch $LOGFILE
477 chown root:adm $LOGFILE
478 chmod 664 $LOGFILE
479 # }}}
480
481 # clean/zero/remove logfiles {{{
482
483 if [ -n "$PRESERVE_LOGFILE" ] ; then
484    echo "Preserving logfile $LOGFILE as requested via \$PRESERVE_LOGFILE"
485 else
486    # make sure it is empty (as it is e.g. appended to grml-live-db)
487    echo -n > $LOGFILE
488 fi
489
490 if [ -n "$ZERO_FAI_LOGFILE" ] ; then
491    if [ -d /var/log/fai/"$HOSTNAME" ] ; then
492       rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last)"
493       rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-dirinstall)"
494       rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-softupdate)"
495       rm -f /var/log/fai/"$HOSTNAME"/last \
496             /var/log/fai/"$HOSTNAME"/last-dirinstall \
497             /var/log/fai/"$HOSTNAME"/last-softupdate
498    fi
499 fi
500 # }}}
501
502 # source config and startup {{{
503 if [ -n "$CONFIG" ] ; then
504    if ! [ -f "$CONFIG" ] ; then
505       log    "Error: $CONFIG could not be read. Exiting. [$(date)]"
506       eerror "Error: $CONFIG could not be read. Exiting." ; eend 1
507       bailout 1
508    else
509       log "Sourcing $CONFIG"
510       . $CONFIG
511    fi
512 fi
513
514 start_seconds=$(cut -d . -f 1 /proc/uptime)
515 log "------------------------------------------------------------------------------"
516 log "Starting grml-live [${GRML_LIVE_VERSION}] run on $(date)"
517 log "Using local config file: $LOCAL_CONFIG"
518 log "Executed grml-live command line:"
519 log "$CMDLINE"
520
521 einfo "Logging actions to logfile $LOGFILE"
522 # }}}
523
524 # dump config variables into file, for script access {{{
525 CONFIGDUMP=$(mktemp)
526 set | egrep \
527   '^(GRML_NAME|RELEASENAME|DATE|VERSION|SUITE|ARCH|DISTRI_NAME|USERNAME|HOSTNAME|APT_PROXY)=' \
528   > ${CONFIGDUMP}
529 # }}}
530
531 # unpack iso/squashfs {{{
532 extract_iso() {
533 if [ -n "$EXTRACT_ISO_NAME" ]; then
534   log "Unpacking ISO from ${EXTRACT_ISO_NAME}"
535   einfo "Unpacking ISO from ${EXTRACT_ISO_NAME}"
536   local mountpoint=$(mktemp -d)
537   local rc=0
538   mount -o loop "${EXTRACT_ISO_NAME}" "$mountpoint" ; rc=$?
539   if [ "$rc" != 0 ]; then
540     rmdir "$mountpoint"
541     log "mount failed"
542     eerror "mount failed"
543     eend 1
544     bailout 1
545   fi
546   unsquashfs -d "${CHROOT_OUTPUT}" "${mountpoint}"/live/*.squashfs ; rc=$?
547   umount "$mountpoint"
548   rmdir "$mountpoint"
549   if [ "$rc" != 0 ]; then
550     log "unsquashfs failed"
551     eerror "unsquashfs failed"
552     eend 1
553     bailout 1
554   fi
555 fi
556 }
557 extract_iso
558 # }}}
559
560 # on-the-fly configuration {{{
561 if [ -n "$FAI_DEBOOTSTRAP" ] ; then
562   sed "s#^FAI_DEBOOTSTRAP=.*#FAI_DEBOOTSTRAP=\"$FAI_DEBOOTSTRAP\"#" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
563 fi
564
565 # does this suck? YES!
566 # /usr/share/debootstrap/scripts/unstable does not exist, instead use 'sid':
567 case $SUITE in
568    unstable) SUITE='sid' ; CLASSES="DEBIAN_UNSTABLE,$CLASSES" ;;
569    *) CLASSES="DEBIAN_$(echo $SUITE | tr 'a-z' 'A-Z'),$CLASSES";;
570 esac
571 export SUITE # make sure it's available in FAI scripts
572
573 for file in "$LIVE_CONF" "$LOCAL_CONFIG" "$NFSROOT_CONF" ; do
574     if [ -n "$file" ] ; then
575        sed "s|^FAI_DEBOOTSTRAP=\"[a-z]* |FAI_DEBOOTSTRAP=\"$SUITE |" "$file" | sponge "$file"
576     fi
577 done
578
579 # validate whether the specified architecture class matches the
580 # architecture (option), otherwise installation of kernel will fail
581 if echo $CLASSES | grep -qi i386 ; then
582    if ! [[ "$ARCH" == "i386" ]] ; then
583       log    "Error: You specified the I386 class but are trying to build something else (AMD64?)."
584       eerror "Error: You specified the I386 class but are trying to build something else (AMD64?)."
585       eerror "Tip:   Either invoke grml-live with '-a i386' or adjust the architecture class. Exiting."
586       eend 1
587       bailout
588    fi
589 elif echo $CLASSES | grep -qi amd64 ; then
590    if ! [[ "$ARCH" == "amd64" ]] ; then
591       log    "Error: You specified the AMD64 class but are trying to build something else (I386?)."
592       eerror "Error: You specified the AMD64 class but are trying to build something else (I386?)."
593       eerror "Tip:   Either invoke grml-live with '-a amd64' or adjust the architecture class. Exiting."
594       eend 1
595       bailout
596    fi
597 fi
598
599 if grep -q -- 'FAI_DEBOOTSTRAP_OPTS.*--arch' "$NFSROOT_CONF" ; then
600    sed "s/--arch [a-z0-9]* /--arch $ARCH /" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
601 else
602    sed "s|^FAI_DEBOOTSTRAP_OPTS=\"\(.*\)|FAI_DEBOOTSTRAP_OPTS=\"--arch $ARCH \1|" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
603 fi
604 # }}}
605
606 # CHROOT_OUTPUT - execute FAI {{{
607 if [ -n "$BUILD_DIRTY" ]; then
608    log   "Skipping stage 'fai' as requested via option -B"
609    ewarn "Skipping stage 'fai' as requested via option -B" ; eend 0
610 else
611    [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
612
613    # provide inform fai about the ISO we build
614    [ -d "$CHROOT_OUTPUT/etc/" ] || mkdir -p "$CHROOT_OUTPUT/etc/"
615    echo '# This file has been generated by grml-live.' > "$CHROOT_OUTPUT/etc/grml_live_version"
616    [ -n "$GRML_LIVE_VERSION" ] && echo "GRML_LIVE_VERSION=$GRML_LIVE_VERSION" >> "$CHROOT_OUTPUT/etc/grml_live_version"
617    [ -n "$SUITE" ] && echo "SUITE=$SUITE" >> "$CHROOT_OUTPUT/etc/grml_live_version"
618
619    if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
620       FAI_ACTION=softupdate
621    else
622       FAI_ACTION=dirinstall
623    fi
624
625    if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
626       if ! [ -r "$CHROOT_OUTPUT/etc/debian_version" ] ; then
627          log    "Error: does not look like you have a working chroot. Updating/building not possible."
628          eerror "Error: does not look like you have a working chroot. Updating/building not possible. (Drop -u/-b option?)"
629          eend 1
630          bailout 20
631       fi
632    fi
633
634    if [ -d "$CHROOT_OUTPUT/bin" -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
635       log   "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already."
636       ewarn "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already." ; eend 0
637    else
638       mkdir -p "$CHROOT_OUTPUT" || bailout 5 "Problem with creating $CHROOT_OUTPUT for FAI"
639
640       if [ -n "${MIRROR_DIRECTORY}" ] ; then
641          mkdir -p "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
642          mount --bind "${MIRROR_DIRECTORY}" "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
643       fi
644
645       mkdir -p "${OUTPUT}/grml_sources/" "${CHROOT_OUTPUT}/grml-live/sources/"
646       mount --bind "${OUTPUT}/grml_sources/" "${CHROOT_OUTPUT}/grml-live/sources/"
647
648       # tell dpkg to use "unsafe io" during the build
649       [ -d "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d" ] || mkdir -p "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d"
650       echo force-unsafe-io > "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
651
652       log "Executed FAI command line:"
653       log "BUILD_ONLY=$BUILD_ONLY BOOTSTRAP_ONLY=$BOOTSTRAP_ONLY GRML_LIVE_CONFIG=$CONFIGDUMP fai $VERBOSE -C $GRML_FAI_CONFIG -s file:///$GRML_FAI_CONFIG/config -c$CLASSES -u $HOSTNAME $FAI_ACTION $CHROOT_OUTPUT $FAI_ARGS"
654       BUILD_ONLY="$BUILD_ONLY" BOOTSTRAP_ONLY="$BOOTSTRAP_ONLY" GRML_LIVE_CONFIG="$CONFIGDUMP" fai $VERBOSE \
655                   -C "$GRML_FAI_CONFIG" -s "file:///$GRML_FAI_CONFIG/config" -c"$CLASSES" \
656                   -u "$HOSTNAME" "$FAI_ACTION" "$CHROOT_OUTPUT" $FAI_ARGS | tee -a $LOGFILE
657       RC="$PIPESTATUS" # notice: bash-only
658
659       rm -f "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
660
661       FORCE_ISO_REBUILD=true
662
663       if [ "$RC" != 0 ] ; then
664          log    "Error: critical error while executing fai [exit code ${RC}]. Exiting."
665          eerror "Error: critical error while executing fai [exit code ${RC}]. Exiting." ; eend 1
666          bailout 1
667       fi
668
669       # move fai logs into grml_logs directory
670       mkdir -p "$LOG_OUTPUT"/fai/
671       cp -r "$CHROOT_OUTPUT"/var/log/fai/"$HOSTNAME"/last/* "$LOG_OUTPUT"/fai/
672       rm -rf "$CHROOT_OUTPUT"/var/log/fai
673       # copy fai package list
674       cp "$CHROOT_OUTPUT"/var/log/install_packages.list "$LOG_OUTPUT"/fai/
675       # fixup owners
676       chown root:adm "$LOG_OUTPUT"/fai/*
677       chmod 664 "$LOG_OUTPUT"/fai/*
678
679       umount_all
680
681       # notice: 'fai dirinstall' does not seem to exit appropriate, so:
682       ERROR=''
683       CHECKLOG="$LOG_OUTPUT"/fai/
684       if [ -r "$CHECKLOG/software.log" ] ; then
685          # 1 errors during executing of commands
686          grep 'dpkg: error processing' $CHECKLOG/software.log >> $LOGFILE && ERROR=1
687          grep 'E: Method http has died unexpectedly!' $CHECKLOG/software.log >> $LOGFILE && ERROR=2
688          grep 'ERROR: chroot' $CHECKLOG/software.log >> $LOGFILE && ERROR=3
689          grep 'E: Failed to fetch' $CHECKLOG/software.log >> $LOGFILE && ERROR=4
690          grep 'Unable to write mmap - msync (28 No space left on device)' $CHECKLOG/software.log >> $LOGFILE && ERROR=5
691       fi
692
693       if [ -r "$CHECKLOG/shell.log" ] ; then
694          grep 'FAILED with exit code' $CHECKLOG/shell.log >> $LOGFILE && ERROR=6
695       fi
696
697       if [ -n "$ERROR" ] ; then
698          log    "Error: there was a critical error [${ERROR}] during execution of stage 'fai dirinstall' [$(date)]"
699          eerror "Error: there was a critical error during execution of stage 'fai dirinstall'"
700          eerror "Note:  check out ${CHECKLOG}/ for details. [exit ${ERROR}]"
701          eend 1
702          bailout 1
703       else
704          log "Finished execution of stage 'fai dirinstall' [$(date)]"
705          einfo "Finished execution of stage 'fai dirinstall'"
706       fi
707    fi
708 fi # BUILD_DIRTY?
709 # }}}
710
711 # package validator {{{
712 CHECKLOG=/var/log/fai/$HOSTNAME/last
713 if [ -r "$CHECKLOG/dpkg.selections" ] ; then
714   package_count=$(wc -l "$CHECKLOG/dpkg.selections" | awk '{print $1}')
715 else
716   package_count="unknown"
717 fi
718
719 mkdir -p "$REPORTS"
720 REPORT_MISSING_PACKAGES="${REPORTS}/TEST-MissingPackages.xml"
721
722 # check for missing packages
723 if ! [ -s "$CHECKLOG/package_errors.log" ] ; then
724   einfo "No missing packages found, generating empty junit report."
725
726   cat > "${REPORT_MISSING_PACKAGES}" << EOF
727 <?xml version="1.0" encoding="UTF-8"?>
728 <testsuite name="grml-live-missing-packages" tests="${package_count}" time="1" failures="0" errors="0" skipped="0" assertions="0">
729   <testcase name="test_missing_packages" time="0" assertions="0">
730   </testcase>
731   <system-out>
732   </system-out>
733   <system-err>
734   </system-err>
735 </testsuite>
736 EOF
737   eend 0
738 else
739   einfo "Missing packages found, generating junit report."
740
741   if [ -r "$CHECKLOG/package_errors.log" ] ; then
742     package_errors=$(wc -l "$CHECKLOG/package_errors.log" | awk '{print $1}')
743   else
744     package_errors="unknown"
745   fi
746
747   mkdir -p "$REPORTS"
748   REPORT_MISSING_PACKAGES="${REPORTS}/TEST-MissingPackages.xml"
749
750   cat > "${REPORT_MISSING_PACKAGES}" << EOF
751 <?xml version="1.0" encoding="UTF-8"?>
752 <testsuite name="grml-live-missing-packages" tests="${package_count}" time="1" failures="${package_errors}" errors="${package_errors}" skipped="0" assertions="0">
753 EOF
754
755   for package in $(awk '{print $5}' "${CHECKLOG}/package_errors.log" | sed 's/\.$//') ; do
756     cat >> "${REPORT_MISSING_PACKAGES}" << EOF
757   <testcase name="test_missing_packages_${package}" time="0" assertions="0">
758     <failure type="RuntimeError" message="Package ${package} is missing">
759 Package $package is missing in chroot
760   </failure>
761   </testcase>
762 EOF
763   done
764
765   cat >> "${REPORT_MISSING_PACKAGES}" << EOF
766   <system-out>
767   </system-out>
768   <system-err>
769   </system-err>
770 </testsuite>
771 EOF
772   eend 0
773
774   if [ -n "$EXIT_ON_MISSING_PACKAGES" -a -z "$BUILD_DIRTY" ] ; then
775     eerror "The following packages were requested for installation but could not be processed:"
776     cat "$CHECKLOG/package_errors.log"
777     eerror "... exiting as requested via \$EXIT_ON_MISSING_PACKAGES."
778     eend 1
779     bailout 13
780   else
781     ewarn "The following packages were requested for installation but could not be processed:"
782     cat "$CHECKLOG/package_errors.log"
783     eend 0
784   fi
785 fi
786 # }}}
787
788 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
789 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
790 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
791
792 # prepare ISO
793 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
794   if [ -n "$BOOTSTRAP_ONLY" ] ; then
795      log   "Skipping stage 'boot' as building with bootstrap only."
796      ewarn "Skipping stage 'boot' as building with bootstrap only." ; eend 0
797   else
798     if [ -d "$BUILD_OUTPUT"/boot/isolinux -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
799        log   "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already."
800        ewarn "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already." ; eend 0
801     else
802        # booting stuff:
803        [ -d "$BUILD_OUTPUT"/boot/isolinux ] || mkdir -p "$BUILD_OUTPUT"/boot/isolinux
804        [ -d "$BUILD_OUTPUT"/boot/"${SHORT_NAME}" ] || mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"
805
806        # if we don't have an initrd we a) can't boot and b) there was an error
807        # during build, so check for the file:
808        INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
809        if [ -n "$INITRD" ] ; then
810           cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/initrd.img
811           find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
812        else
813           log    "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
814           eerror "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
815           bailout 10
816        fi
817
818        KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
819        if [ -n "$KERNEL_IMAGE" ] ; then
820           cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/vmlinuz
821        else
822           log    "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
823           eerror "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
824           bailout 11
825        fi
826
827        [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
828        if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
829           log    "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
830           eerror "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
831           bailout 8
832        fi
833
834        # copy _required_ isolinux files
835        for file in ifcpu64.c32 isolinux.bin vesamenu.c32; do
836          copy_addon_file "${file}" /usr/lib/syslinux isolinux
837        done
838
839        # *always* copy files to output directory so the variables
840        # get adjusted according to the build.
841        cp ${TEMPLATE_DIRECTORY}/boot/isolinux/*  "$BUILD_OUTPUT"/boot/isolinux/
842
843        if [ -n "$NO_ADDONS" ] ; then
844           log   "Skipping installation of boot addons as requested via \$NO_ADDONS."
845           einfo "Skipping installation of boot addons as requested via \$NO_ADDONS."; eend 0
846        else
847           if ! [ -d "$TEMPLATE_DIRECTORY"/boot/addons ] ; then
848             log   "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)"
849             ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
850           else
851             # copy addons from system packages or grml-live-compat
852             copy_addon_file ipxe.lkrn /usr/lib/ipxe addons
853             copy_addon_file pci.ids /usr/share/misc addons
854             copy_addon_file memtest86+.bin /boot addons
855             for file in memdisk chain.c32 hdt.c32 menu.c32; do
856               copy_addon_file "${file}" /usr/lib/syslinux addons
857             done
858
859             # make memtest filename FAT16/8.3 compatible
860             mv "${BUILD_OUTPUT}/boot/addons/memtest86+.bin" \
861               "${BUILD_OUTPUT}/boot/addons/memtest"
862
863             # copy only files so we can handle bsd4grml on its own
864             for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
865               test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
866             done
867
868             if [ -n "$NO_ADDONS_BSD4GRML" ] ; then
869                log   "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."
870                einfo "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."; eend 0
871             else
872                if [ -d "$TEMPLATE_DIRECTORY"/boot/addons/bsd4grml ] ; then
873                  cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
874                else
875                  log   "Missing addon file: bsd4grml"
876                  ewarn "Missing addon file: bsd4grml" ; eend 0
877                fi
878             fi
879
880           fi # no "$TEMPLATE_DIRECTORY"/boot/addons
881        fi # NO_ADDONS
882
883        if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
884          mkdir -p "${BUILD_OUTPUT}/boot/grub"
885        fi
886        cp -a ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
887
888        # copy grub files from target
889        cp -a "${CHROOT_OUTPUT}"/usr/lib/grub/*-pc/*.mod "${BUILD_OUTPUT}"/boot/grub/
890        cp -a "${CHROOT_OUTPUT}"/usr/lib/grub/*-pc/*.o "${BUILD_OUTPUT}"/boot/grub/
891        cp -a "${CHROOT_OUTPUT}"/usr/lib/grub/*-pc/*.lst "${BUILD_OUTPUT}"/boot/grub/
892        cp -a "${CHROOT_OUTPUT}"/usr/share/grub/ascii.pf2 "${BUILD_OUTPUT}"/boot/grub/
893        cp -a "${CHROOT_OUTPUT}"/boot/grub/core.img "${BUILD_OUTPUT}"/boot/grub/
894
895        if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
896           log    "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
897           eerror "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
898           bailout 9
899        fi
900
901        [ -d "$BUILD_OUTPUT"/GRML ] || mkdir "$BUILD_OUTPUT"/GRML
902        cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/
903
904        # adjust boot splash information:
905        RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
906        RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
907        RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
908
909        if [ -r "$BUILD_OUTPUT"/GRML/grml-version ] ; then
910           sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/grml-version
911           sed -i "s/%DATE%/$DATE/"                                      "$BUILD_OUTPUT"/GRML/grml-version
912        fi
913
914        # make sure the squashfs filename is set accordingly:
915        SQUASHFS_NAME="$GRML_NAME.squashfs"
916
917        if [ -n "$NO_BOOTID" ] ; then
918           log   'Skipping bootid feature as requested via $NO_BOOTID.'
919           einfo 'Skipping bootid feature as requested via $NO_BOOTID.'
920        else
921           [ -n "$BOOTID" ] || BOOTID="$(echo ${GRML_NAME}${VERSION} | tr -d ',./;\- ')"
922           [ -d "$BUILD_OUTPUT"/conf ] || mkdir "$BUILD_OUTPUT"/conf
923           einfo "Generating /conf/bootid.txt with entry ${BOOTID}."
924           log   "Generating /conf/bootid.txt with entry ${BOOTID}."
925           echo "$BOOTID" > "$BUILD_OUTPUT"/conf/bootid.txt
926           eend $?
927        fi
928
929        # adjust all variables in the templates with the according distribution information
930        for file in "${BUILD_OUTPUT}"/boot/isolinux/*.cfg "${BUILD_OUTPUT}"/boot/isolinux/*.msg \
931                    "${BUILD_OUTPUT}"/boot/grub/* ; do
932          if [ -r "${file}" ] ; then
933            sed -i "s/%ARCH%/$ARCH/g"                    "${file}"
934            sed -i "s/%DATE%/$DATE/g"                    "${file}"
935            sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/g"      "${file}"
936            sed -i "s/%DISTRI_NAME%/$DISTRI_NAME/g"      "${file}"
937            sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/g"  "${file}"
938            sed -i "s/%GRML_NAME%/$GRML_NAME/g"          "${file}"
939            sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/g"  "${file}"
940            sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/g"    "${file}"
941            sed -i "s/%SHORT_NAME%/$SHORT_NAME/g"        "${file}"
942            sed -i "s/%VERSION%/$VERSION/g"              "${file}"
943
944            [ -n "$DEFAULT_BOOTOPTIONS" ] && sed -i "s/ boot=live/ boot=live $DEFAULT_BOOTOPTIONS/"  "${file}"
945
946            if [ -n "$NO_BOOTID" ] ; then
947               sed -i "s/ bootid=%BOOTID%//g" "${file}" # drop bootid bootoption
948            else
949               sed -i "s/%BOOTID%/$BOOTID/g" "${file}" # adjust bootid=... argument
950            fi
951          fi
952        done
953
954        for param in ARCH DATE DISTRI_INFO DISTRI_NAME DISTRI_SPLASH GRML_NAME SQUASHFS_NAME \
955            RELEASE_INFO SHORT_NAME VERSION ; do
956            for file in $(find "${BUILD_OUTPUT}" -name "*%$param%*") ; do
957                value="$(eval echo '$'"$param")"
958                mv ${file} ${file/\%${param}\%/$value}
959            done
960        done
961
962        # adjust bootsplash accordingly but make sure the string has the according lenght
963        SQUASHFS_NAME="$(cut_string 20 "$SQUASHFS_NAME")"
964        SQUASHFS_NAME="$(extend_string_end 20 "$SQUASHFS_NAME")"
965        for file in f4 f5 ; do
966           if [ -r "${BUILD_OUTPUT}/boot/isolinux/${file}" ] ; then
967              sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
968              sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
969           fi
970        done
971
972        # generate addon list
973        rm -f "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
974        for name in "${BUILD_OUTPUT}"/boot/isolinux/addon_*.cfg ; do
975          include_name=$(basename "$name")
976          echo "include $include_name"  >> "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
977        done
978
979        if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
980           log "including grmlmain.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
981           echo "include grmlmain.cfg"    >  "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
982           echo "include default.cfg"     >  "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
983           echo "include menuoptions.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
984           echo "include grml.cfg"        >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
985
986           for f in "${BUILD_OUTPUT}"/boot/isolinux/submenu*.cfg ; do
987             echo "include $(basename $f)"     >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
988           done
989
990           echo "include options.cfg"     >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
991           if [ ! -n "$NO_ADDONS" ] ; then
992             echo "include addons.cfg"    >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
993           fi
994           echo "include isoprompt.cfg"   >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
995           echo "include hd.cfg"          >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
996           echo "include hidden.cfg"      >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
997        else # assume we are building a custom distribution:
998           log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
999           einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
1000           if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
1001             log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
1002             eindent
1003             einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
1004             eoutdent
1005             eend $?
1006          else
1007             log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1008             echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1009             [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1010           fi
1011        fi
1012
1013        # use old style console based isolinux method only if requested:
1014        if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
1015           log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
1016           einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
1017           if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
1018             einfo "include for console.cfg already found, nothing to do."
1019             eend 0
1020           else
1021             log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1022             einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1023             echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1024             eend $?
1025           fi
1026        else
1027           log 'Using graphical boot menu.'
1028           if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
1029             log "include for vesamenu.cfg already found, nothing to do."
1030           else
1031             log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1032             echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1033           fi
1034        fi
1035
1036        if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
1037           sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
1038        fi
1039
1040        DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot
1041        if ! [ -r "$DPKG_LIST" ] ; then
1042           ewarn "$DPKG_LIST could not be read, ignoring to store package information on ISO therefore."
1043        else
1044           einfo "Storing package list information as /GRML/${GRML_NAME}-packages.txt on ISO."
1045           cp "$DPKG_LIST" "${BUILD_OUTPUT}/GRML/${GRML_NAME}-packages.txt"
1046           eend $?
1047        fi
1048
1049        # autostart for Windows:
1050        if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
1051           cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
1052        fi
1053
1054     FORCE_ISO_REBUILD=true
1055     einfo "Finished execution of stage 'boot'" ; eend 0
1056     fi
1057   fi # BOOTSTRAP_ONLY
1058 else
1059    log    'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
1060    eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
1061    bailout
1062 fi
1063
1064 # support installation of local files into the chroot/ISO
1065 if [ -n "$CHROOT_INSTALL" ] ; then
1066   if ! [ -d "$CHROOT_INSTALL" ] ; then
1067      log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1068      ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1069   else
1070      log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1071      einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1072      rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
1073      eend $?
1074      einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
1075      FORCE_ISO_REBUILD=true
1076   fi
1077 fi
1078
1079 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
1080    log   "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
1081    ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
1082 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
1083    log   "Skipping stage 'squashfs' as requested via option -q or -N"
1084    ewarn "Skipping stage 'squashfs' as requested via option -q or -N" ; eend 0
1085 else
1086    [ -d "$BUILD_OUTPUT"/live ] || mkdir "$BUILD_OUTPUT"/live
1087    # make sure we don't leave (even an empty) base.tgz:
1088    [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
1089
1090    # if unconfigured default to squashfs-tools' mksquashfs binary
1091    if [ -z "$SQUASHFS_BINARY" ] ; then
1092       SQUASHFS_BINARY='mksquashfs'
1093    fi
1094
1095    if which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
1096       log    "Using mksquashfs binary ${SQUASHFS_BINARY}"
1097       einfo  "Using mksquashfs binary ${SQUASHFS_BINARY}" ; eend 0
1098    else
1099       log    "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
1100       eerror "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
1101       bailout
1102    fi
1103
1104    # use sane defaults if $SQUASHFS_OPTIONS isn't set
1105    if [ -z "$SQUASHFS_OPTIONS" ] ; then
1106      # use blocksize 256k as this gives best result with regards to time + compression
1107      SQUASHFS_OPTIONS="-b 256k"
1108
1109      # set lzma/xz compression by default, unless -z option has been specified on command line
1110      if [ -z "$SQUASHFS_ZLIB" ] ; then
1111         SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp xz"
1112      else
1113         SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp gzip"
1114      fi
1115    fi
1116
1117    # support exclusion of files via exclude-file:
1118    if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
1119       SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE -wildcards"
1120    fi
1121
1122    # get rid of unnecessary files when building grml-small for final release:
1123    if echo "$CLASSES" | grep -q GRML_SMALL ; then
1124       SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
1125    fi
1126
1127    # log stuff
1128    SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
1129
1130    # informational stuff
1131    [ -n "$SQUASHFS_OPTIONS" ]  && SQUASHFS_INFO_MSG="$SQUASHFS_OPTIONS"
1132    [ -n "$SQUASHFS_INFO_MSG" ] && SQUASHFS_INFO_MSG="using options: $SQUASHFS_INFO_MSG"
1133    einfo "Squashfs build information: running binary $SQUASHFS_BINARY $SQUASHFS_INFO_MSG"
1134
1135    log "$SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS"
1136
1137    if $SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/"${GRML_NAME}".squashfs \
1138       -noappend $SQUASHFS_OPTIONS 2>"${SQUASHFS_STDERR}" ; then
1139       echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/filesystem.module
1140       log "Finished execution of stage 'squashfs' [$(date)]"
1141       einfo "Finished execution of stage 'squashfs'" ; eend 0
1142    else
1143       log    "Error: there was a critical error executing stage 'squashfs' [$(date)]:"
1144       log    "$(cat $SQUASHFS_STDERR)"
1145       eerror "Error: there was a critical error executing stage 'squashfs':"
1146       cat    "${SQUASHFS_STDERR}"
1147       eend 1
1148       bailout
1149    fi
1150
1151    FORCE_ISO_REBUILD=true
1152 fi
1153
1154 # create md5sum file:
1155 if [ -z "$BOOTSTRAP_ONLY" ] ; then
1156   ( cd $BUILD_OUTPUT/GRML &&
1157   find .. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
1158 fi
1159 # }}}
1160
1161 # ISO_OUTPUT - mkisofs {{{
1162 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
1163 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
1164
1165 if [ "$BOOT_METHOD" = "isolinux" ] ; then
1166    BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
1167 elif [ "$BOOT_METHOD" = "grub2" ] ; then
1168    BOOT_ARGS="-no-emul-boot -boot-load-size 4 -b boot/grub/toriboot.bin"
1169 fi
1170
1171 # Just until http://bts.grml.org/grml/issue945 has been resolved.
1172 # HYBRID_METHOD defaults to manifold, so make sure the default works OOTB.
1173 if [[ $BOOT_METHOD != isolinux && ($HYBRID_METHOD = isohybrid || $HYBRID_METHOD = manifold) ]]; then
1174   log   "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1175   ewarn "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1176   HYBRID_METHOD='grub2'
1177   eend 0
1178 fi
1179
1180 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ]  ; then
1181    log   "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already."
1182    ewarn "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already." ; eend 0
1183 elif [ -n "$SKIP_MKISOFS" ] ; then
1184    log   "Skipping stage 'iso build' as requested via option -n or -N"
1185    ewarn "Skipping stage 'iso build' as requested via option -n or -N" ; eend 0
1186 else
1187    mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
1188
1189    if $FORCE_ISO_REBUILD && ! [ -f "${ISO_OUTPUT}/${ISO_NAME}" ] ; then
1190       log   "Forcing rebuild of ISO because files on ISO have been modified."
1191       einfo "Forcing rebuild of ISO because files on ISO have been modified."
1192    fi
1193
1194    # support xorriso as well mkisofs and genisoimage
1195    if which xorriso >/dev/null 2>&1 ; then
1196       MKISOFS='xorriso -as mkisofs'
1197     elif which mkisofs >/dev/null 2>&1; then
1198       MKISOFS='mkisofs'
1199    elif which genisoimage >/dev/null 2>&1; then
1200       MKISOFS='genisoimage'
1201    else
1202       log    "Error: neither xorriso nor mkisofs nor genisoimage available - can not create ISO."
1203       eerror "Error: neither xorriso nor mkisofs nor genisoimage available - can not create ISO." ; eend 1
1204       bailout
1205    fi
1206
1207    case "$ARCH" in
1208      amd64)
1209        # using -eltorito-alt-boot is limited to xorriso for now
1210        case "$MKISOFS" in
1211          xorriso*)
1212            einfo "Using xorriso for ISO generation." ;  eend 0
1213            eindent
1214
1215            if ! dpkg --compare-versions $(dpkg-query -W -f='${Version}\n' xorriso 2>/dev/null) gt-nl 1.1.6-1 ; then
1216              log   "Disabling (U)EFI boot support since xorriso version is not recent enough."
1217              ewarn "Disabling (U)EFI boot support since xorriso version is not recent enough." ; eend 0
1218            else
1219              log   "xorriso with -eltorito-alt-boot present, enabling (U)EFI boot support."
1220              einfo "xorriso with -eltorito-alt-boot present, enabling (U)EFI boot support." ; eend 0
1221
1222              if [ -r "${CHROOT_OUTPUT}/var/lib/grml_live_efi.img" ] ; then
1223                einfo "Found /var/lib/grml_live_efi.img - moving to /boot/efi.img for ISO."
1224                log   "Found /var/lib/grml_live_efi.img - moving to /boot/efi.img for ISO."
1225                mv "${CHROOT_OUTPUT}/var/lib/grml_live_efi.img" "${BUILD_OUTPUT}/boot/efi.img"
1226                eend $?
1227              fi
1228
1229              if [ -r "${CHROOT_OUTPUT}/var/lib/grml_live_bootx64.efi" ] ; then
1230                einfo "Found /var/lib/grml_live_bootx64.efi - moving to /efi/boot/bootx64.efi for ISO"
1231                log   "Found /var/lib/grml_live_bootx64.efi - moving to /efi/boot/bootx64.efi for ISO"
1232                mkdir -p "${BUILD_OUTPUT}/efi/boot/"
1233                mv "${CHROOT_OUTPUT}/var/lib/grml_live_bootx64.efi" "${BUILD_OUTPUT}/efi/boot/bootx64.efi"
1234                eend $?
1235              fi
1236
1237              if [ -r "${BUILD_OUTPUT}"/boot/efi.img ] ; then
1238                einfo "/boot/efi.img found and amd64 architecture present, extending boot arguments."
1239                log   "/boot/efi.img found and amd64 architecture present, extending boot arguments."
1240                BOOT_ARGS="$BOOT_ARGS -boot-info-table -eltorito-alt-boot -e boot/efi.img -no-emul-boot"
1241                eend $?
1242              fi
1243            fi
1244
1245            eoutdent
1246            ;;
1247        esac
1248        ;;
1249    esac
1250
1251    CURRENT_DIR=$(pwd)
1252    if cd "$BUILD_OUTPUT" ; then
1253       if [ "$BOOT_METHOD" = "grub2" ]; then
1254          # make a 2048-byte bootsector for El Torito
1255          dd if=/dev/zero of=boot/grub/toriboot.bin bs=512 count=4 2>/dev/null
1256          # those are in 2048-byte sectors, so 1 16 matches 4 63 below
1257          echo 1 16 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -B 11 | \
1258             dd of=boot/grub/toriboot.bin conv=notrunc 2>/dev/null
1259       fi
1260       log "$MKISOFS -V '${GRML_NAME} ${VERSION}' -publisher 'grml-live | grml.org' -l -r -J $BOOT_ARGS -o ${ISO_OUTPUT}/${ISO_NAME} ."
1261       $MKISOFS -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
1262               -l -r -J $BOOT_ARGS -no-pad \
1263               -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
1264       # both of these need core.img there, so it’s easier to write it here
1265       if [ "$BOOT_METHOD" = "grub2" ] || [ "$HYBRID_METHOD" = "grub2" ]; then
1266          # must be <= 30720 bytes
1267          dd if=boot/grub/core.img of="${ISO_OUTPUT}/${ISO_NAME}" \
1268            conv=notrunc bs=512 seek=4 2>/dev/null
1269       fi
1270
1271       # pad the output ISO to multiples of 256 KiB for partition table support
1272       siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
1273       cyls=$((siz / 512 / 32 / 16 + 1))   # C=$cyls H=16 S=32
1274       siz=$((cyls * 16 * 32 * 512))   # size after padding
1275       dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
1276          of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
1277
1278       # support disabling hybrid ISO image
1279       if [ "$HYBRID_METHOD" = "disable" ] ; then\
1280          log   "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1281          einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1282          eend 0
1283       elif [ "$HYBRID_METHOD" = "manifold" ] ; then
1284          # isoinfo is part of both mkisofs and genisoimage so we're good
1285          bootoff=$(isoinfo -l -i "${ISO_OUTPUT}/${ISO_NAME}" | \
1286            sed -n '/^.*\[ *\([0-9]*\)[] ].* ISOLINUX.BIN[;1]* *$/s//\1/p')
1287          if ! [ -r boot/grub/core.img ] ; then
1288            ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
1289          elif [ "${bootoff:-0}" -lt 1 ] ; then
1290            ewarn "isolinux.bin not found on the ISO file, disabling manifold boot"
1291          else
1292            log "Creating hybrid ISO file with manifold method"
1293            einfo "Creating hybrid ISO file with manifold method"
1294            if [ "$HYBRID_METHOD" = "grub2" ] ; then
1295                # 512 bytes: MBR, partition table, load GRUB 2
1296                echo 4 63 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 4:0x96 -g $cyls:16:32
1297            else
1298               # read only one but 2048-byte sized (scale: << 2) sector
1299               echo $bootoff $bootoff | \
1300                  mksh /usr/share/grml-live/scripts/bootilnx.mksh -A -M 4:0x96 -g $cyls:16:32 -S 2
1301            fi | dd of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
1302            eend $?
1303          fi
1304       # use isohybrid as default
1305       else
1306          if ! which isohybrid >/dev/null 2>&1 ; then
1307            bailout 12 "isohybrid binary not found - please install syslinux/syslinux-common"
1308          else
1309            log   "Creating hybrid ISO file with isohybrid method"
1310            einfo "Creating hybrid ISO file with isohybrid method"
1311            # Notes for consideration:
1312            # "-entry 4 -type 1c"
1313            # * using 4 as the partition number is supposed to help with BIOSes
1314            #   that only support USB-Zip boot
1315            # * using 1c (i.e. hidden FAT32 LBA), instead of the default 0x17
1316            #   (hidden NTFS, IIRC), as the partition type is sometimes needed
1317            #   to get the BIOS even look at the partition created by isohybrid
1318            if isohybrid --help | grep -q -- --uefi ; then
1319              einfo "Detected uefi support for isohybrid, enabling."
1320              ISOHYBRID_OPTIONS=--uefi
1321            fi
1322
1323            log "isohybrid $ISOHYBRID_OPTIONS ${ISO_OUTPUT}/${ISO_NAME}"
1324            isohybrid $ISOHYBRID_OPTIONS "${ISO_OUTPUT}/${ISO_NAME}"
1325            eend $?
1326          fi
1327       fi
1328
1329       # generate md5sum and sha1sum of ISO if we are using class 'RELEASE':
1330       case $CLASSES in *RELEASE*)
1331          [ "$RC" = 0 ] && \
1332          (
1333            if cd $ISO_OUTPUT ; then
1334              md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
1335              touch -r ${ISO_NAME} ${ISO_NAME}.md5
1336              sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
1337              touch -r ${ISO_NAME} ${ISO_NAME}.sha1
1338            fi
1339          )
1340          ;;
1341       esac
1342
1343       cd "$CURRENT_DIR"
1344    fi
1345
1346    if [ "$RC" = 0 ] ; then
1347       log   "Finished execution of stage 'iso build' [$(date)]"
1348       einfo "Finished execution of stage 'iso build'" ; eend 0
1349    else
1350       log    "Error: there was a critical error ($RC) executing stage 'iso build' [$(date)]"
1351       eerror "Error: there was a critical error executing stage 'iso build'" ; eend 1
1352       bailout $RC
1353    fi
1354 fi
1355 # }}}
1356
1357 # netboot package {{{
1358 create_netbootpackage() {
1359   local OUTPUT_FILE="${NETBOOT}/grml_netboot_package_${GRML_NAME}_${VERSION}.tar.bz2"
1360
1361   if [ -f "${OUTPUT_FILE}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
1362     log   "Skipping stage 'netboot' as $OUTPUT_FILE exists already."
1363     ewarn "Skipping stage 'netboot' as $OUTPUT_FILE exists already." ; eend 0
1364     return 0
1365   elif [ -n "$SKIP_NETBOOT" ] ; then
1366     log   "Skipping stage 'netboot' as requested via option -Q"
1367     ewarn "Skipping stage 'netboot' as requested via option -Q" ; eend 0
1368     return 0
1369   fi
1370
1371   mkdir -p "$NETBOOT"
1372
1373   if ! [ -r "${CHROOT}/usr/lib/syslinux/pxelinux.0" ] ; then
1374     ewarn "File /usr/lib/syslinux/pxelinux.0 not found in build chroot." ; eend 0
1375     eindent
1376     einfo "Install syslinux[-common] package in chroot to get a netboot package."
1377     eoutdent
1378     return 0
1379   fi
1380
1381   local OUTPUTDIR="${NETBOOT}/build_tmp"
1382   local WORKING_DIR="${OUTPUTDIR}/grml_netboot_package_${GRML_NAME}_${VERSION}/tftpboot/"
1383
1384   mkdir -p "$WORKING_DIR"
1385
1386   cp "${CHROOT_OUTPUT}"/boot/vmlinuz-*    "$WORKING_DIR"/vmlinuz
1387   cp "${CHROOT_OUTPUT}"/boot/initrd.img-* "$WORKING_DIR"/initrd.img
1388   cp "${CHROOT_OUTPUT}"/usr/lib/syslinux/pxelinux.0 "${WORKING_DIR}/pxelinux.0"
1389
1390   mkdir -p "${WORKING_DIR}/pxelinux.cfg"
1391   if [ -r "${BUILD_OUTPUT}/boot/isolinux/netboot.cfg" ] ; then
1392     cp "${BUILD_OUTPUT}/boot/isolinux/netboot.cfg" "${WORKING_DIR}/pxelinux.cfg/default"
1393   else
1394     ewarn "File ${BUILD_OUTPUT}/boot/isolinux/netboot.cfg not found." ; eend 0
1395   fi
1396
1397   if tar -C "$OUTPUTDIR" -jcf "${OUTPUT_FILE}" "grml_netboot_package_${GRML_NAME}_${VERSION}" ; then
1398     sha1sum "${OUTPUT_FILE}" > "${OUTPUT_FILE}.sha1"
1399     einfo "Generated netboot package ${OUTPUT_FILE}" ; eend 0
1400     rm -rf "${OUTPUTDIR}"
1401   else
1402     rm -rf "${OUTPUTDIR}"
1403     eerror "Could not generate netboot package ${OUTPUT_FILE}" ; eend 1
1404     bailout 21
1405   fi
1406 }
1407
1408 create_netbootpackage
1409 # }}}
1410
1411 # log build information to database if grml-live-db is installed and enabled {{{
1412 dpkg_to_db() {
1413 if [ -d /usr/share/grml-live-db ] ; then
1414
1415   # safe defaults
1416   DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot:
1417   [ -n "$DPKG_DATABASE" ]  || DPKG_DATABASE=/var/log/grml-live.db
1418   [ -n "$DPKG_DBSCRIPT" ]  || DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
1419   [ -n "$DPKG_DBOPTIONS" ] || DPKG_DBOPTIONS="--database $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME --dpkg $DPKG_LIST"
1420
1421   if ! [ -x "$DPKG_DBSCRIPT" ] ; then
1422     log "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information."
1423     eerror "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information." ; eend 1
1424     bailout 14
1425   fi
1426
1427   # disable by default for now, not sure whether really everyone is using a local db file
1428   #if ! touch "$DPKG_DATABASE" ; then
1429   #  eerror "Error: can not write to ${DPKG_DATABASE}, can not log dpkg information." ; eend 1
1430   #  bailout 14
1431   #fi
1432
1433   if ! [ -r "$DPKG_LIST" ] ; then
1434      log   "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)"
1435      ewarn "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)" ; eend 0
1436   else
1437      einfo "Logging $DPKG_LIST to database $DPKG_DATABASE"
1438      log "Logging $DPKG_LIST to database $DPKG_DATABASE"
1439      log "Executing $DPKG_DBSCRIPT $DPKG_DBOPTIONS"
1440      eindent
1441
1442      if DB_INFO=$("$DPKG_DBSCRIPT" $DPKG_DBOPTIONS 2>&1) ; then
1443        einfo "$DB_INFO"
1444        eend 0
1445      else
1446        eerror "$DB_INFO"
1447        eend 1
1448      fi
1449
1450      eoutdent
1451   fi
1452
1453 fi
1454 }
1455 # }}}
1456
1457 # finalize {{{
1458 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
1459 log "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]"
1460
1461 dpkg_to_db # make sure we catch the last log line as well, therefore execute between log + einfo
1462
1463 einfo "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]" ; eend 0
1464 bailout 0
1465 # }}}
1466
1467 ## END OF FILE #################################################################
1468 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=2