Replace all references to ftp.de.debian.org with cdn.debian.org
[grml-live.git] / grml-live
index fb7d8ba..6198546 100755 (executable)
--- a/grml-live
+++ b/grml-live
@@ -1,24 +1,34 @@
 #!/bin/bash
 # Filename:      grml-live
 # Purpose:       build process script for generating a (grml based) Linux Live-ISO
-# Authors:       grml-team (grml.org), (c) Michael Prokop <mika@grml.org>
+# Authors:       grml-team (grml.org),
+#                (c) Michael Prokop <mika@grml.org>,
+#                (c) Thorsten Glaser <tg@mirbsd.org>
 # Bug-Reports:   see http://grml.org/bugs/
 # License:       This file is licensed under the GPL v2 or any later version.
 ################################################################################
 
-# read configuration files, set some misc variables {{{
-
+# some misc and global stuff {{{
 export LANG=C
 export LC_ALL=C
 
+# define function getfilesize before "set -e"
+if stat --help >/dev/null 2>&1; then
+  getfilesize='stat -c %s'  # GNU stat
+else
+  getfilesize='stat -f %z'  # BSD stat
+fi
+
 # exit on any error:
 set -e
 
-GRML_LIVE_VERSION='0.9.16'
+# global variables
+GRML_LIVE_VERSION='0.9.21'
 PN="$(basename $0)"
 CMDLINE="$0 $@"
 ISO_DATE="$(date +%Y-%m-%d)"
 SOURCES_LIST_FILE='/etc/grml/fai/apt/sources.list'
+# }}}
 
 # usage information {{{
 usage()
@@ -37,6 +47,8 @@ Usage: $PN [options, see as follows]
    -g <grml_name>]         set the grml flavour name
    -h                      display short usage information and exit
    -i <iso_name>           name of ISO
+   -I <src_directory>      directory which provides files that should become
+                           part of the chroot/ISO
    -o <output_directory>   main output directory of the build process
    -q                      skip mksquashfs
    -r <release_name<       release name
@@ -72,6 +84,7 @@ if [ "$1" = '-h' -o "$1" = '--help' ] ; then
 fi
 # }}}
 
+# some runtime checks {{{
 # we need root permissions for the build-process:
 if [ "$(id -u 2>/dev/null)" != 0 ] ; then
    echo "Error: please run this script with uid 0 (root)." >&2
@@ -90,7 +103,9 @@ if [ -r /var/run/fai/fai_softupdate_is_running ] ; then
    echo "You may remove /var/run/fai/fai_softupdate_is_running and try again.">&2
    exit 1
 fi
+# }}}
 
+# lsb-functions and configuration stuff {{{
 # make sure they are not set by default
 VERBOSE=''
 FORCE=''
@@ -111,7 +126,6 @@ fi
 # source main configuration file:
 LIVE_CONF=/etc/grml/grml-live.conf
 . $LIVE_CONF
-
 # }}}
 
 # clean exit {{{
@@ -127,28 +141,11 @@ bailout() {
 trap bailout 1 2 3 3 6 9 14 15
 # }}}
 
-# check for important variables {{{
-[ -n "$GRML_FAI_CONFIG" ] || GRML_FAI_CONFIG=/etc/grml/fai
-[ -n "$HOSTNAME" ] || HOSTNAME=grml
-[ -n "$USERNAME" ] || USERNAME=grml
-[ -n "$CLASSES" ]  || CLASSES="GRML,I386"
-[ -n "$BOOT_METHOD" ] || BOOT_METHOD='isolinux'
-[ -n "$OUTPUT" ] || bailout 1 "${PN}: \$OUTPUT not specified. Please adjust $LIVE_CONF. Exiting."
-
-[ -n "$VERSION" ]  || VERSION="0.0.1"
-[ -n "$RELEASENAME" ] || RELEASENAME="grml-live rocks"
-[ -n "$GRML_NAME" ] || GRML_NAME='grml'
-
-# logfile:
-if [ -z "$LOGFILE" ] ; then
-   LOGFILE=/var/log/grml-live.log
-fi
+# log file stuff {{{
+[ -n "$LOGFILE" ] || LOGFILE=/var/log/grml-live.log
 touch $LOGFILE
 chown root:adm $LOGFILE
 chmod 664 $LOGFILE
-
-NFSROOT_CONF=/etc/grml/fai/make-fai-nfsroot.conf
-
 # }}}
 
 # some important functions {{{
@@ -212,7 +209,7 @@ fi
 # }}}
 
 # command line parsing {{{
-while getopts "a:C:c:g:i:o:r:s:t:v:bBFuqVz" opt; do
+while getopts "a:C:c:g:i:I:o:r:s:t:v:bBFuqVz" opt; do
   case "$opt" in
     a) ARCH="$OPTARG" ;;
     b) BUILD_ONLY=1 ;;
@@ -221,11 +218,8 @@ while getopts "a:C:c:g:i:o:r:s:t:v:bBFuqVz" opt; do
     C) CONFIG="$OPTARG" ;;
     g) GRML_NAME="$OPTARG" ;;
     i) ISO_NAME="$OPTARG" ;;
-    o) OUTPUT="$OPTARG"
-       CHROOT_OUTPUT="$OUTPUT/grml_chroot"
-       BUILD_OUTPUT="$OUTPUT/grml_cd"
-       ISO_OUTPUT="$OUTPUT/grml_isos"
-       ;;
+    I) CHROOT_INSTALL="$OPTARG" ;;
+    o) OUTPUT="$OPTARG" ;;
     q) SKIP_MKSQUASHFS=1 ;;
     r) RELEASENAME="$OPTARG" ;;
     s) SUITE="$OPTARG" ;;
@@ -241,12 +235,42 @@ done
 shift $(($OPTIND - 1))  # set ARGV to the first not parsed commandline parameter
 # }}}
 
+# assume sane defaults (if not set already) {{{
+[ -n "$ARCH" ]             || ARCH="$(dpkg --print-architecture)"
+[ -n "$BOOT_METHOD" ]      || BOOT_METHOD='isolinux'
+[ -n "$BUILD_OUTPUT" ]     || BUILD_OUTPUT="$OUTPUT/grml_cd"
+[ -n "$CHROOT_OUTPUT" ]    || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
+[ -n "$CLASSES" ]          || CLASSES="GRMLBASE,GRML_MEDIUM,I386"
+[ -n "$DISTRI_INFO" ]      || DISTRI_INFO='Grml - Live Linux for system administrators   '
+[ -n "$DISTRI_NAME" ]      || DISTRI_NAME="grml"
+[ -n "$DISTRI_SPLASH" ]    || DISTRI_SPLASH='grml.png'
+[ -n "$FORCE_ISO_REBUILD" ] || FORCE_ISO_REBUILD="false"
+[ -n "$GRML_FAI_CONFIG" ]  || GRML_FAI_CONFIG='/etc/grml/fai'
+[ -n "$GRML_NAME" ]        || GRML_NAME='grml'
+[ -n "$HOSTNAME" ]         || HOSTNAME='grml'
+[ -n "$ISO_OUTPUT" ]       || ISO_OUTPUT="$OUTPUT/grml_isos"
+[ -n "$NFSROOT_CONF" ]     || NFSROOT_CONF='/etc/grml/fai/make-fai-nfsroot.conf'
+[ -n "$OUTPUT" ]           || OUTPUT='/grml/grml-live'
+[ -n "$RELEASENAME" ]      || RELEASENAME='grml-live rocks'
+[ -n "$SQUASHFS_EXCLUDES_FILE " ] || SQUASHFS_EXCLUDES_FILE='/etc/grml/fai/squashfs-excludes'
+[ -n "$SUITE" ]            || SUITE='stable'
+[ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
+[ -n "$USERNAME" ]         || USERNAME='grml'
+[ -n "$VERSION" ]          || VERSION='0.0.1'
+[ -n "$WINDOWS_BINARIES" ] || WINDOWS_BINARIES='http://the.earth.li/~sgtatham/putty/latest/x86/'
+# }}}
+
 # some misc checks before executing FAI {{{
 [ -n "$CLASSES" ] || bailout 1 "Error: \$CLASSES unset, please set it in $LIVE_CONF or
 specify it on the command line using the -c option."
 [ -n "$OUTPUT" ] || bailout 1 "Error: \$OUTPUT unset, please set it in $LIVE_CONF or
 specify it on the command line using the -o option."
 
+# set subdirectories according to $OUTPUT:
+CHROOT_OUTPUT="$OUTPUT/grml_chroot"
+BUILD_OUTPUT="$OUTPUT/grml_cd"
+ISO_OUTPUT="$OUTPUT/grml_isos"
+
 # trim characters that are known to cause problems inside $GRML_NAME;
 # for example isolinux does not like '-' inside the directory name
 [ -n "$GRML_NAME" ] && export SHORT_GRML_NAME="$(echo $GRML_NAME | tr -d ',./;\- ')"
@@ -294,6 +318,7 @@ if [ -z "$FORCE" ] ; then
    [ -n "$ARCH" ]               && echo "  Architecture:      $ARCH"
    [ -n "$BOOT_METHOD" ]        && echo "  Boot method:       $BOOT_METHOD"
    [ -n "$TEMPLATE_DIRECTORY" ] && echo "  Template files:    $TEMPLATE_DIRECTORY"
+   [ -n "$CHROOT_INSTALL" ]     && echo "  Install files from directory to chroot:  $CHROOT_INSTALL"
    [ -n "$FAI_ARGS" ]           && echo "  additional arguments for FAI: $FAI_ARGS"
    [ -n "$LOGFILE" ]            && echo "  Logging to file:   $LOGFILE"
    [ -n "$SQUASHFS_ZLIB" ]      && echo "  Using ZLIB (instead of LZMA) compression."
@@ -364,41 +389,61 @@ if [ -n "$FAI_DEBOOTSTRAP" ] ; then
 fi
 
 # does this suck? YES!
-if [ -n "$SUITE" ] ; then
-
-   # /usr/share/debootstrap/scripts/unstable does not exist, instead use 'sid':
-   case $SUITE in
-      unstable) SUITE='sid' ;;
-   esac
-
-   DIST=" etch\| stable\| lenny\| squeeze\| testing\| sid\| unstable"
-   sed "s/\(^deb .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/" "$SOURCES_LIST_FILE" | sponge "$SOURCES_LIST_FILE"
-   for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" ; do
-       if [ -n "$file" ] ; then
-          sed "s/^SUITE=.*/SUITE=\"$SUITE\"/" $file | sponge $file
-          sed "s/\(^deb .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/" "$file" | sponge "$file"
-       fi
-   done
-
-   # notice: activate grml-live pool only if we are building against unstable:
-   if grep -qe unstable -qe sid "$SOURCES_LIST_FILE" ; then
-      grep -q 'grml-live.*main' "$SOURCES_LIST_FILE" || \
-      grep grml-stable "$SOURCES_LIST_FILE" | \
-           sed 's/grml-stable/grml-live/' >> "$SOURCES_LIST_FILE"
-   else
-      grep -q 'grml-live.*main' "$SOURCES_LIST_FILE" && \
-      sed 's/.*grml-live.*/# removed grml-live repository/' "$SOURCES_LIST_FILE" | sponge "$SOURCES_LIST_FILE"
-   fi
+# /usr/share/debootstrap/scripts/unstable does not exist, instead use 'sid':
+case $SUITE in
+   unstable) SUITE='sid' ;;
+   # make sure that we *NEVER* write any broken suite name to sources.list,
+   # otherwise we won't be able to adjust it one next (correct) execution
+   stable)   ;;
+   testing)  ;;
+   etch)     ;;
+   lenny)    ;;
+   squeeze)  ;;
+   sid)      ;;
+   *) echo "Sorry, $SUITE is not a valid Debian suite, exiting.">&2; bailout 1 ;;
+esac
+
+DIST=" etch\| stable\| lenny\| squeeze\| testing\| sid\| unstable"
+sed "s/\(^deb .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/" "$SOURCES_LIST_FILE" | sponge "$SOURCES_LIST_FILE"
+for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" ; do
+    if [ -n "$file" ] ; then
+       sed "s/^SUITE=.*/SUITE=\"$SUITE\"/" $file | sponge $file
+       sed "s/\(^deb .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/" "$file" | sponge "$file"
+    fi
+done
 
-   for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" "$NFSROOT_CONF" ; do
-       if [ -n "$file" ] ; then
-          sed "s|^FAI_DEBOOTSTRAP=\"[a-z]* |FAI_DEBOOTSTRAP=\"$SUITE |" "$file" | sponge "$file"
-       fi
-   done
+# notice: activate grml-live pool only if we are building against unstable:
+if grep -qe unstable -qe sid "$SOURCES_LIST_FILE" ; then
+   grep -q 'grml-live.*main' "$SOURCES_LIST_FILE" || \
+   grep grml-stable "$SOURCES_LIST_FILE" | \
+        sed 's/grml-stable/grml-live/' >> "$SOURCES_LIST_FILE"
+else
+   grep -q 'grml-live.*main' "$SOURCES_LIST_FILE" && \
+   sed 's/.*grml-live.*/# removed grml-live repository/' "$SOURCES_LIST_FILE" | sponge "$SOURCES_LIST_FILE"
+fi
+
+for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" "$NFSROOT_CONF" ; do
+    if [ -n "$file" ] ; then
+       sed "s|^FAI_DEBOOTSTRAP=\"[a-z]* |FAI_DEBOOTSTRAP=\"$SUITE |" "$file" | sponge "$file"
+    fi
+done
+
+# validate whether the specified architecture class matches the
+# architecture (option), otherwise installation of kernel will fail
+if echo $CLASSES | grep -qi i386 ; then
+   if ! [[ "$ARCH" == "i386" ]] ; then
+      eerror "You specified the I386 class but are trying to build something else (AMD64?)."
+      eerror "-> Either invoke grml-live with '-i i386' or adjust the architecture class. Exiting."
+      bailout
+   fi
+elif echo $CLASSES | grep -qi amd64 ; then
+   if ! [[ "$ARCH" == "amd64" ]] ; then
+      eerror "You specified the AMD64 class but are trying to build something else (I386?)."
+      eerror "-> Either invoke grml-live with '-i amd64' or adjust the architecture class. Exiting."
+      bailout
+   fi
 fi
 
-# set $ARCH
-[ -n "$ARCH" ] || ARCH="$(dpkg --print-architecture)"
 if grep -q -- 'FAI_DEBOOTSTRAP_OPTS.*--arch' "$NFSROOT_CONF" ; then
    sed "s/--arch [a-z0-9]* /--arch $ARCH /" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
 else
@@ -412,6 +457,12 @@ if [ -n "$BUILD_DIRTY" ]; then
 else
    [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
 
+   # provide inform fai about the ISO we build
+   [ -d "$CHROOT_OUTPUT/etc/" ] || mkdir -p "$CHROOT_OUTPUT/etc/"
+   echo '# This file has been generated by grml-live.' > "$CHROOT_OUTPUT/etc/grml_live_version"
+   [ -n "$GRML_LIVE_VERSION" ] && echo "GRML_LIVE_VERSION=$GRML_LIVE_VERSION" >> "$CHROOT_OUTPUT/etc/grml_live_version"
+   [ -n "$SUITE" ] && echo "SUITE=$SUITE" >> "$CHROOT_OUTPUT/etc/grml_live_version"
+
    if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
       FAI_ACTION=softupdate
    else
@@ -444,6 +495,8 @@ else
       "$HOSTNAME" $FAI_ACTION "$CHROOT_OUTPUT" $FAI_ARGS | tee -a $LOGFILE
       RC="$PIPESTATUS" # notice: bash-only
 
+      FORCE_ISO_REBUILD=true
+
       if [ "$RC" != 0 ] ; then
          log "Error while executing fai [exit code ${RC}]. Exiting."
          eerror "Error while executing fai [exit code ${RC}]. Exiting." ; eend 1
@@ -498,6 +551,8 @@ else
          einfo "Finished execution of stage 'fai dirinstall'"
       fi
 
+      einfo "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)."
+      eend 0
    fi
 fi # BUILD_DIRTY?
 # }}}
@@ -508,9 +563,9 @@ mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for s
 
 # i386:
 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
-   if [ -d "$BUILD_OUTPUT"/boot -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
-      log "$BUILD_OUTPUT/boot exists already, skipping stage 'boot'"
-      ewarn "$BUILD_OUTPUT/boot exists already, skipping stage 'boot'" ; eend 0
+   if [ -d "$BUILD_OUTPUT"/boot/isolinux -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
+      log "$BUILD_OUTPUT/boot/isolinux exists already, skipping stage 'boot'"
+      ewarn "$BUILD_OUTPUT/boot/isolinux exists already, skipping stage 'boot'" ; eend 0
    else
       # booting stuff:
       [ -d "$BUILD_OUTPUT"/boot/isolinux ] || mkdir -p "$BUILD_OUTPUT"/boot/isolinux
@@ -518,7 +573,17 @@ if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
 
       if [ -z "$NO_ADDONS" ] ; then
          [ -d "$BUILD_OUTPUT"/boot/addons   ] || mkdir -p "$BUILD_OUTPUT"/boot/addons
-         cp /boot/memtest86+.bin "$BUILD_OUTPUT"/boot/addons/memtest
+         if [ -r "$TEMPLATE_DIRECTORY"/boot/addons/memtest ] ; then
+            log "Installing $TEMPLATE_DIRECTORY/boot/addons/memtest"
+            cp "$TEMPLATE_DIRECTORY"/boot/addons/memtest "$BUILD_OUTPUT"/boot/addons/memtest
+         elif [ -r /boot/memtest86+.bin ] ; then
+            log "Installing /boot/memtest86+.bin"
+            cp /boot/memtest86+.bin "$BUILD_OUTPUT"/boot/addons/memtest
+         else
+            ewarn "No memtest binary found, skipping."
+            log "No memtest binary found, skipping."
+            eend 0
+         fi
       fi
 
       # if we don't have an initrd we a) can't boot and b) there was an error
@@ -551,15 +616,19 @@ if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
 
       cp ${TEMPLATE_DIRECTORY}/boot/isolinux/*  "$BUILD_OUTPUT"/boot/isolinux/
 
-      if [ -z "$NO_ADDONS" ] ; then
+      if [ -n "$NO_ADDONS" ] ; then
+         log "Skipping installation boot addons requested via \$NO_ADDONS."
+         einfo "Skipping installation boot addons requested via \$NO_ADDONS."
+         eend 0
+      else
          if ! [ -d /usr/share/grml-live/templates/boot/addons/bsd4grml ] ; then
-           ewarn "Boot addons not found, skipping therefor. (Consider installing package grml-live-addons)" ; eend 0
+           ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
          else
            # copy only files so we can handle bsd4grml on its own
            for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
                test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
            done
-  
+
            if [ -z "$NO_ADDONS_BSD4GRML" ] ; then
               cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
            fi
@@ -569,6 +638,9 @@ if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
       if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
          cp -a ${TEMPLATE_DIRECTORY}/boot/grub  "$BUILD_OUTPUT"/boot/
       fi
+      # make sure we have recent template files available, otherwise updating
+      # the strings like $GRML_NAME and $VERSION might be out of date
+      cp ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
 
       if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
          log "${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
@@ -599,23 +671,119 @@ if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
       sed -i "s/%VERSION%/$VERSION/"           "$BUILD_OUTPUT"/boot/grub/menu.lst
       sed -i "s/%GRML_NAME%/$SHORT_GRML_NAME/" "$BUILD_OUTPUT"/boot/grub/menu.lst
 
+      sed -i "s/%VERSION%/$VERSION/"           "$BUILD_OUTPUT"/boot/grub/grub.cfg
+      sed -i "s/%GRML_NAME%/$SHORT_GRML_NAME/" "$BUILD_OUTPUT"/boot/grub/grub.cfg
+
+      if [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] ; then
+         sed -i "s/%VERSION%/$VERSION/"            "$BUILD_OUTPUT"/boot/isolinux/grml.cfg
+         sed -i "s/%GRML_LONG_NAME%/$DISTRI_NAME/" "$BUILD_OUTPUT"/boot/isolinux/grml.cfg
+         sed -i "s/%GRML_NAME%/$SHORT_GRML_NAME/"  "$BUILD_OUTPUT"/boot/isolinux/grml.cfg
+         sed -i "s/%ARCH%/$ARCH/"                  "$BUILD_OUTPUT"/boot/isolinux/grml.cfg
+      fi
+
+      sed -i "s/%VERSION%/$VERSION/"           "$BUILD_OUTPUT"/boot/isolinux/grml.cfg
+      sed -i "s/%GRML_LONG_NAME%/$GRML_NAME/"  "$BUILD_OUTPUT"/boot/isolinux/grml.cfg
+      sed -i "s/%GRML_NAME%/$SHORT_GRML_NAME/" "$BUILD_OUTPUT"/boot/isolinux/grml.cfg
+      sed -i "s/%ARCH%/$ARCH/"                 "$BUILD_OUTPUT"/boot/isolinux/grml.cfg
+
+      sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/" "$BUILD_OUTPUT"/boot/isolinux/vesamenu.cfg
+      sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/" "$BUILD_OUTPUT"/boot/isolinux/vesamenu.cfg
+
       # make sure the squashfs filename is set accordingly:
       GRML_NAME_SQUASHFS="$GRML_NAME.squashfs"
       sed -i "s/%GRML_NAME_SQUASHFS%/$GRML_NAME_SQUASHFS/" "$BUILD_OUTPUT"/boot/isolinux/isolinux.cfg
       sed -i "s/%GRML_NAME_SQUASHFS%/$GRML_NAME_SQUASHFS/" "$BUILD_OUTPUT"/boot/isolinux/syslinux.cfg
+      sed -i "s/%GRML_NAME_SQUASHFS%/$GRML_NAME_SQUASHFS/" "$BUILD_OUTPUT"/boot/grub/menu.lst
 
       GRML_NAME_SQUASHFS="$(cut_string 20 "$GRML_NAME_SQUASHFS")"
       GRML_NAME_SQUASHFS="$(extend_string_end 20 "$GRML_NAME_SQUASHFS")"
       sed -i "s/%GRML_NAME_SQUASHFS%/$GRML_NAME_SQUASHFS/" "$BUILD_OUTPUT"/boot/isolinux/f4
       sed -i "s/%GRML_NAME_SQUASHFS%/$GRML_NAME_SQUASHFS/" "$BUILD_OUTPUT"/boot/isolinux/f5
 
+      if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
+         log "including grml.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
+         echo "include grml.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
+         [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
+      else # assume we are building a custom distribution:
+         log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
+         einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
+         if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
+           log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
+           eindent
+           einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
+           eoutdent
+           eend $?
+        else
+           log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
+           echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
+           [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
+         fi
+      fi
+
+      # use old style console based isolinux method only if requested:
+      if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
+         log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
+         einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
+         if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
+           einfo "include for console.cfg already foud, nothing to do."
+           eend 0
+         else
+           log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
+           einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
+           echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
+           eend $?
+         fi
+      else
+         log 'Using graphical boot menu.'
+         if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
+           log "include for vesamenu.cfg already foud, nothing to do."
+         else
+           log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
+           echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
+         fi
+      fi
+
+      # jump back to grub from bsd4grml:
+      if [ -e "$BUILD_OUTPUT"/boot/grub/stage2 ]; then
+         GRUB_LEGACY=stage2
+      else
+         GRUB_LEGACY=stage2_eltorito
+      fi
+      if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
+         if [ -e "$BUILD_OUTPUT"/boot/grub/core.img ]; then
+            GRUB_VERSION=2
+         else
+            GRUB_VERSION=1
+         fi
+
+         # why not ed(1)?
+         for file in "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 \
+                     "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.cfg; do
+             sed -i -e "s!%GRUB_VERSION%!$GRUB_VERSION!g" \
+                    -e "s!%GRUB_LEGACY%!$GRUB_LEGACY!g" "$file"
+         done
+
+         sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
+      fi
+      if [ -e "$BUILD_OUTPUT"/boot/grub/$GRUB_LEGACY ]; then
+         sed -i "s/%GRUB_LEGACY%/$GRUB_LEGACY/g" "$BUILD_OUTPUT"/boot/grub/menu.lst
+         sed -i "s/%GRUB_LEGACY%/$GRUB_LEGACY/g" "$BUILD_OUTPUT"/boot/grub/grub.cfg
+      else
+         sed -i "/%GRUB_LEGACY%/d" "$BUILD_OUTPUT"/boot/grub/menu.lst
+         sed -i "/%GRUB_LEGACY%/d" "$BUILD_OUTPUT"/boot/grub/grub.cfg
+      fi
+
       # autostart for Windows:
       if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
          cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
       fi
 
       # windows-binaries:
-      if [ -n "$WINDOWS_BINARIES" ] ; then
+      if [ -n "$NO_WINDOWS_BINARIES" ] ; then
+         log "Skipping download of windows binaries as requested via \$NO_WINDOWS_BINARIES."
+         einfo "Skipping download of windows binaries as requested via \$NO_WINDOWS_BINARIES."
+         eend 0
+      else
          if [ -f "$BUILD_OUTPUT"/windows/putty.exe ] ; then
             log "$BUILD_OUTPUT/windows exists already, skipping stage 'WINDOWS_BINARIES'"
             ewarn "$BUILD_OUTPUT/windows exists already, skipping stage 'WINDOWS_BINARIES'" ; eend 0
@@ -629,19 +797,33 @@ if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
                  done )
             fi
          fi
-      log "Finished execution of stage 'WINDOWS_BINARIES' [$(date)]"
-      einfo "Finished execution of stage 'WINDOWS_BINARIES'" ; eend 0
+         log "Finished execution of stage 'WINDOWS_BINARIES' [$(date)]"
+         einfo "Finished execution of stage 'WINDOWS_BINARIES'" ; eend 0
       fi
+
+   FORCE_ISO_REBUILD=true
    einfo "Finished execution of stage 'boot'" ; eend 0
    fi
-# ppc:
-elif [ "$ARCH" = powerpc ] ; then
-    ewarn 'Warning: formorer, it is your turn. :)'>&2
-# unsuported:
 else
+   log 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
    eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
 fi
 
+# support installation of local files into the chroot/ISO
+if [ -n "$CHROOT_INSTALL" ] ; then
+  if ! [ -d "$CHROOT_INSTALL" ] ; then
+     log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
+     ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
+  else
+     log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
+     einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
+     rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
+     eend $?
+     einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
+     FORCE_ISO_REBUILD=true
+  fi
+fi
+
 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
    log "$BUILD_OUTPUT/live exists already, skipping stage 'squashfs'"
    ewarn "$BUILD_OUTPUT/live exists already, skipping stage 'squashfs'" ; eend 0
@@ -700,6 +882,8 @@ else
       rm -f "${SQUASHFS_OUTPUT}"
       bailout
    fi
+
+   FORCE_ISO_REBUILD=true
 fi
 
 # create md5sum file:
@@ -717,20 +901,73 @@ elif [ "$BOOT_METHOD" = "grub" ] ; then
    BOOT_FILE="boot/grub/stage2_eltorito"
 fi
 
-if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
-   log "$ISO_OUTPUT exists already, skipping stage 'iso build'"
-   ewarn "$ISO_OUTPUT exists already, skipping stage 'iso build'" ; eend 0
+if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ]  ; then
+   log "$ISO_OUTPUT/${ISO_NAME} exists already, skipping stage 'iso build'"
+   ewarn "$ISO_OUTPUT/${ISO_NAME} exists already, skipping stage 'iso build'" ; eend 0
 else
    mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
 
+   if $FORCE_ISO_REBUILD ; then
+      log "Forcing rebuild of ISO because files on ISO have been modified."
+      einfo "Forcing rebuild of ISO because files on ISO have been modified."
+   fi
+
+   # support mkisofs as well as genisoimage
+   if which mkisofs >/dev/null 2>&1; then
+      MKISOFS='mkisofs'
+   elif which genisoimage >/dev/null 2>&1; then
+      MKISOFS='genisoimage'
+   else
+      log "Sorry, neither mkisofs nor genisoimage available - can not create ISO."
+      eerror "Sorry, neither mkisofs nor genisoimage available - can not create ISO." ; eend 1
+      bailout
+   fi
+
    CURRENT_DIR=$(pwd)
    if cd "$BUILD_OUTPUT" ; then
-      log "mkisofs -V '${GRML_NAME} ${VERSION}' -publisher 'grml-live | grml.org' -l -r -J -no-emul-boot -boot-load-size 4 -boot-info-table -b $BOOT_FILE -o ${ISO_OUTPUT}/${ISO_NAME} ."
-      mkisofs -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
+      log "$MKISOFS -V '${GRML_NAME} ${VERSION}' -publisher 'grml-live | grml.org' -l -r -J -no-emul-boot -boot-load-size 4 -boot-info-table -b $BOOT_FILE -o ${ISO_OUTPUT}/${ISO_NAME} ."
+      "$MKISOFS" -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
               -l -r -J -no-emul-boot -boot-load-size 4 -boot-info-table    \
-              -b $BOOT_FILE \
+              -b $BOOT_FILE -no-pad \
               -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
 
+      # pad the output ISO to multiples of 256 KiB for partition table support
+      siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
+      cyls=$((siz / 512 / 32 / 16 + 1))   # C=$cyls H=16 S=32
+      siz=$((cyls * 16 * 32 * 512))   # size after padding
+      dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
+         of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
+
+      # support disabling hybrid ISO image
+      if [ "$HYBRID_METHOD" = "disable" ] ; then\
+         log "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
+         einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
+         eend 0
+      # use isohybrid only on request
+      elif [ "$HYBRID_METHOD" = "isohybrid" ] ; then
+         if ! which isohybrid >/dev/null 2>&1 ; then
+           bailout 12 "isohybrid binary not found - please install syslinux/syslinux-common"
+         else
+           log "Creating hybrid ISO file with isohybrid method"
+           einfo "Creating hybrid ISO file with isohybrid method"
+           isohybrid "${ISO_OUTPUT}/${ISO_NAME}"
+           eend $?
+         fi
+      # by default use our manifold boot method:
+      else
+         if ! [ -r boot/grub/core.img ] ; then
+           ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
+         else
+           log "Creating hybrid ISO file with manifold method"
+           einfo "Creating hybrid ISO file with manifold method"
+           echo 1 63 | \
+               mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 1 -p 0x83 -g $cyls:16:32 | \
+               cat - boot/grub/core.img | \
+               dd conv=notrunc of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
+           eend $?
+         fi
+      fi
+
       # generate md5sum and sha1sum of ISO if we are using class 'RELEASE':
       case $CLASSES in *RELEASE*)
          [ "$RC" = 0 ] && \
@@ -761,8 +998,8 @@ fi
 
 # finalize {{{
 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
-einfo "Sucessfully finished execution of $PN [running ${SECONDS} seconds]" ; eend 0
-log "Sucessfully finished execution of $PN [running ${SECONDS} seconds]"
+einfo "Successfully finished execution of $PN [running ${SECONDS} seconds]" ; eend 0
+log "Successfully finished execution of $PN [running ${SECONDS} seconds]"
 bailout 0
 # }}}