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