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