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