1e8ddadd4dc2eed7151017e28a1c922067991707
[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   echo $RC
521   if [ "$RC" != 0 ] ; then
522     eend 1
523     bailout 1
524   fi
525   eend 0
526 fi
527 # }}}
528
529 # cleanup CHROOT_ARCHIVE now {{{
530 if [ -n "${PACK_ARTIFACTS}" ]; then
531   # can't do this earlier, as UNPACK_CHROOT might point to CHROOT_ARCHIVE
532   [ -n "${CHROOT_ARCHIVE}" -a -f "${CHROOT_ARCHIVE}" ] && rm "${CHROOT_ARCHIVE}"
533 fi
534 # }}}
535
536 # on-the-fly configuration {{{
537 if [ -n "$FAI_DEBOOTSTRAP" ] ; then
538   sed "s#^FAI_DEBOOTSTRAP=.*#FAI_DEBOOTSTRAP=\"$FAI_DEBOOTSTRAP\"#" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
539 fi
540
541 # does this suck? YES!
542 # /usr/share/debootstrap/scripts/unstable does not exist, instead use 'sid':
543 case $SUITE in
544    unstable) SUITE='sid' ; CLASSES="DEBIAN_UNSTABLE,$CLASSES" ;;
545    *) CLASSES="DEBIAN_$(echo $SUITE | tr 'a-z' 'A-Z'),$CLASSES";;
546 esac
547 export SUITE # make sure it's available in FAI scripts
548
549 for file in "$LIVE_CONF" "$GRML_LIVE_LOCAL_CONFIG" "$NFSROOT_CONF" ; do
550     if [ -n "$file" ] ; then
551        sed "s|^FAI_DEBOOTSTRAP=\"[a-z]* |FAI_DEBOOTSTRAP=\"$SUITE |" "$file" | sponge "$file"
552     fi
553 done
554
555 # validate whether the specified architecture class matches the
556 # architecture (option), otherwise installation of kernel will fail
557 if echo $CLASSES | grep -qi i386 ; then
558    if ! [[ "$ARCH" == "i386" ]] ; then
559       log    "Error: You specified the I386 class but are trying to build something else (AMD64?)."
560       eerror "Error: You specified the I386 class but are trying to build something else (AMD64?)."
561       eerror "Tip:   Either invoke grml-live with '-a i386' or adjust the architecture class. Exiting."
562       eend 1
563       bailout
564    fi
565 elif echo $CLASSES | grep -qi amd64 ; then
566    if ! [[ "$ARCH" == "amd64" ]] ; then
567       log    "Error: You specified the AMD64 class but are trying to build something else (I386?)."
568       eerror "Error: You specified the AMD64 class but are trying to build something else (I386?)."
569       eerror "Tip:   Either invoke grml-live with '-a amd64' or adjust the architecture class. Exiting."
570       eend 1
571       bailout
572    fi
573 fi
574
575 if grep -q -- 'FAI_DEBOOTSTRAP_OPTS.*--arch' "$NFSROOT_CONF" ; then
576    sed "s/--arch [a-z0-9]* /--arch $ARCH /" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
577 else
578    sed "s|^FAI_DEBOOTSTRAP_OPTS=\"\(.*\)|FAI_DEBOOTSTRAP_OPTS=\"--arch $ARCH \1|" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
579 fi
580 # }}}
581
582 # CHROOT_OUTPUT - execute FAI {{{
583 if [ -n "$BUILD_DIRTY" ]; then
584    log   "Skipping stage 'fai' as requested via option -B"
585    ewarn "Skipping stage 'fai' as requested via option -B" ; eend 0
586 else
587    [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
588
589    # provide inform fai about the ISO we build
590    [ -d "$CHROOT_OUTPUT/etc/" ] || mkdir -p "$CHROOT_OUTPUT/etc/"
591    echo '# This file has been generated by grml-live.' > "$CHROOT_OUTPUT/etc/grml_live_version"
592    [ -n "$GRML_LIVE_VERSION" ] && echo "GRML_LIVE_VERSION=$GRML_LIVE_VERSION" >> "$CHROOT_OUTPUT/etc/grml_live_version"
593    [ -n "$SUITE" ] && echo "SUITE=$SUITE" >> "$CHROOT_OUTPUT/etc/grml_live_version"
594
595    if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
596       FAI_ACTION=softupdate
597    else
598       FAI_ACTION=dirinstall
599    fi
600
601    if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
602       if ! [ -r "$CHROOT_OUTPUT/etc/debian_version" ] ; then
603          log    "Error: does not look like you have a working chroot. Updating/building not possible."
604          eerror "Error: does not look like you have a working chroot. Updating/building not possible. (Drop -u/-b option?)"
605          eend 1
606          bailout 20
607       fi
608    fi
609
610    if [ -d "$CHROOT_OUTPUT/bin" -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
611       log   "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already."
612       ewarn "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already." ; eend 0
613    else
614       mkdir -p "$CHROOT_OUTPUT" || bailout 5 "Problem with creating $CHROOT_OUTPUT for FAI"
615
616       if [ -n "${MIRROR_DIRECTORY}" ] ; then
617          mkdir -p "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
618          mount --bind "${MIRROR_DIRECTORY}" "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
619       fi
620
621       mkdir -p "${OUTPUT}/grml_sources/" "${CHROOT_OUTPUT}/grml-live/sources/"
622       mount --bind "${OUTPUT}/grml_sources/" "${CHROOT_OUTPUT}/grml-live/sources/"
623
624       # tell dpkg to use "unsafe io" during the build
625       [ -d "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d" ] || mkdir -p "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d"
626       echo force-unsafe-io > "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
627
628       log "Executed FAI command line:"
629       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"
630       BUILD_ONLY="$BUILD_ONLY" BOOTSTRAP_ONLY="$BOOTSTRAP_ONLY" GRML_LIVE_LOCAL_CONFIG="$GRML_LIVE_LOCAL_CONFIG" fai $VERBOSE \
631                   -C "$GRML_FAI_CONFIG" -s "file:///$GRML_FAI_CONFIG/config" -c"$CLASSES" \
632                   -u "$HOSTNAME" "$FAI_ACTION" "$CHROOT_OUTPUT" $FAI_ARGS | tee -a $LOGFILE
633       RC="$PIPESTATUS" # notice: bash-only
634
635       rm -f "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
636
637       FORCE_ISO_REBUILD=true
638
639       if [ "$RC" != 0 ] ; then
640          log    "Error: critical error while executing fai [exit code ${RC}]. Exiting."
641          eerror "Error: critical error while executing fai [exit code ${RC}]. Exiting." ; eend 1
642          bailout 1
643       else
644          einfo "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
645          log   "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
646          echo "$GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]" > $CHROOT_OUTPUT/etc/grml_version
647          chmod 644 $CHROOT_OUTPUT/etc/grml_version
648          einfo "Rebuilding initramfs"
649          # make sure new /etc/grml_version reaches initramfs, iterate over all
650          # present kernel versions (note: we can't really handle more than one
651          # kernel version anyway right now)
652          # chroot $CHROOT_OUTPUT update-initramfs -u -t => might break when using kernel-package :(
653          for initrd in "$(basename $CHROOT_OUTPUT/boot/vmlinuz-*)" ; do
654            if ! chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -c ; then
655              einfo "Creating fresh initrd did not work, trying update instead:"
656              log   "Creating fresh initrd did not work, trying update instead:"
657              chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -u
658            fi
659          done
660          eend $?
661       fi
662
663       # move fai logs into grml_logs directory
664       mkdir -p "$LOG_OUTPUT"/fai/
665       cp -r "$CHROOT_OUTPUT"/var/log/fai/"$HOSTNAME"/last/* "$LOG_OUTPUT"/fai/
666       rm -rf "$CHROOT_OUTPUT"/var/log/fai
667       # copy fai package list
668       cp "$CHROOT_OUTPUT"/var/log/install_packages.list "$LOG_OUTPUT"/fai/
669       # fixup owners
670       chown root:adm "$LOG_OUTPUT"/fai/*
671       chmod 664 "$LOG_OUTPUT"/fai/*
672
673       umount_all
674
675       # notice: 'fai dirinstall' does not seem to exit appropriate, so:
676       ERROR=''
677       CHECKLOG="$LOG_OUTPUT"/fai/
678       if [ -r "$CHECKLOG/software.log" ] ; then
679          # 1 errors during executing of commands
680          grep 'dpkg: error processing' $CHECKLOG/software.log >> $LOGFILE && ERROR=1
681          grep 'E: Method http has died unexpectedly!' $CHECKLOG/software.log >> $LOGFILE && ERROR=2
682          grep 'ERROR: chroot' $CHECKLOG/software.log >> $LOGFILE && ERROR=3
683          grep 'E: Failed to fetch' $CHECKLOG/software.log >> $LOGFILE && ERROR=4
684          grep 'Unable to write mmap - msync (28 No space left on device)' $CHECKLOG/software.log >> $LOGFILE && ERROR=5
685       fi
686
687       if [ -r "$CHECKLOG/shell.log" ] ; then
688          grep 'FAILED with exit code' $CHECKLOG/shell.log >> $LOGFILE && ERROR=6
689       fi
690
691       if [ -n "$ERROR" ] ; then
692          log    "Error: there was a critical error [${ERROR}] during execution of stage 'fai dirinstall' [$(date)]"
693          eerror "Error: there was a critical error during execution of stage 'fai dirinstall'"
694          eerror "Note:  check out ${CHECKLOG}/ for details. [exit ${ERROR}]"
695          eend 1
696          bailout 1
697       else
698          log "Finished execution of stage 'fai dirinstall' [$(date)]"
699          einfo "Finished execution of stage 'fai dirinstall'"
700       fi
701    fi
702 fi # BUILD_DIRTY?
703 # }}}
704
705 # package validator {{{
706 CHECKLOG=/var/log/fai/$HOSTNAME/last
707 if [ -r "$CHECKLOG/dpkg.selections" ] ; then
708   package_count=$(wc -l "$CHECKLOG/dpkg.selections" | awk '{print $1}')
709 else
710   package_count="unknown"
711 fi
712
713 mkdir -p "$REPORTS"
714 REPORT_MISSING_PACKAGES="${REPORTS}/TEST-MissingPackages.xml"
715
716 # check for missing packages
717 if ! [ -s "$CHECKLOG/package_errors.log" ] ; then
718   einfo "No missing packages found, generating empty junit report."
719
720   cat > "${REPORT_MISSING_PACKAGES}" << EOF
721 <?xml version="1.0" encoding="UTF-8"?>
722 <testsuite name="grml-live-missing-packages" tests="${package_count}" time="1" failures="0" errors="0" skipped="0" assertions="0">
723   <testcase name="test_missing_packages" time="0" assertions="0">
724   </testcase>
725   <system-out>
726   </system-out>
727   <system-err>
728   </system-err>
729 </testsuite>
730 EOF
731   eend 0
732 else
733   einfo "Missing packages found, generating junit report."
734
735   if [ -r "$CHECKLOG/package_errors.log" ] ; then
736     package_errors=$(wc -l "$CHECKLOG/package_errors.log" | awk '{print $1}')
737   else
738     package_errors="unknown"
739   fi
740
741   mkdir -p "$REPORTS"
742   REPORT_MISSING_PACKAGES="${REPORTS}/TEST-MissingPackages.xml"
743
744   cat > "${REPORT_MISSING_PACKAGES}" << EOF
745 <?xml version="1.0" encoding="UTF-8"?>
746 <testsuite name="grml-live-missing-packages" tests="${package_count}" time="1" failures="${package_errors}" errors="${package_errors}" skipped="0" assertions="0">
747 EOF
748
749   for package in $(awk '{print $5}' "${CHECKLOG}/package_errors.log" | sed 's/\.$//') ; do
750     cat >> "${REPORT_MISSING_PACKAGES}" << EOF
751   <testcase name="test_missing_packages_${package}" time="0" assertions="0">
752     <failure type="RuntimeError" message="Package ${package} is missing">
753 Package $package is missing in chroot
754   </failure>
755   </testcase>
756 EOF
757   done
758
759   cat >> "${REPORT_MISSING_PACKAGES}" << EOF
760   <system-out>
761   </system-out>
762   <system-err>
763   </system-err>
764 </testsuite>
765 EOF
766   eend 0
767
768   if [ -n "$EXIT_ON_MISSING_PACKAGES" -a -z "$BUILD_DIRTY" ] ; then
769     eerror "The following packages were requested for installation but could not be processed:"
770     cat "$CHECKLOG/package_errors.log"
771     eerror "... exiting as requested via \$EXIT_ON_MISSING_PACKAGES."
772     eend 1
773     bailout 13
774   else
775     ewarn "The following packages were requested for installation but could not be processed:"
776     cat "$CHECKLOG/package_errors.log"
777     eend 0
778   fi
779 fi
780 # }}}
781
782 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
783 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
784 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
785
786 # prepare ISO
787 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
788   if [ -n "$BOOTSTRAP_ONLY" ] ; then
789      log   "Skipping stage 'boot' as building with bootstrap only."
790      ewarn "Skipping stage 'boot' as building with bootstrap only." ; eend 0
791   else
792     if [ -d "$BUILD_OUTPUT"/boot/isolinux -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
793        log   "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already."
794        ewarn "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already." ; eend 0
795     else
796        # booting stuff:
797        [ -d "$BUILD_OUTPUT"/boot/isolinux ] || mkdir -p "$BUILD_OUTPUT"/boot/isolinux
798        [ -d "$BUILD_OUTPUT"/boot/"${SHORT_NAME}" ] || mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"
799
800        # if we don't have an initrd we a) can't boot and b) there was an error
801        # during build, so check for the file:
802        INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
803        if [ -n "$INITRD" ] ; then
804           cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/initrd.gz
805           find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
806        else
807           log    "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
808           eerror "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
809           bailout 10
810        fi
811
812        KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
813        if [ -n "$KERNEL_IMAGE" ] ; then
814           cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/linux26
815        else
816           log    "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
817           eerror "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
818           bailout 11
819        fi
820
821        [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
822        if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
823           log    "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
824           eerror "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
825           bailout 8
826        fi
827
828        # copy _required_ isolinux files
829        for file in ifcpu64.c32 isolinux.bin vesamenu.c32; do
830          copy_addon_file "${file}" /usr/lib/syslinux isolinux
831        done
832
833        # *always* copy files to output directory so the variables
834        # get adjusted according to the build.
835        cp ${TEMPLATE_DIRECTORY}/boot/isolinux/*  "$BUILD_OUTPUT"/boot/isolinux/
836
837        if [ -n "$NO_ADDONS" ] ; then
838           log   "Skipping installation of boot addons as requested via \$NO_ADDONS."
839           einfo "Skipping installation of boot addons as requested via \$NO_ADDONS."; eend 0
840        else
841           if ! [ -d "$TEMPLATE_DIRECTORY"/boot/addons ] ; then
842             log   "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)"
843             ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
844           else
845             # copy addons from system packages or grml-live-compat
846             copy_addon_file ipxe.lkrn /usr/lib/ipxe addons
847             copy_addon_file pci.ids /usr/share/misc addons
848             copy_addon_file memtest86+.bin /boot addons
849             for file in memdisk chain.c32 hdt.c32 menu.c32; do
850               copy_addon_file "${file}" /usr/lib/syslinux addons
851             done
852
853             # make memtest filename FAT16/8.3 compatible
854             mv "${BUILD_OUTPUT}/boot/addons/memtest86+.bin" \
855               "${BUILD_OUTPUT}/boot/addons/memtest"
856
857             # copy only files so we can handle bsd4grml on its own
858             for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
859               test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
860             done
861
862             if [ -n "$NO_ADDONS_BSD4GRML" ] ; then
863                log   "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."
864                einfo "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."; eend 0
865             else
866                if [ -d "$TEMPLATE_DIRECTORY"/boot/addons/bsd4grml ] ; then
867                  cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
868                else
869                  log   "Missing addon file: bsd4grml"
870                  ewarn "Missing addon file: bsd4grml" ; eend 0
871                fi
872             fi
873
874           fi # no "$TEMPLATE_DIRECTORY"/boot/addons
875        fi # NO_ADDONS
876
877        if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
878          mkdir -p "${BUILD_OUTPUT}/boot/grub"
879        fi
880        cp ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
881
882        if [ -e ${TEMPLATE_DIRECTORY}/compat/grub/linux.mod ]; then
883          cp "${TEMPLATE_DIRECTORY}"/compat/grub/* "${BUILD_OUTPUT}"/boot/grub/
884        else
885          if ! which "grub-mkimage" >/dev/null 2>&1 ; then
886            log   "grub-mkimage not found, skipping Grub step therefore." ; eend 0
887            ewarn "grub-mkimage not found, skipping Grub step therefore."
888            ewarn "Please install grub-pc-bin or grub-common >= 1.98+20100804-14." ; eend 0
889          elif ! grub-mkimage --help | grep -q -- --format ; then
890            log   "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore." ; eend 0
891            ewarn "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore."
892            ewarn "Please install grub-common >= 1.98+20100804-14 or grub-pc-bin." ; eend 0
893          else
894            # copy system grub files if grml-live-compat is not installed
895            cp -a /usr/lib/grub/*-pc/*.mod "${BUILD_OUTPUT}"/boot/grub/
896            cp -a /usr/lib/grub/*-pc/*.o "${BUILD_OUTPUT}"/boot/grub/
897            cp -a /usr/lib/grub/*-pc/*.lst "${BUILD_OUTPUT}"/boot/grub/
898            cp -a /usr/share/grub/ascii.pf2 "${BUILD_OUTPUT}"/boot/grub/
899            grub-mkimage -d /usr/lib/grub/*-pc -o \
900              "${BUILD_OUTPUT}/boot/grub/core.img" biosdisk iso9660 --format=i386-pc
901          fi
902        fi
903
904        if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
905           log    "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
906           eerror "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
907           bailout 9
908        fi
909
910        [ -d "$BUILD_OUTPUT"/GRML ] || mkdir "$BUILD_OUTPUT"/GRML
911        cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/
912
913        # adjust boot splash information:
914        RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
915        RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
916        RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
917
918        if [ -r "$BUILD_OUTPUT"/GRML/grml-version ] ; then
919           sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/grml-version
920           sed -i "s/%DATE%/$DATE/"                                      "$BUILD_OUTPUT"/GRML/grml-version
921        fi
922
923        # make sure the squashfs filename is set accordingly:
924        SQUASHFS_NAME="$GRML_NAME.squashfs"
925
926        if [ -n "$NO_BOOTID" ] ; then
927           log   'Skipping bootid feature as requested via $NO_BOOTID.'
928           einfo 'Skipping bootid feature as requested via $NO_BOOTID.'
929        else
930           [ -n "$BOOTID" ] || BOOTID="$(echo ${GRML_NAME}${VERSION} | tr -d ',./;\- ')"
931           [ -d "$BUILD_OUTPUT"/conf ] || mkdir "$BUILD_OUTPUT"/conf
932           einfo "Generating /conf/bootid.txt with entry ${BOOTID}."
933           log   "Generating /conf/bootid.txt with entry ${BOOTID}."
934           echo "$BOOTID" > "$BUILD_OUTPUT"/conf/bootid.txt
935           eend $?
936        fi
937
938        # adjust all variables in the templates with the according distribution information
939        for file in "${BUILD_OUTPUT}"/boot/isolinux/*.cfg "${BUILD_OUTPUT}"/boot/isolinux/*.msg \
940                    "${BUILD_OUTPUT}"/boot/grub/* ; do
941          if [ -r "${file}" ] ; then
942            sed -i "s/%ARCH%/$ARCH/g"                    "${file}"
943            sed -i "s/%DATE%/$DATE/g"                    "${file}"
944            sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/g"      "${file}"
945            sed -i "s/%DISTRI_NAME%/$DISTRI_NAME/g"      "${file}"
946            sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/g"  "${file}"
947            sed -i "s/%GRML_NAME%/$GRML_NAME/g"          "${file}"
948            sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/g"  "${file}"
949            sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/g"    "${file}"
950            sed -i "s/%SHORT_NAME%/$SHORT_NAME/g"        "${file}"
951            sed -i "s/%VERSION%/$VERSION/g"              "${file}"
952
953            [ -n "$DEFAULT_BOOTOPTIONS" ] && sed -i "s/ boot=live/ boot=live $DEFAULT_BOOTOPTIONS/"  "${file}"
954
955            if [ -n "$NO_BOOTID" ] ; then
956               sed -i "s/ bootid=%BOOTID%//g" "${file}" # drop bootid bootoption
957            else
958               sed -i "s/%BOOTID%/$BOOTID/g" "${file}" # adjust bootid=... argument
959            fi
960          fi
961        done
962
963        # adjust bootsplash accordingly but make sure the string has the according lenght
964        SQUASHFS_NAME="$(cut_string 20 "$SQUASHFS_NAME")"
965        SQUASHFS_NAME="$(extend_string_end 20 "$SQUASHFS_NAME")"
966        for file in f4 f5 ; do
967           if [ -r "${BUILD_OUTPUT}/boot/isolinux/${file}" ] ; then
968              sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
969              sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
970           fi
971        done
972
973        # generate addon list
974        rm -f "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
975        for name in "${BUILD_OUTPUT}"/boot/isolinux/addon_*.cfg ; do
976          include_name=$(basename "$name")
977          echo "include $include_name"  >> "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
978        done
979
980        if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
981           log "including grmlmain.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
982           echo "include grmlmain.cfg"    >  "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
983           echo "include default.cfg"     >  "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
984           echo "include menuoptions.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
985           echo "include grml.cfg"        >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
986
987           for f in "${BUILD_OUTPUT}"/boot/isolinux/submenu*.cfg ; do
988             echo "include $(basename $f)"     >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
989           done
990
991           echo "include options.cfg"     >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
992           if [ ! -n "$NO_ADDONS" ] ; then
993             echo "include addons.cfg"    >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
994           fi
995           echo "include isoprompt.cfg"   >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
996           echo "include hd.cfg"          >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
997           echo "include hidden.cfg"      >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
998        else # assume we are building a custom distribution:
999           log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
1000           einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
1001           if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
1002             log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
1003             eindent
1004             einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
1005             eoutdent
1006             eend $?
1007          else
1008             log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1009             echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1010             [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
1011           fi
1012        fi
1013
1014        # use old style console based isolinux method only if requested:
1015        if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
1016           log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
1017           einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
1018           if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
1019             einfo "include for console.cfg already found, nothing to do."
1020             eend 0
1021           else
1022             log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1023             einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1024             echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1025             eend $?
1026           fi
1027        else
1028           log 'Using graphical boot menu.'
1029           if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
1030             log "include for vesamenu.cfg already found, nothing to do."
1031           else
1032             log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1033             echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
1034           fi
1035        fi
1036
1037        if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
1038           sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
1039        fi
1040
1041        DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot
1042        if ! [ -r "$DPKG_LIST" ] ; then
1043           ewarn "$DPKG_LIST could not be read, ignoring to store package information on ISO therefore."
1044        else
1045           einfo "Storing package list information as /GRML/${GRML_NAME}-packages.txt on ISO."
1046           cp "$DPKG_LIST" "${BUILD_OUTPUT}/GRML/${GRML_NAME}-packages.txt"
1047           eend $?
1048        fi
1049
1050        # autostart for Windows:
1051        if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
1052           cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
1053        fi
1054
1055     FORCE_ISO_REBUILD=true
1056     einfo "Finished execution of stage 'boot'" ; eend 0
1057     fi
1058   fi # BOOTSTRAP_ONLY
1059 else
1060    log    'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
1061    eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
1062    bailout
1063 fi
1064
1065 # support installation of local files into the chroot/ISO
1066 if [ -n "$CHROOT_INSTALL" ] ; then
1067   if ! [ -d "$CHROOT_INSTALL" ] ; then
1068      log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1069      ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
1070   else
1071      log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1072      einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
1073      rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
1074      eend $?
1075      einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
1076      FORCE_ISO_REBUILD=true
1077   fi
1078 fi
1079
1080 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
1081    log   "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
1082    ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
1083 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
1084    log   "Skipping stage 'squashfs' as requested via option -q or -N"
1085    ewarn "Skipping stage 'squashfs' as requested via option -q or -N" ; eend 0
1086 else
1087    [ -d "$BUILD_OUTPUT"/live ] || mkdir "$BUILD_OUTPUT"/live
1088    # make sure we don't leave (even an empty) base.tgz:
1089    [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
1090
1091    # if unconfigured default to squashfs-tools' mksquashfs binary
1092    if [ -z "$SQUASHFS_BINARY" ] ; then
1093       SQUASHFS_BINARY='mksquashfs'
1094    fi
1095
1096    if which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
1097       log    "Using mksquashfs binary ${SQUASHFS_BINARY}"
1098       einfo  "Using mksquashfs binary ${SQUASHFS_BINARY}" ; eend 0
1099    else
1100       log    "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
1101       eerror "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
1102       bailout
1103    fi
1104
1105    # use sane defaults if $SQUASHFS_OPTIONS isn't set
1106    if [ -z "$SQUASHFS_OPTIONS" ] ; then
1107      # use blocksize 256k as this gives best result with regards to time + compression
1108      SQUASHFS_OPTIONS="-b 256k"
1109
1110      # set lzma/xz compression by default, unless -z option has been specified on command line
1111      if [ -z "$SQUASHFS_ZLIB" ] ; then
1112         SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp xz"
1113      else
1114         SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp gzip"
1115      fi
1116    fi
1117
1118    # support exclusion of files via exclude-file:
1119    if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
1120       SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE -wildcards"
1121    fi
1122
1123    # get rid of unnecessary files when building grml-small for final release:
1124    if echo "$CLASSES" | grep -q GRML_SMALL ; then
1125       SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
1126    fi
1127
1128    # log stuff
1129    SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
1130
1131    # informational stuff
1132    [ -n "$SQUASHFS_OPTIONS" ]  && SQUASHFS_INFO_MSG="$SQUASHFS_OPTIONS"
1133    [ -n "$SQUASHFS_INFO_MSG" ] && SQUASHFS_INFO_MSG="using options: $SQUASHFS_INFO_MSG"
1134    einfo "Squashfs build information: running binary $SQUASHFS_BINARY $SQUASHFS_INFO_MSG"
1135
1136    log "$SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS"
1137
1138    if $SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/"${GRML_NAME}".squashfs \
1139       -noappend $SQUASHFS_OPTIONS 2>"${SQUASHFS_STDERR}" ; then
1140       echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/filesystem.module
1141       log "Finished execution of stage 'squashfs' [$(date)]"
1142       einfo "Finished execution of stage 'squashfs'" ; eend 0
1143    else
1144       log    "Error: there was a critical error executing stage 'squashfs' [$(date)]:"
1145       log    "$(cat $SQUASHFS_STDERR)"
1146       eerror "Error: there was a critical error executing stage 'squashfs':"
1147       cat    "${SQUASHFS_STDERR}"
1148       eend 1
1149       bailout
1150    fi
1151
1152    FORCE_ISO_REBUILD=true
1153 fi
1154
1155 # create md5sum file:
1156 if [ -z "$BOOTSTRAP_ONLY" ] ; then
1157   ( cd $BUILD_OUTPUT/GRML &&
1158   find .. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
1159 fi
1160 # }}}
1161
1162 # ISO_OUTPUT - mkisofs {{{
1163 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
1164 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
1165
1166 if [ "$BOOT_METHOD" = "isolinux" ] ; then
1167    BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
1168 elif [ "$BOOT_METHOD" = "grub2" ] ; then
1169    BOOT_ARGS="-no-emul-boot -boot-load-size 4 -b boot/grub/toriboot.bin"
1170 fi
1171
1172 # Just until http://bts.grml.org/grml/issue945 has been resolved.
1173 # HYBRID_METHOD defaults to manifold, so make sure the default works OOTB.
1174 if [[ $BOOT_METHOD != isolinux && ($HYBRID_METHOD = isohybrid || $HYBRID_METHOD = manifold) ]]; then
1175   log   "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1176   ewarn "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1177   HYBRID_METHOD='grub2'
1178   eend 0
1179 fi
1180
1181 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ]  ; then
1182    log   "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already."
1183    ewarn "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already." ; eend 0
1184 elif [ -n "$SKIP_MKISOFS" ] ; then
1185    log   "Skipping stage 'iso build' as requested via option -n or -N"
1186    ewarn "Skipping stage 'iso build' as requested via option -n or -N" ; eend 0
1187 else
1188    mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
1189
1190    if $FORCE_ISO_REBUILD && ! [ -f "${ISO_OUTPUT}/${ISO_NAME}" ] ; then
1191       log   "Forcing rebuild of ISO because files on ISO have been modified."
1192       einfo "Forcing rebuild of ISO because files on ISO have been modified."
1193    fi
1194
1195    # support xorriso as well mkisofs and genisoimage
1196    if which xorriso >/dev/null 2>&1 && \
1197       dpkg --compare-versions $(dpkg-query -W -f='${Version}\n' xorriso 2>/dev/null) gt-nl 1.1.6-2 ; then
1198       MKISOFS='xorriso -as mkisofs'
1199     elif which mkisofs >/dev/null 2>&1; then
1200       MKISOFS='mkisofs'
1201    elif which genisoimage >/dev/null 2>&1; then
1202       MKISOFS='genisoimage'
1203    else
1204       log    "Error: neither xorriso nor mkisofs nor genisoimage available - can not create ISO."
1205       eerror "Error: neither xorriso nor mkisofs nor genisoimage available - can not create ISO." ; eend 1
1206       bailout
1207    fi
1208
1209    case "$ARCH" in
1210      amd64)
1211        # using -eltorito-alt-boot is limited to xorriso for now
1212        case "$MKISOFS" in
1213          xorriso*)
1214            einfo "Using xorriso for ISO generation." ;  eend 0
1215
1216            if [ -r "${CHROOT_OUTPUT}/var/lib/grml_live_efi.img" ] ; then
1217              einfo "Found /var/lib/grml_live_efi.img - moving to /boot/efi.img for ISO."
1218              log   "Found /var/lib/grml_live_efi.img - moving to /boot/efi.img for ISO."
1219              mv "${CHROOT_OUTPUT}/var/lib/grml_live_efi.img" "${BUILD_OUTPUT}/boot/efi.img"
1220              eend $?
1221            fi
1222
1223            if [ -r "${CHROOT_OUTPUT}/var/lib/grml_live_bootx64.efi" ] ; then
1224              einfo "Found /var/lib/grml_live_bootx64.efi - moving to /efi/boot/bootx64.efi for ISO"
1225              log   "Found /var/lib/grml_live_bootx64.efi - moving to /efi/boot/bootx64.efi for ISO"
1226              mkdir -p "${BUILD_OUTPUT}/efi/boot/"
1227              mv "${CHROOT_OUTPUT}/var/lib/grml_live_bootx64.efi" "${BUILD_OUTPUT}/efi/boot/bootx64.efi"
1228              eend $?
1229            fi
1230
1231            if [ -r "${BUILD_OUTPUT}"/boot/efi.img ] ; then
1232              einfo "/boot/efi.img found and amd64 architecture present, extending boot arguments."
1233              log   "/boot/efi.img found and amd64 architecture present, extending boot arguments."
1234              BOOT_ARGS="$BOOT_ARGS -boot-info-table -eltorito-alt-boot -e boot/efi.img -no-emul-boot"
1235              eend $?
1236            fi
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 # pack artifacts {{{
1349 if [ -n "$PACK_ARTIFACTS" ]; then
1350   log "Packing artifcats"
1351   einfo "Packing artifacts"
1352   [ -f "${CHROOT_ARCHIVE}" ] && rm -r "${CHROOT_ARCHIVE}"
1353   tar -c -a -f ${CHROOT_ARCHIVE} --preserve-permissions -C "$(dirname ${CHROOT_OUTPUT})" "$(basename ${CHROOT_OUTPUT})"
1354   eend 0
1355 fi
1356 # }}}
1357
1358 # log build information to database if grml-live-db is installed and enabled {{{
1359 dpkg_to_db() {
1360 if [ -d /usr/share/grml-live-db ] ; then
1361
1362   # safe defaults
1363   DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot:
1364   [ -n "$DPKG_DATABASE" ]  || DPKG_DATABASE=/var/log/grml-live.db
1365   [ -n "$DPKG_DBSCRIPT" ]  || DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
1366   [ -n "$DPKG_DBOPTIONS" ] || DPKG_DBOPTIONS="--database $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME --dpkg $DPKG_LIST"
1367
1368   if ! [ -x "$DPKG_DBSCRIPT" ] ; then
1369     log "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information."
1370     eerror "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information." ; eend 1
1371     bailout 14
1372   fi
1373
1374   # disable by default for now, not sure whether really everyone is using a local db file
1375   #if ! touch "$DPKG_DATABASE" ; then
1376   #  eerror "Error: can not write to ${DPKG_DATABASE}, can not log dpkg information." ; eend 1
1377   #  bailout 14
1378   #fi
1379
1380   if ! [ -r "$DPKG_LIST" ] ; then
1381      log   "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)"
1382      ewarn "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)" ; eend 0
1383   else
1384      einfo "Logging $DPKG_LIST to database $DPKG_DATABASE"
1385      log "Logging $DPKG_LIST to database $DPKG_DATABASE"
1386      log "Executing $DPKG_DBSCRIPT $DPKG_DBOPTIONS"
1387      eindent
1388
1389      if DB_INFO=$("$DPKG_DBSCRIPT" $DPKG_DBOPTIONS 2>&1) ; then
1390        einfo "$DB_INFO"
1391        eend 0
1392      else
1393        eerror "$DB_INFO"
1394        eend 1
1395      fi
1396
1397      eoutdent
1398   fi
1399
1400 fi
1401 }
1402 # }}}
1403
1404 # finalize {{{
1405 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
1406 log "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]"
1407
1408 dpkg_to_db # make sure we catch the last log line as well, therefore execute between log + einfo
1409
1410 einfo "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]" ; eend 0
1411 bailout 0
1412 # }}}
1413
1414 ## END OF FILE #################################################################
1415 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=2