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