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