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