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