Shorten, but don't totally rename kernel and initrd files
[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 ${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        # adjust bootsplash accordingly but make sure the string has the according lenght
955        SQUASHFS_NAME="$(cut_string 20 "$SQUASHFS_NAME")"
956        SQUASHFS_NAME="$(extend_string_end 20 "$SQUASHFS_NAME")"
957        for file in f4 f5 ; do
958           if [ -r "${BUILD_OUTPUT}/boot/isolinux/${file}" ] ; then
959              sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
960              sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
961           fi
962        done
963
964        # generate addon list
965        rm -f "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
966        for name in "${BUILD_OUTPUT}"/boot/isolinux/addon_*.cfg ; do
967          include_name=$(basename "$name")
968          echo "include $include_name"  >> "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
969        done
970
971        if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
972           log "including grmlmain.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
973           echo "include grmlmain.cfg"    >  "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
974           echo "include default.cfg"     >  "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
975           echo "include menuoptions.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
976           echo "include grml.cfg"        >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
977
978           for f in "${BUILD_OUTPUT}"/boot/isolinux/submenu*.cfg ; do
979             echo "include $(basename $f)"     >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
980           done
981
982           echo "include options.cfg"     >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
983           if [ ! -n "$NO_ADDONS" ] ; then
984             echo "include addons.cfg"    >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
985           fi
986           echo "include isoprompt.cfg"   >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
987           echo "include hd.cfg"          >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
988           echo "include hidden.cfg"      >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
989        else # assume we are building a custom distribution:
990           log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
991           einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
992           if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
993             log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
994             eindent
995             einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
996             eoutdent
997             eend $?
998          else
999             log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1000             echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1001             [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1002           fi
1003        fi
1004
1005        # use old style console based isolinux method only if requested:
1006        if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
1007           log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
1008           einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
1009           if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
1010             einfo "include for console.cfg already found, nothing to do."
1011             eend 0
1012           else
1013             log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1014             einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1015             echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1016             eend $?
1017           fi
1018        else
1019           log 'Using graphical boot menu.'
1020           if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
1021             log "include for vesamenu.cfg already found, nothing to do."
1022           else
1023             log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1024             echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1025           fi
1026        fi
1027
1028        if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
1029           sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
1030        fi
1031
1032        DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot
1033        if ! [ -r "$DPKG_LIST" ] ; then
1034           ewarn "$DPKG_LIST could not be read, ignoring to store package information on ISO therefore."
1035        else
1036           einfo "Storing package list information as /GRML/${GRML_NAME}-packages.txt on ISO."
1037           cp "$DPKG_LIST" "${BUILD_OUTPUT}/GRML/${GRML_NAME}-packages.txt"
1038           eend $?
1039        fi
1040
1041        # autostart for Windows:
1042        if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
1043           cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
1044        fi
1045
1046     FORCE_ISO_REBUILD=true
1047     einfo "Finished execution of stage 'boot'" ; eend 0
1048     fi
1049   fi # BOOTSTRAP_ONLY
1050 else
1051    log    'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
1052    eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
1053    bailout
1054 fi
1055
1056 # support installation of local files into the chroot/ISO
1057 if [ -n "$CHROOT_INSTALL" ] ; then
1058   if ! [ -d "$CHROOT_INSTALL" ] ; then
1059      log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1060      ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1061   else
1062      log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1063      einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1064      rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
1065      eend $?
1066      einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
1067      FORCE_ISO_REBUILD=true
1068   fi
1069 fi
1070
1071 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
1072    log   "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
1073    ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
1074 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
1075    log   "Skipping stage 'squashfs' as requested via option -q or -N"
1076    ewarn "Skipping stage 'squashfs' as requested via option -q or -N" ; eend 0
1077 else
1078    [ -d "$BUILD_OUTPUT"/live ] || mkdir "$BUILD_OUTPUT"/live
1079    # make sure we don't leave (even an empty) base.tgz:
1080    [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
1081
1082    # if unconfigured default to squashfs-tools' mksquashfs binary
1083    if [ -z "$SQUASHFS_BINARY" ] ; then
1084       SQUASHFS_BINARY='mksquashfs'
1085    fi
1086
1087    if which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
1088       log    "Using mksquashfs binary ${SQUASHFS_BINARY}"
1089       einfo  "Using mksquashfs binary ${SQUASHFS_BINARY}" ; eend 0
1090    else
1091       log    "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
1092       eerror "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
1093       bailout
1094    fi
1095
1096    # use sane defaults if $SQUASHFS_OPTIONS isn't set
1097    if [ -z "$SQUASHFS_OPTIONS" ] ; then
1098      # use blocksize 256k as this gives best result with regards to time + compression
1099      SQUASHFS_OPTIONS="-b 256k"
1100
1101      # set lzma/xz compression by default, unless -z option has been specified on command line
1102      if [ -z "$SQUASHFS_ZLIB" ] ; then
1103         SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp xz"
1104      else
1105         SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp gzip"
1106      fi
1107    fi
1108
1109    # support exclusion of files via exclude-file:
1110    if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
1111       SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE -wildcards"
1112    fi
1113
1114    # get rid of unnecessary files when building grml-small for final release:
1115    if echo "$CLASSES" | grep -q GRML_SMALL ; then
1116       SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
1117    fi
1118
1119    # log stuff
1120    SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
1121
1122    # informational stuff
1123    [ -n "$SQUASHFS_OPTIONS" ]  && SQUASHFS_INFO_MSG="$SQUASHFS_OPTIONS"
1124    [ -n "$SQUASHFS_INFO_MSG" ] && SQUASHFS_INFO_MSG="using options: $SQUASHFS_INFO_MSG"
1125    einfo "Squashfs build information: running binary $SQUASHFS_BINARY $SQUASHFS_INFO_MSG"
1126
1127    log "$SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS"
1128
1129    if $SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/"${GRML_NAME}".squashfs \
1130       -noappend $SQUASHFS_OPTIONS 2>"${SQUASHFS_STDERR}" ; then
1131       echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/filesystem.module
1132       log "Finished execution of stage 'squashfs' [$(date)]"
1133       einfo "Finished execution of stage 'squashfs'" ; eend 0
1134    else
1135       log    "Error: there was a critical error executing stage 'squashfs' [$(date)]:"
1136       log    "$(cat $SQUASHFS_STDERR)"
1137       eerror "Error: there was a critical error executing stage 'squashfs':"
1138       cat    "${SQUASHFS_STDERR}"
1139       eend 1
1140       bailout
1141    fi
1142
1143    FORCE_ISO_REBUILD=true
1144 fi
1145
1146 # create md5sum file:
1147 if [ -z "$BOOTSTRAP_ONLY" ] ; then
1148   ( cd $BUILD_OUTPUT/GRML &&
1149   find .. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
1150 fi
1151 # }}}
1152
1153 # ISO_OUTPUT - mkisofs {{{
1154 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
1155 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
1156
1157 if [ "$BOOT_METHOD" = "isolinux" ] ; then
1158    BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
1159 elif [ "$BOOT_METHOD" = "grub2" ] ; then
1160    BOOT_ARGS="-no-emul-boot -boot-load-size 4 -b boot/grub/toriboot.bin"
1161 fi
1162
1163 # Just until http://bts.grml.org/grml/issue945 has been resolved.
1164 # HYBRID_METHOD defaults to manifold, so make sure the default works OOTB.
1165 if [[ $BOOT_METHOD != isolinux && ($HYBRID_METHOD = isohybrid || $HYBRID_METHOD = manifold) ]]; then
1166   log   "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1167   ewarn "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1168   HYBRID_METHOD='grub2'
1169   eend 0
1170 fi
1171
1172 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ]  ; then
1173    log   "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already."
1174    ewarn "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already." ; eend 0
1175 elif [ -n "$SKIP_MKISOFS" ] ; then
1176    log   "Skipping stage 'iso build' as requested via option -n or -N"
1177    ewarn "Skipping stage 'iso build' as requested via option -n or -N" ; eend 0
1178 else
1179    mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
1180
1181    if $FORCE_ISO_REBUILD && ! [ -f "${ISO_OUTPUT}/${ISO_NAME}" ] ; then
1182       log   "Forcing rebuild of ISO because files on ISO have been modified."
1183       einfo "Forcing rebuild of ISO because files on ISO have been modified."
1184    fi
1185
1186    # support xorriso as well mkisofs and genisoimage
1187    if which xorriso >/dev/null 2>&1 ; then
1188       MKISOFS='xorriso -as mkisofs'
1189     elif which mkisofs >/dev/null 2>&1; then
1190       MKISOFS='mkisofs'
1191    elif which genisoimage >/dev/null 2>&1; then
1192       MKISOFS='genisoimage'
1193    else
1194       log    "Error: neither xorriso nor mkisofs nor genisoimage available - can not create ISO."
1195       eerror "Error: neither xorriso nor mkisofs nor genisoimage available - can not create ISO." ; eend 1
1196       bailout
1197    fi
1198
1199    case "$ARCH" in
1200      amd64)
1201        # using -eltorito-alt-boot is limited to xorriso for now
1202        case "$MKISOFS" in
1203          xorriso*)
1204            einfo "Using xorriso for ISO generation." ;  eend 0
1205            eindent
1206
1207            if ! dpkg --compare-versions $(dpkg-query -W -f='${Version}\n' xorriso 2>/dev/null) gt-nl 1.1.6-1 ; then
1208              log   "Disabling (U)EFI boot support since xorriso version is not recent enough."
1209              ewarn "Disabling (U)EFI boot support since xorriso version is not recent enough." ; eend 0
1210            else
1211              log   "xorriso with -eltorito-alt-boot present, enabling (U)EFI boot support."
1212              einfo "xorriso with -eltorito-alt-boot present, enabling (U)EFI boot support." ; eend 0
1213
1214              if [ -r "${CHROOT_OUTPUT}/var/lib/grml_live_efi.img" ] ; then
1215                einfo "Found /var/lib/grml_live_efi.img - moving to /boot/efi.img for ISO."
1216                log   "Found /var/lib/grml_live_efi.img - moving to /boot/efi.img for ISO."
1217                mv "${CHROOT_OUTPUT}/var/lib/grml_live_efi.img" "${BUILD_OUTPUT}/boot/efi.img"
1218                eend $?
1219              fi
1220
1221              if [ -r "${CHROOT_OUTPUT}/var/lib/grml_live_bootx64.efi" ] ; then
1222                einfo "Found /var/lib/grml_live_bootx64.efi - moving to /efi/boot/bootx64.efi for ISO"
1223                log   "Found /var/lib/grml_live_bootx64.efi - moving to /efi/boot/bootx64.efi for ISO"
1224                mkdir -p "${BUILD_OUTPUT}/efi/boot/"
1225                mv "${CHROOT_OUTPUT}/var/lib/grml_live_bootx64.efi" "${BUILD_OUTPUT}/efi/boot/bootx64.efi"
1226                eend $?
1227              fi
1228
1229              if [ -r "${BUILD_OUTPUT}"/boot/efi.img ] ; then
1230                einfo "/boot/efi.img found and amd64 architecture present, extending boot arguments."
1231                log   "/boot/efi.img found and amd64 architecture present, extending boot arguments."
1232                BOOT_ARGS="$BOOT_ARGS -boot-info-table -eltorito-alt-boot -e boot/efi.img -no-emul-boot"
1233                eend $?
1234              fi
1235            fi
1236
1237            eoutdent
1238            ;;
1239        esac
1240        ;;
1241    esac
1242
1243    CURRENT_DIR=$(pwd)
1244    if cd "$BUILD_OUTPUT" ; then
1245       if [ "$BOOT_METHOD" = "grub2" ]; then
1246          # make a 2048-byte bootsector for El Torito
1247          dd if=/dev/zero of=boot/grub/toriboot.bin bs=512 count=4 2>/dev/null
1248          # those are in 2048-byte sectors, so 1 16 matches 4 63 below
1249          echo 1 16 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -B 11 | \
1250             dd of=boot/grub/toriboot.bin conv=notrunc 2>/dev/null
1251       fi
1252       log "$MKISOFS -V '${GRML_NAME} ${VERSION}' -publisher 'grml-live | grml.org' -l -r -J $BOOT_ARGS -o ${ISO_OUTPUT}/${ISO_NAME} ."
1253       $MKISOFS -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
1254               -l -r -J $BOOT_ARGS -no-pad \
1255               -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
1256       # both of these need core.img there, so it’s easier to write it here
1257       if [ "$BOOT_METHOD" = "grub2" ] || [ "$HYBRID_METHOD" = "grub2" ]; then
1258          # must be <= 30720 bytes
1259          dd if=boot/grub/core.img of="${ISO_OUTPUT}/${ISO_NAME}" \
1260            conv=notrunc bs=512 seek=4 2>/dev/null
1261       fi
1262
1263       # pad the output ISO to multiples of 256 KiB for partition table support
1264       siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
1265       cyls=$((siz / 512 / 32 / 16 + 1))   # C=$cyls H=16 S=32
1266       siz=$((cyls * 16 * 32 * 512))   # size after padding
1267       dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
1268          of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
1269
1270       # support disabling hybrid ISO image
1271       if [ "$HYBRID_METHOD" = "disable" ] ; then\
1272          log   "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1273          einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1274          eend 0
1275       elif [ "$HYBRID_METHOD" = "manifold" ] ; then
1276          # isoinfo is part of both mkisofs and genisoimage so we're good
1277          bootoff=$(isoinfo -l -i "${ISO_OUTPUT}/${ISO_NAME}" | \
1278            sed -n '/^.*\[ *\([0-9]*\)[] ].* ISOLINUX.BIN[;1]* *$/s//\1/p')
1279          if ! [ -r boot/grub/core.img ] ; then
1280            ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
1281          elif [ "${bootoff:-0}" -lt 1 ] ; then
1282            ewarn "isolinux.bin not found on the ISO file, disabling manifold boot"
1283          else
1284            log "Creating hybrid ISO file with manifold method"
1285            einfo "Creating hybrid ISO file with manifold method"
1286            if [ "$HYBRID_METHOD" = "grub2" ] ; then
1287                # 512 bytes: MBR, partition table, load GRUB 2
1288                echo 4 63 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 4:0x96 -g $cyls:16:32
1289            else
1290               # read only one but 2048-byte sized (scale: << 2) sector
1291               echo $bootoff $bootoff | \
1292                  mksh /usr/share/grml-live/scripts/bootilnx.mksh -A -M 4:0x96 -g $cyls:16:32 -S 2
1293            fi | dd of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
1294            eend $?
1295          fi
1296       # use isohybrid as default
1297       else
1298          if ! which isohybrid >/dev/null 2>&1 ; then
1299            bailout 12 "isohybrid binary not found - please install syslinux/syslinux-common"
1300          else
1301            log   "Creating hybrid ISO file with isohybrid method"
1302            einfo "Creating hybrid ISO file with isohybrid method"
1303            # Notes for consideration:
1304            # "-entry 4 -type 1c"
1305            # * using 4 as the partition number is supposed to help with BIOSes
1306            #   that only support USB-Zip boot
1307            # * using 1c (i.e. hidden FAT32 LBA), instead of the default 0x17
1308            #   (hidden NTFS, IIRC), as the partition type is sometimes needed
1309            #   to get the BIOS even look at the partition created by isohybrid
1310            if isohybrid --help | grep -q -- --uefi ; then
1311              einfo "Detected uefi support for isohybrid, enabling."
1312              ISOHYBRID_OPTIONS=--uefi
1313            fi
1314
1315            log "isohybrid $ISOHYBRID_OPTIONS ${ISO_OUTPUT}/${ISO_NAME}"
1316            isohybrid $ISOHYBRID_OPTIONS "${ISO_OUTPUT}/${ISO_NAME}"
1317            eend $?
1318          fi
1319       fi
1320
1321       # generate md5sum and sha1sum of ISO if we are using class 'RELEASE':
1322       case $CLASSES in *RELEASE*)
1323          [ "$RC" = 0 ] && \
1324          (
1325            if cd $ISO_OUTPUT ; then
1326              md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
1327              touch -r ${ISO_NAME} ${ISO_NAME}.md5
1328              sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
1329              touch -r ${ISO_NAME} ${ISO_NAME}.sha1
1330            fi
1331          )
1332          ;;
1333       esac
1334
1335       cd "$CURRENT_DIR"
1336    fi
1337
1338    if [ "$RC" = 0 ] ; then
1339       log   "Finished execution of stage 'iso build' [$(date)]"
1340       einfo "Finished execution of stage 'iso build'" ; eend 0
1341    else
1342       log    "Error: there was a critical error ($RC) executing stage 'iso build' [$(date)]"
1343       eerror "Error: there was a critical error executing stage 'iso build'" ; eend 1
1344       bailout $RC
1345    fi
1346 fi
1347 # }}}
1348
1349 # netboot package {{{
1350 create_netbootpackage() {
1351   local OUTPUT_FILE="${NETBOOT}/grml_netboot_package_${GRML_NAME}_${VERSION}.tar.bz2"
1352
1353   if [ -f "${OUTPUT_FILE}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
1354     log   "Skipping stage 'netboot' as $OUTPUT_FILE exists already."
1355     ewarn "Skipping stage 'netboot' as $OUTPUT_FILE exists already." ; eend 0
1356     return 0
1357   elif [ -n "$SKIP_NETBOOT" ] ; then
1358     log   "Skipping stage 'netboot' as requested via option -Q"
1359     ewarn "Skipping stage 'netboot' as requested via option -Q" ; eend 0
1360     return 0
1361   fi
1362
1363   mkdir -p "$NETBOOT"
1364
1365   if ! [ -r "${CHROOT}/usr/lib/syslinux/pxelinux.0" ] ; then
1366     ewarn "File /usr/lib/syslinux/pxelinux.0 not found in build chroot." ; eend 0
1367     eindent
1368     einfo "Install syslinux[-common] package in chroot to get a netboot package."
1369     eoutdent
1370     return 0
1371   fi
1372
1373   local OUTPUTDIR="${NETBOOT}/build_tmp"
1374   local WORKING_DIR="${OUTPUTDIR}/grml_netboot_package_${GRML_NAME}_${VERSION}/tftpboot/"
1375
1376   mkdir -p "$WORKING_DIR"
1377
1378   cp "${CHROOT_OUTPUT}"/boot/vmlinuz-*    "$WORKING_DIR"/vmlinuz
1379   cp "${CHROOT_OUTPUT}"/boot/initrd.img-* "$WORKING_DIR"/initrd.img
1380   cp "${CHROOT_OUTPUT}"/usr/lib/syslinux/pxelinux.0 "${WORKING_DIR}/pxelinux.0"
1381
1382   if [ -r "${BUILD_OUTPUT}/boot/isolinux/netboot.cfg" ] ; then
1383     mkdir -p "${WORKING_DIR}/pxelinux.cfg/default"
1384     cp "${BUILD_OUTPUT}/boot/isolinux/netboot.cfg" "${WORKING_DIR}/pxelinux.cfg/default"
1385   else
1386     ewarn "File ${BUILD_OUTPUT}/boot/isolinux/netboot.cfg not found." ; eend 0
1387   fi
1388
1389   mkdir -p "${WORKING_DIR}/pxelinux.cfg"
1390
1391   if tar -C "$OUTPUTDIR" -jcf "${OUTPUT_FILE}" "grml_netboot_package_${GRML_NAME}_${VERSION}" ; then
1392     sha1sum "${OUTPUT_FILE}" > "${OUTPUT_FILE}.sha1"
1393     einfo "Generated netboot package ${OUTPUT_FILE}" ; eend 0
1394     rm -rf "${OUTPUTDIR}"
1395   else
1396     rm -rf "${OUTPUTDIR}"
1397     eerror "Could not generate netboot package ${OUTPUT_FILE}" ; eend 1
1398     bailout 21
1399   fi
1400 }
1401
1402 create_netbootpackage
1403 # }}}
1404
1405 # log build information to database if grml-live-db is installed and enabled {{{
1406 dpkg_to_db() {
1407 if [ -d /usr/share/grml-live-db ] ; then
1408
1409   # safe defaults
1410   DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot:
1411   [ -n "$DPKG_DATABASE" ]  || DPKG_DATABASE=/var/log/grml-live.db
1412   [ -n "$DPKG_DBSCRIPT" ]  || DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
1413   [ -n "$DPKG_DBOPTIONS" ] || DPKG_DBOPTIONS="--database $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME --dpkg $DPKG_LIST"
1414
1415   if ! [ -x "$DPKG_DBSCRIPT" ] ; then
1416     log "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information."
1417     eerror "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information." ; eend 1
1418     bailout 14
1419   fi
1420
1421   # disable by default for now, not sure whether really everyone is using a local db file
1422   #if ! touch "$DPKG_DATABASE" ; then
1423   #  eerror "Error: can not write to ${DPKG_DATABASE}, can not log dpkg information." ; eend 1
1424   #  bailout 14
1425   #fi
1426
1427   if ! [ -r "$DPKG_LIST" ] ; then
1428      log   "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)"
1429      ewarn "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)" ; eend 0
1430   else
1431      einfo "Logging $DPKG_LIST to database $DPKG_DATABASE"
1432      log "Logging $DPKG_LIST to database $DPKG_DATABASE"
1433      log "Executing $DPKG_DBSCRIPT $DPKG_DBOPTIONS"
1434      eindent
1435
1436      if DB_INFO=$("$DPKG_DBSCRIPT" $DPKG_DBOPTIONS 2>&1) ; then
1437        einfo "$DB_INFO"
1438        eend 0
1439      else
1440        eerror "$DB_INFO"
1441        eend 1
1442      fi
1443
1444      eoutdent
1445   fi
1446
1447 fi
1448 }
1449 # }}}
1450
1451 # finalize {{{
1452 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
1453 log "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]"
1454
1455 dpkg_to_db # make sure we catch the last log line as well, therefore execute between log + einfo
1456
1457 einfo "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]" ; eend 0
1458 bailout 0
1459 # }}}
1460
1461 ## END OF FILE #################################################################
1462 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=2