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