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