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