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