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