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