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