Refactored addon handlng for grml-live.
[grml-live.git] / grml-live
1 #!/bin/bash
2 # Filename:      grml-live
3 # Purpose:       build process script for generating a (grml based) Linux Live-ISO
4 # Authors:       grml-team (grml.org),
5 #                (c) Michael Prokop <mika@grml.org>,
6 #                (c) Thorsten Glaser <tg@mirbsd.org>
7 # Bug-Reports:   see http://grml.org/bugs/
8 # License:       This file is licensed under the GPL v2 or any later version.
9 ################################################################################
10
11 # some misc and global stuff {{{
12 export LANG=C
13 export LC_ALL=C
14
15 # define function getfilesize before "set -e"
16 if stat --help >/dev/null 2>&1; then
17   getfilesize='stat -c %s'  # GNU stat
18 else
19   getfilesize='stat -f %z'  # BSD stat
20 fi
21
22 # exit on any error:
23 set -e
24
25 # global variables
26 GRML_LIVE_VERSION='0.9.26'
27 PN="$(basename $0)"
28 CMDLINE="$0 $@"
29 ISO_DATE="$(date +%Y-%m-%d)"
30 SOURCES_LIST_FILE='/etc/grml/fai/apt/sources.list'
31 ADDONS_LIST_FILE='/boot/isolinux/addons_list.cfg'
32 # }}}
33
34 # usage information {{{
35 usage()
36 {
37   echo "
38 $PN - build process script for generating a (grml based) Linux Live-ISO
39
40 Usage: $PN [options, see as follows]
41
42    -a <architecture>       architecture; available values: i386 and amd64
43    -b                      build the ISO without updating the chroot via FAI
44    -B                      build the ISO without touching the chroot (skips cleanup)
45    -c <classe[s]>          classes to be used for building the ISO via FAI
46    -C <configfile>         configuration file for grml-live
47    -F                      force execution without prompting
48    -g <grml_name>          set the grml flavour name
49    -h                      display short usage information and exit
50    -i <iso_name>           name of ISO
51    -I <src_directory>      directory which provides files that should become
52                            part of the chroot/ISO
53    -n                      skip generation of ISO
54    -o <output_directory>   main output directory of the build process
55    -q                      skip mksquashfs
56    -r <release_name>       release name
57    -s <suite>              Debian suite; values: etch, lenny, squeeze, sid
58    -t <template_directory> place of the templates
59    -u                      update existing chroot instead of rebuilding it from scratch
60    -v <version_number>     specify version number of the release
61    -V                      increase verbosity in the build process
62    -z                      use ZLIB instead of LZMA compression (depends on
63                            squashfs-tools version)
64
65 Usage examples:
66
67     $PN
68     $PN -c GRMLBASE,GRML_MEDIUM,I386 -o /dev/shm/grml
69     $PN -c GRMLBASE,GRML_SMALL,REMOVE_DOCS,I386 -g grml-small -v 1.0
70     $PN -c GRMLBASE,GRML_FULL,I386 -i grml_0.0-1.iso -v 0.0-1
71     $PN -c GRMLBASE,GRML_FULL,I386 -s sid -V -r 'grml-live rocks'
72
73 More details: man grml-live + /usr/share/doc/grml-live/grml-live.html
74               http://grml.org/grml-live/
75
76 Please send your bug reports and feedback to the grml-team: http://grml.org/bugs/
77 "
78 }
79
80 # make sure it's possible to get usage information without being
81 # root or actually executing the script
82 if [ "$1" = '-h' -o "$1" = '--help' ] ; then
83    usage
84    [ "$(id -u 2>/dev/null)" != 0 ] && echo "Please notice that this script requires root permissions."
85    exit 0
86 fi
87 # }}}
88
89 # some runtime checks {{{
90 # we need root permissions for the build-process:
91 if [ "$(id -u 2>/dev/null)" != 0 ] ; then
92    echo "Error: please run this script with uid 0 (root)." >&2
93    exit 1
94 fi
95
96 if [ -r /var/run/fai/FAI_INSTALLATION_IN_PROGRESS ] ; then
97    echo "/usr/sbin/fai already running or was aborted before.">&2
98    echo "You may remove /var/run/fai/FAI_INSTALLATION_IN_PROGRESS and try again.">&2
99    exit 1
100 fi
101
102 # see #449236
103 if [ -r /var/run/fai/fai_softupdate_is_running ] ; then
104    echo "/usr/sbin/fai softupdate already running or was aborted before.">&2
105    echo "You may remove /var/run/fai/fai_softupdate_is_running and try again.">&2
106    exit 1
107 fi
108 # }}}
109
110 # lsb-functions and configuration stuff {{{
111 # make sure they are not set by default
112 VERBOSE=''
113 FORCE=''
114 UPDATE=''
115 BUILD_ONLY=''
116 BUILD_DIRTY=''
117 HOSTNAME=''
118
119 if [ -r /etc/grml/lsb-functions ] ; then
120    . /etc/grml/lsb-functions
121 else
122    einfo()  { echo "  [*] $*" ;}
123    eerror() { echo "  [!] $*">&2 ;}
124    ewarn()  { echo "  [x] $*" ;}
125    eend()   { return 0 ;}
126 fi
127
128 # source main configuration file:
129 LIVE_CONF=/etc/grml/grml-live.conf
130 . $LIVE_CONF
131 # }}}
132
133 # clean exit {{{
134 bailout() {
135   rm -f /var/run/fai/fai_softupdate_is_running \
136         /var/run/fai/FAI_INSTALLATION_IN_PROGRESS
137   [ -n "$SQUASHFS_STDERR" ]  && rm -rf "$SQUASHFS_STDERR"
138   [ -n "$MIRROR_DIRECTORY" ] && umount "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
139   [ -n "$1" ] && EXIT="$1" || EXIT="1"
140   [ -n "$2" ] && eerror "$2">&2
141   log "------------------------------------------------------------------------------"
142   exit "$EXIT"
143 }
144 trap bailout 1 2 3 3 6 9 14 15
145 # }}}
146
147 # log file stuff {{{
148 [ -n "$LOGFILE" ] || LOGFILE=/var/log/grml-live.log
149 touch $LOGFILE
150 chown root:adm $LOGFILE
151 chmod 664 $LOGFILE
152 # }}}
153
154 # some important functions {{{
155
156 # log output:
157 # usage: log "string to log"
158 log() { echo "$*" >> $LOGFILE ; }
159
160 # cut string at character number int = $1
161 # usage: cut_string 5 "1234567890" will output "12345"
162 cut_string() {
163   [ -n "$2" ] || return 1
164   echo "$2" | head -c "$1"; echo -ne "\n"
165 }
166
167 # prepend int = $1 spaces before string = $2
168 # usage: extend_string_begin 5 "123" will output "  123"
169 extend_string_begin() {
170   [ -n "$2" ] || return 1
171   local COUNT="$(echo $2 | wc -c)"
172   local FILL="$(expr $COUNT - $1)"
173   while [ "$FILL" -gt 1 ] ; do
174     echo -n " "
175     local FILL=$(expr $FILL - 1)
176   done
177   while [ "$FILL" -lt 1 ] ; do
178     echo -n " "
179     local FILL=$(expr $FILL + 1)
180   done
181   echo "$2" | head -c "$1"; echo -ne "\n"
182 }
183
184 # append int = $1 spaces to string = $2
185 # usage: extend_string_begin 5 "123" will output "123  "
186 extend_string_end() {
187   [ -n "$2" ] || return 1
188   echo -n "$2" | head -c "$1"
189   local COUNT="$(echo $2 | wc -c)"
190   local FILL="$(expr $COUNT - $1)"
191   while [ "$FILL" -gt 1 ] ; do
192     echo -n " "
193     local FILL=$(expr $FILL - 1)
194   done
195   while [ "$FILL" -lt 1 ] ; do
196     echo -n " "
197     local FILL=$(expr $FILL + 1)
198   done
199   echo -ne "\n"
200 }
201 # }}}
202
203 # read local (non-packaged) configuration {{{
204 LOCAL_CONFIG=/etc/grml/grml-live.local
205 if [ -r "$LOCAL_CONFIG" ] ; then
206    log "Sourcing $LOCAL_CONFIG"
207    . $LOCAL_CONFIG
208 else
209    log "No $LOCAL_CONFIG found, not sourcing it"
210    LOCAL_CONFIG=''
211 fi
212 # }}}
213
214 # command line parsing {{{
215 while getopts "a:C:c:g:i:I:o:r:s:t:v:bBFnquVz" opt; do
216   case "$opt" in
217     a) ARCH="$OPTARG" ;;
218     b) BUILD_ONLY=1 ;;
219     B) BUILD_DIRTY=1 ;;
220     c) CLASSES="$OPTARG" ;;
221     C) CONFIG="$OPTARG" ;;
222     g) GRML_NAME="$OPTARG" ;;
223     i) ISO_NAME="$OPTARG" ;;
224     I) CHROOT_INSTALL="$OPTARG" ;;
225     n) SKIP_MKISOFS=1 ;;
226     o) OUTPUT="$OPTARG" ;;
227     q) SKIP_MKSQUASHFS=1 ;;
228     r) RELEASENAME="$OPTARG" ;;
229     s) SUITE="$OPTARG" ;;
230     t) TEMPLATE_DIRECTORY="$OPTARG";;
231     v) VERSION="$OPTARG" ;;
232     F) FORCE=1 ;;
233     u) UPDATE=1 ;;
234     V) VERBOSE="-v" ;;
235     z) SQUASHFS_ZLIB="-nolzma" ;;
236     ?) echo "invalid option -$OPTARG" >&2; bailout 1 ;;
237   esac
238 done
239 shift $(($OPTIND - 1))  # set ARGV to the first not parsed commandline parameter
240 # }}}
241
242 # assume sane defaults (if not set already) {{{
243 [ -n "$ARCH" ]             || ARCH="$(dpkg --print-architecture)"
244 [ -n "$BOOT_METHOD" ]      || BOOT_METHOD='isolinux'
245 [ -n "$BUILD_OUTPUT" ]     || BUILD_OUTPUT="$OUTPUT/grml_cd"
246 [ -n "$CHROOT_OUTPUT" ]    || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
247 [ -n "$CLASSES" ]          || CLASSES="GRMLBASE,GRML_MEDIUM,I386"
248 [ -n "$DISTRI_INFO" ]      || DISTRI_INFO='Grml - Live Linux for system administrators   '
249 [ -n "$DISTRI_NAME" ]      || DISTRI_NAME="grml"
250 [ -n "$DISTRI_SPLASH" ]    || DISTRI_SPLASH='grml.png'
251 [ -n "$FORCE_ISO_REBUILD" ] || FORCE_ISO_REBUILD="false"
252 [ -n "$GRML_FAI_CONFIG" ]  || GRML_FAI_CONFIG='/etc/grml/fai'
253 [ -n "$GRML_NAME" ]        || GRML_NAME='grml'
254 [ -n "$HOSTNAME" ]         || HOSTNAME='grml'
255 [ -n "$ISO_OUTPUT" ]       || ISO_OUTPUT="$OUTPUT/grml_isos"
256 [ -n "$NFSROOT_CONF" ]     || NFSROOT_CONF='/etc/grml/fai/make-fai-nfsroot.conf'
257 [ -n "$OUTPUT" ]           || OUTPUT='/grml/grml-live'
258 [ -n "$RELEASENAME" ]      || RELEASENAME='grml-live rocks'
259 [ -n "$SQUASHFS_EXCLUDES_FILE " ] || SQUASHFS_EXCLUDES_FILE='/etc/grml/fai/squashfs-excludes'
260 [ -n "$SUITE" ]            || SUITE='lenny'
261 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
262 [ -n "$USERNAME" ]         || USERNAME='grml'
263 [ -n "$VERSION" ]          || VERSION='0.0.1'
264 [ -n "$WINDOWS_BINARIES" ] || WINDOWS_BINARIES='http://the.earth.li/~sgtatham/putty/latest/x86/'
265 # }}}
266
267 # some misc checks before executing FAI {{{
268 [ -n "$CLASSES" ] || bailout 1 "Error: \$CLASSES unset, please set it in $LIVE_CONF or
269 specify it on the command line using the -c option."
270 [ -n "$OUTPUT" ] || bailout 1 "Error: \$OUTPUT unset, please set it in $LIVE_CONF or
271 specify it on the command line using the -o option."
272
273 # set subdirectories according to $OUTPUT:
274 CHROOT_OUTPUT="$OUTPUT/grml_chroot"
275 BUILD_OUTPUT="$OUTPUT/grml_cd"
276 ISO_OUTPUT="$OUTPUT/grml_isos"
277
278 # trim characters that are known to cause problems inside $GRML_NAME;
279 # for example isolinux does not like '-' inside the directory name
280 [ -n "$GRML_NAME" ] && export SHORT_NAME="$(echo $GRML_NAME | tr -d ',./;\- ')"
281
282 # export variables to have them available in fai scripts:
283 [ -n "$GRML_NAME" ]   && export GRML_NAME="$GRML_NAME"
284 [ -n "$RELEASENAME" ] && export RELEASENAME="$RELEASENAME"
285 # }}}
286
287 # clean/zero grml-live logfile {{{
288 if [ -n "$ZERO_LOGFILE" ] ; then
289    echo -n > $LOGFILE
290 fi
291 # }}}
292
293 # clean/zero/remove old FAI directory {{{
294 if [ -n "$ZERO_FAI_LOGFILE" ] ; then
295    if [ -d /var/log/fai/"$HOSTNAME" ] ; then
296       rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last)"
297       rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-dirinstall)"
298       rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-softupdate)"
299       rm -f /var/log/fai/"$HOSTNAME"/last \
300             /var/log/fai/"$HOSTNAME"/last-dirinstall \
301             /var/log/fai/"$HOSTNAME"/last-softupdate
302    fi
303 fi
304 # }}}
305
306 # ask user whether the setup is ok {{{
307 if [ -z "$FORCE" ] ; then
308    echo
309    echo "${PN} [${GRML_LIVE_VERSION}]: check your configuration (or use -F to force execution):"
310    echo
311    echo "  FAI classes:       $CLASSES"
312    [ -r "$LOCAL_CONFIG" ]       && echo "  local config:      /etc/grml/grml-live.local"
313    [ -n "$CONFIG" ]             && echo "  configuration:     $CONFIG"
314    echo "  main directory:    $OUTPUT"
315    [ -n "$CHROOT_OUTPUT" ]      && echo "  chroot target:     $CHROOT_OUTPUT"
316    [ -n "$BUILD_OUTPUT" ]       && echo "  build target:      $BUILD_OUTPUT"
317    [ -n "$ISO_OUTPUT" ]         && echo "  ISO target:        $ISO_OUTPUT"
318    [ -n "$GRML_NAME" ]          && echo "  grml name:         $GRML_NAME"
319    [ -n "$RELEASENAME" ]        && echo "  release name:      $RELEASENAME"
320    [ -n "$VERSION" ]            && echo "  grml version:      $VERSION"
321    [ -n "$SUITE" ]              && echo "  Debian suite:      $SUITE"
322    [ -n "$ARCH" ]               && echo "  Architecture:      $ARCH"
323    [ -n "$BOOT_METHOD" ]        && echo "  Boot method:       $BOOT_METHOD"
324    [ -n "$TEMPLATE_DIRECTORY" ] && echo "  Template files:    $TEMPLATE_DIRECTORY"
325    [ -n "$CHROOT_INSTALL" ]     && echo "  Install files from directory to chroot:  $CHROOT_INSTALL"
326    [ -n "$FAI_ARGS" ]           && echo "  additional arguments for FAI: $FAI_ARGS"
327    [ -n "$LOGFILE" ]            && echo "  Logging to file:   $LOGFILE"
328    [ -n "$SQUASHFS_ZLIB" ]      && echo "  Using ZLIB (instead of LZMA) compression."
329    [ -n "$SQUASHFS_OPTIONS" ]   && echo "  Using SQUASHFS_OPTIONS ${SQUASHFS_OPTIONS}"
330    [ -n "$VERBOSE" ]            && echo "  Using VERBOSE mode."
331    [ -n "$UPDATE" ]             && echo "  Executing UPDATE instead of fresh installation."
332    [ -n "$SKIP_MKSQUASHFS" ]    && echo "  Skipping creation of SQUASHFS file."
333    [ -n "$SKIP_MKISOFS" ]       && echo "  Skipping creation of ISO file."
334    [ -n "$BUILD_ONLY" ]         && echo "  Executing BUILD_ONLY instead of fresh installation or UPDATE."
335    [ -n "$BUILD_DIRTY" ]        && echo "  Executing BUILD_DIRTY to leave chroot untouched."
336    echo
337    echo -n "Is this ok for you? [y/N] "
338    read a
339    if ! [ "$a" = 'y' -o "$a" = 'Y' ] ; then
340       bailout 1 "Exiting as requested."
341    fi
342    echo
343 fi
344
345 if [ -n "$CONFIG" ] ; then
346    if ! [ -f "$CONFIG" ] ; then
347       log    "Error: $CONFIG could not be read. Exiting. [$(date)]"
348       eerror "Error: $CONFIG could not be read. Exiting." ; eend 1
349       bailout 1
350    else
351       log "Sourcing $CONFIG"
352       . $CONFIG
353    fi
354 fi
355
356 start_seconds=$(cut -d . -f 1 /proc/uptime)
357 log "------------------------------------------------------------------------------"
358 log "Starting grml-live [${GRML_LIVE_VERSION}] run on $(date)"
359 log "Executed grml-live command line:"
360 log "$CMDLINE"
361
362 einfo "Logging actions to logfile $LOGFILE"
363 # }}}
364
365 # on-the-fly configuration {{{
366 if [ -n "$MIRROR_DIRECTORY" ] ; then
367    if ! [ -d "$MIRROR_DIRECTORY/debian" ] ; then
368       log    "Error: $MIRROR_DIRECTORY/debian does not seem to exist. Exiting. [$(date)]"
369       eerror "Error: $MIRROR_DIRECTORY/debian does not seem to exist. Exiting." ; eend 1
370       bailout 1
371    fi
372    cat > "$SOURCES_LIST_FILE" << EOF
373 # NOTE: This file is *NOT* meant for manual customisation! This file is
374 # modified by grml-live and any changes might be overriden.
375 # You might consider using GRML_LIVE_SOURCES in /etc/grml/grml-live.conf*
376 # and using /etc/grml/fai/files/etc/apt instead!'
377 EOF
378    echo "$MIRROR_SOURCES" >> "$SOURCES_LIST_FILE"
379    if [ -n "$GRML_LIVE_SOURCES" ] ; then
380       echo "$GRML_LIVE_SOURCES" >> "$SOURCES_LIST_FILE"
381    fi
382 elif [ -n "$GRML_LIVE_SOURCES" ] ; then
383    cat > "$SOURCES_LIST_FILE" << EOF
384 # NOTE: This file is *NOT* meant for manual customisation! This file is
385 # modified by grml-live and any changes might be overriden.
386 # You might consider using GRML_LIVE_SOURCES in /etc/grml/grml-live.conf*
387 # and using /etc/grml/fai/files/etc/apt instead!'
388 EOF
389    echo "$GRML_LIVE_SOURCES" >> "$SOURCES_LIST_FILE"
390 fi
391
392 if [ -n "$FAI_DEBOOTSTRAP" ] ; then
393    sed "s#^FAI_DEBOOTSTRAP=.*#FAI_DEBOOTSTRAP=\"$FAI_DEBOOTSTRAP\"#" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
394 fi
395
396 # does this suck? YES!
397 # /usr/share/debootstrap/scripts/unstable does not exist, instead use 'sid':
398 case $SUITE in
399    unstable) SUITE='sid' ;;
400    # make sure that we *NEVER* write any broken suite name to sources.list,
401    # otherwise we won't be able to adjust it one next (correct) execution
402    stable)   ;;
403    testing)  ;;
404    etch)     ;;
405    lenny)    ;;
406    squeeze)  ;;
407    sid)      ;;
408    *) echo "Sorry, $SUITE is not a valid Debian suite, exiting.">&2; bailout 1 ;;
409 esac
410
411 DIST=" etch\| stable\| lenny\| squeeze\| testing\| sid\| unstable"
412 sed "s/\(^deb .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/" "$SOURCES_LIST_FILE" | sponge "$SOURCES_LIST_FILE"
413 for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" ; do
414     if [ -n "$file" ] ; then
415        sed "s/^SUITE=.*/SUITE=\"$SUITE\"/" $file | sponge $file
416        sed "s/\(^deb .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/" "$file" | sponge "$file"
417     fi
418 done
419
420 # notice: activate grml-live pool only if we are building against unstable:
421 if grep -qe unstable -qe sid "$SOURCES_LIST_FILE" ; then
422    grep -q 'grml-live.*main' "$SOURCES_LIST_FILE" || \
423    grep grml-stable "$SOURCES_LIST_FILE" | \
424         sed 's/grml-stable/grml-live/' >> "$SOURCES_LIST_FILE"
425 else
426    grep -q 'grml-live.*main' "$SOURCES_LIST_FILE" && \
427    sed 's/.*grml-live.*/# removed grml-live repository/' "$SOURCES_LIST_FILE" | sponge "$SOURCES_LIST_FILE"
428 fi
429
430 for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" "$NFSROOT_CONF" ; do
431     if [ -n "$file" ] ; then
432        sed "s|^FAI_DEBOOTSTRAP=\"[a-z]* |FAI_DEBOOTSTRAP=\"$SUITE |" "$file" | sponge "$file"
433     fi
434 done
435
436 # validate whether the specified architecture class matches the
437 # architecture (option), otherwise installation of kernel will fail
438 if echo $CLASSES | grep -qi i386 ; then
439    if ! [[ "$ARCH" == "i386" ]] ; then
440       log    "Error: You specified the I386 class but are trying to build something else (AMD64?)."
441       eerror "Error: You specified the I386 class but are trying to build something else (AMD64?)."
442       eerror "Tip:   Either invoke grml-live with '-i i386' or adjust the architecture class. Exiting."
443       eend 1
444       bailout
445    fi
446 elif echo $CLASSES | grep -qi amd64 ; then
447    if ! [[ "$ARCH" == "amd64" ]] ; then
448       log    "Error: You specified the AMD64 class but are trying to build something else (I386?)."
449       eerror "Error: You specified the AMD64 class but are trying to build something else (I386?)."
450       eerror "Tip:   Either invoke grml-live with '-i amd64' or adjust the architecture class. Exiting."
451       eend 1
452       bailout
453    fi
454 fi
455
456 if grep -q -- 'FAI_DEBOOTSTRAP_OPTS.*--arch' "$NFSROOT_CONF" ; then
457    sed "s/--arch [a-z0-9]* /--arch $ARCH /" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
458 else
459    sed "s|^FAI_DEBOOTSTRAP_OPTS=\"\(.*\)|FAI_DEBOOTSTRAP_OPTS=\"--arch $ARCH \1|" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
460 fi
461 # }}}
462
463 # CHROOT_OUTPUT - execute FAI {{{
464 if [ -n "$BUILD_DIRTY" ]; then
465    log   "Skipping stage 'fai' as requested via option -B"
466    ewarn "Skipping stage 'fai' as requested via option -B" ; eend 0
467 else
468    [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
469
470    # provide inform fai about the ISO we build
471    [ -d "$CHROOT_OUTPUT/etc/" ] || mkdir -p "$CHROOT_OUTPUT/etc/"
472    echo '# This file has been generated by grml-live.' > "$CHROOT_OUTPUT/etc/grml_live_version"
473    [ -n "$GRML_LIVE_VERSION" ] && echo "GRML_LIVE_VERSION=$GRML_LIVE_VERSION" >> "$CHROOT_OUTPUT/etc/grml_live_version"
474    [ -n "$SUITE" ] && echo "SUITE=$SUITE" >> "$CHROOT_OUTPUT/etc/grml_live_version"
475
476    if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
477       FAI_ACTION=softupdate
478    else
479       FAI_ACTION=dirinstall
480    fi
481
482    if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
483       if ! [ -r "$CHROOT_OUTPUT/etc/debian_version" ] ; then
484          log    "Error: does not look like you have a working chroot. Updating/building not possible."
485          eerror "Error: does not look like you have a working chroot. Updating/building not possible. (Drop -u/-b option?)"
486          eend 1
487          bailout 20
488       fi
489    fi
490
491    if [ -d "$CHROOT_OUTPUT/bin" -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
492       log   "Skiping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already."
493       ewarn "Skiping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already." ; eend 0
494    else
495       mkdir -p "$CHROOT_OUTPUT" || bailout 5 "Problem with creating $CHROOT_OUTPUT for FAI"
496
497       if [ -n "${MIRROR_DIRECTORY}" ] ; then
498          mkdir -p "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
499          mount --bind "${MIRROR_DIRECTORY}" "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
500       fi
501
502       log "Executed FAI command line:"
503       log "BUILD_ONLY=$BUILD_ONLY fai $VERBOSE -C $GRML_FAI_CONFIG -c$CLASSES -u $HOSTNAME $FAI_ACTION $CHROOT_OUTPUT $FAI_ARGS"
504       BUILD_ONLY="$BUILD_ONLY" fai $VERBOSE -C "$GRML_FAI_CONFIG" -c"$CLASSES" -u \
505       "$HOSTNAME" $FAI_ACTION "$CHROOT_OUTPUT" $FAI_ARGS | tee -a $LOGFILE
506       RC="$PIPESTATUS" # notice: bash-only
507
508       FORCE_ISO_REBUILD=true
509
510       if [ "$RC" != 0 ] ; then
511          log    "Error: critical error while executing fai [exit code ${RC}]. Exiting."
512          eerror "Error: critical error while executing fai [exit code ${RC}]. Exiting." ; eend 1
513          bailout 1
514       else
515          log "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$ISO_DATE]"
516          echo "$GRML_NAME $VERSION Release Codename $RELEASENAME [$ISO_DATE]" > $CHROOT_OUTPUT/etc/grml_version
517          chmod 644 $CHROOT_OUTPUT/etc/grml_version
518          einfo "Rebuilding initramfs"
519          # make sure new /etc/grml_version reaches the initramfs:
520          # chroot $CHROOT_OUTPUT update-initramfs -u -t => might break when using kernel-package :(
521          chroot $CHROOT_OUTPUT update-initramfs -u -k all
522          eend $?
523       fi
524
525       # Remove all FAI logs from chroot if class RELEASE is used:
526       if [ -f "$CHROOT_OUTPUT"/etc/grml_fai_release ] ; then
527          rm -rf "$CHROOT_OUTPUT"/var/log/fai/*
528       fi
529
530       # make sure we don't leave any mounts - FAI doesn't remove them always
531       umount $CHROOT_OUTPUT/proc 2>/dev/null || /bin/true
532       umount $CHROOT_OUTPUT/sys  2>/dev/null || /bin/true
533       umount $CHROOT_OUTPUT/dev/pts 2>/dev/null || /bin/true
534       umount $CHROOT_OUTPUT/dev 2>/dev/null || /bin/true
535
536       [ -n "$MIRROR_DIRECTORY" ] && umount "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
537
538       # notice: 'fai dirinstall' does not seem to exit appropriate, so:
539       ERROR=''
540       CHECKLOG=/var/log/fai/$HOSTNAME/last
541       if [ -r "$CHECKLOG/software.log" ] ; then
542          # 1 errors during executing of commands
543          grep 'dpkg: error processing' $CHECKLOG/software.log >> $LOGFILE && ERROR=1
544          grep 'E: Method http has died unexpectedly!' $CHECKLOG/software.log >> $LOGFILE && ERROR=2
545          grep 'ERROR: chroot' $CHECKLOG/software.log >> $LOGFILE && ERROR=3
546          grep 'E: Failed to fetch' $CHECKLOG/software.log >> $LOGFILE && ERROR=4
547          grep 'Unable to write mmap - msync (28 No space left on device)' $CHECKLOG/software.log >> $LOGFILE && ERROR=5
548       fi
549
550       if [ -r "$CHECKLOG/shell.log" ] ; then
551          grep 'FAILED with exit code' $CHECKLOG/shell.log >> $LOGFILE && ERROR=2
552       fi
553
554       if [ -n "$ERROR" ] ; then
555          log    "Error: there was a critical error [${ERROR}] during execution of stage 'fai dirinstall' [$(date)]"
556          eerror "Error: there was a critical error during execution of stage 'fai dirinstall'"
557          eerror "Note:  check out ${CHECKLOG}/ for details. [exit ${ERROR}]"
558          eend 1
559          bailout 1
560       else
561          log "Finished execution of stage 'fai dirinstall' [$(date)]"
562          einfo "Finished execution of stage 'fai dirinstall'"
563       fi
564
565       einfo "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
566       log   "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
567       eend 0
568    fi
569 fi # BUILD_DIRTY?
570 # }}}
571
572 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
573 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
574 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
575
576 # i386:
577 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
578    if [ -d "$BUILD_OUTPUT"/boot/isolinux -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
579       log   "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already."
580       ewarn "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already." ; eend 0
581    else
582       # booting stuff:
583       [ -d "$BUILD_OUTPUT"/boot/isolinux ] || mkdir -p "$BUILD_OUTPUT"/boot/isolinux
584       [ -d "$BUILD_OUTPUT"/boot/"${SHORT_NAME}" ] || mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"
585
586       if [ -z "$NO_ADDONS" ] ; then
587          [ -d "$BUILD_OUTPUT"/boot/addons   ] || mkdir -p "$BUILD_OUTPUT"/boot/addons
588          if [ -r "$TEMPLATE_DIRECTORY"/boot/addons/memtest ] ; then
589             log "Installing $TEMPLATE_DIRECTORY/boot/addons/memtest"
590             cp "$TEMPLATE_DIRECTORY"/boot/addons/memtest "$BUILD_OUTPUT"/boot/addons/memtest
591          elif [ -r /boot/memtest86+.bin ] ; then
592             log "Installing /boot/memtest86+.bin"
593             cp /boot/memtest86+.bin "$BUILD_OUTPUT"/boot/addons/memtest
594          else
595             ewarn "No memtest binary found, skipping."
596             log "No memtest binary found, skipping."
597             eend 0
598          fi
599       fi
600
601       # if we don't have an initrd we a) can't boot and b) there was an error
602       # during build, so check for the file:
603       INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
604       if [ -n "$INITRD" ] ; then
605          cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/initrd.gz
606          find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
607       else
608          log    "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
609          eerror "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
610          bailout 10
611       fi
612
613       KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
614       if [ -n "$KERNEL_IMAGE" ] ; then
615          cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/linux26
616       else
617          log    "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
618          eerror "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
619          bailout 11
620       fi
621
622       [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
623       if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
624          log    "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
625          eerror "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
626          bailout 8
627       fi
628
629       # *always* copy files to output directory so the variables
630       # get adjusted according to the build
631       cp ${TEMPLATE_DIRECTORY}/boot/isolinux/*  "$BUILD_OUTPUT"/boot/isolinux/
632
633       if [ -n "$NO_ADDONS" ] ; then
634          log "Skipping installation boot addons requested via \$NO_ADDONS."
635          einfo "Skipping installation boot addons requested via \$NO_ADDONS."
636          eend 0
637       else
638          if ! [ -d /usr/share/grml-live/templates/boot/addons/bsd4grml ] ; then
639            ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
640          else
641            # copy only files so we can handle bsd4grml on its own
642            for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
643                test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
644            done
645
646            if [ -z "$NO_ADDONS_BSD4GRML" ] ; then
647               cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
648            fi
649          fi
650       fi
651
652       if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
653          cp -a ${TEMPLATE_DIRECTORY}/boot/grub  "$BUILD_OUTPUT"/boot/
654       fi
655       # make sure we have recent template files available, otherwise updating
656       # the strings like $GRML_NAME and $VERSION might be out of date
657       cp ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
658
659       if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
660          log    "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
661          eerror "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
662          bailout 9
663       fi
664
665       [ -d "$BUILD_OUTPUT"/GRML ] || mkdir "$BUILD_OUTPUT"/GRML
666       cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/
667
668       # adjust boot splash information:
669       RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
670       RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
671       RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
672
673       sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/grml-version
674       sed -i "s/%DATE%/$ISO_DATE/"                                  "$BUILD_OUTPUT"/GRML/grml-version
675
676       # make sure the squashfs filename is set accordingly:
677       SQUASHFS_NAME="$GRML_NAME.squashfs"
678
679       # adjust all variables in the templates with the according distribution information
680       for file in "${BUILD_OUTPUT}"/boot/isolinux/*.cfg "${BUILD_OUTPUT}"/boot/isolinux/*.msg \
681                   "${BUILD_OUTPUT}"/boot/grub/* ; do
682         sed -i "s/%ARCH%/$ARCH/g"                    "${file}"
683         sed -i "s/%DATE%/$ISO_DATE/g"                "${file}"
684         sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/g"      "${file}"
685         sed -i "s/%DISTRI_NAME%/$DISTRI_NAME/g"      "${file}"
686         sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/g"  "${file}"
687         sed -i "s/%GRML_NAME%/$GRML_NAME/g"          "${file}"
688         sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/g"  "${file}"
689         sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/g"    "${file}"
690         sed -i "s/%SHORT_NAME%/$SHORT_NAME/g"        "${file}"
691         sed -i "s/%VERSION%/$VERSION/g"              "${file}"
692       done
693
694       # adjust bootsplash accordingly but make sure the string has the according lenght
695       SQUASHFS_NAME="$(cut_string 20 "$SQUASHFS_NAME")"
696       SQUASHFS_NAME="$(extend_string_end 20 "$SQUASHFS_NAME")"
697       sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "$BUILD_OUTPUT"/boot/isolinux/f4
698       sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "$BUILD_OUTPUT"/boot/isolinux/f5
699
700       # generate addon list
701       rm "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
702       for name in $(ls "${BUILD_OUTPUT}"/boot/isolinux/addon_*.cfg) ; do
703         include_name=$(basename "$name")
704         echo "include $include_name"  >> "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
705       done
706
707       if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
708          log "including grmlmain.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
709          echo "include grmlmain.cfg"    >  "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
710          echo "include default.cfg"     >  "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
711          echo "include menuoptions.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
712          echo "include grml.cfg"        >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
713          echo "include options.cfg"     >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
714          if [ ! -n "$NO_ADDONS" ] ; then
715            echo "include addons.cfg"    >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
716          fi
717          echo "include isoprompt.cfg"   >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
718          echo "include hd.cfg"          >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
719          echo "include hidden.cfg"      >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
720       else # assume we are building a custom distribution:
721          log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
722          einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
723          if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
724            log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
725            eindent
726            einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
727            eoutdent
728            eend $?
729         else
730            log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
731            echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
732            [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
733          fi
734       fi
735
736       # use old style console based isolinux method only if requested:
737       if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
738          log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
739          einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
740          if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
741            einfo "include for console.cfg already foud, nothing to do."
742            eend 0
743          else
744            log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
745            einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
746            echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
747            eend $?
748          fi
749       else
750          log 'Using graphical boot menu.'
751          if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
752            log "include for vesamenu.cfg already foud, nothing to do."
753          else
754            log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
755            echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
756          fi
757       fi
758
759       # jump back to grub from bsd4grml:
760       if [ -e "$BUILD_OUTPUT"/boot/grub/stage2 ]; then
761          GRUB_LEGACY=stage2
762       else
763          GRUB_LEGACY=stage2_eltorito
764       fi
765       if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
766          if [ -e "$BUILD_OUTPUT"/boot/grub/core.img ]; then
767             GRUB_VERSION=2
768          else
769             GRUB_VERSION=1
770          fi
771
772          for file in "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 \
773                      "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.cfg \
774                      "$BUILD_OUTPUT"/boot/isolinux/addons.cfg \
775                      "$BUILD_OUTPUT"/boot/isolinux/syslinux.cfg \
776                      "$BUILD_OUTPUT"/boot/grub/grub.cfg \
777                      "$BUILD_OUTPUT"/boot/grub/menu.lst ; do
778              if [ -e "$file" ] ; then
779                sed -i -e "s!%GRUB_VERSION%!$GRUB_VERSION!g" \
780                       -e "s!%GRUB_LEGACY%!$GRUB_LEGACY!g" "$file"
781              fi
782          done
783
784          sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
785       fi
786
787       if [ -e "$BUILD_OUTPUT"/boot/grub/$GRUB_LEGACY ]; then
788          sed -i "s/%GRUB_LEGACY%/$GRUB_LEGACY/g" "$BUILD_OUTPUT"/boot/grub/menu.lst
789          sed -i "s/%GRUB_LEGACY%/$GRUB_LEGACY/g" "$BUILD_OUTPUT"/boot/grub/grub.cfg
790       else
791          sed -i "/%GRUB_LEGACY%/d" "$BUILD_OUTPUT"/boot/grub/menu.lst
792          sed -i "/%GRUB_LEGACY%/d" "$BUILD_OUTPUT"/boot/grub/grub.cfg
793       fi
794
795       # autostart for Windows:
796       if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
797          cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
798       fi
799
800       # windows-binaries:
801       if [ -n "$NO_WINDOWS_BINARIES" ] ; then
802          log   "Skipping download of windows binaries as requested via \$NO_WINDOWS_BINARIES."
803          einfo "Skipping download of windows binaries as requested via \$NO_WINDOWS_BINARIES."
804          eend 0
805       else
806          if [ -f "$BUILD_OUTPUT"/windows/putty.exe ] ; then
807             log   "Skipping stage 'WINDOWS_BINARIES' as $BUILD_OUTPUT/windows exists already."
808             ewarn "Skipping stage 'WINDOWS_BINARIES' as $BUILD_OUTPUT/windows exists already." ; eend 0
809          else
810             if ! [ -d "$BUILD_OUTPUT"/windows ] ; then
811                mkdir "$BUILD_OUTPUT"/windows
812                ( cd "$BUILD_OUTPUT"/windows
813                  for file in pageant plink pscp psftp putty puttygen ; do
814                     wget -O ${file}.exe ${WINDOWS_BINARIES}/${file}.exe
815                     md5sum ${file}.exe > ${file}.exe.md5
816                  done )
817             fi
818
819             log "Finished execution of stage 'WINDOWS_BINARIES' [$(date)]"
820             einfo "Finished execution of stage 'WINDOWS_BINARIES'" ; eend 0
821          fi
822       fi
823
824    FORCE_ISO_REBUILD=true
825    einfo "Finished execution of stage 'boot'" ; eend 0
826    fi
827 else
828    log    'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
829    eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
830    bailout
831 fi
832
833 # support installation of local files into the chroot/ISO
834 if [ -n "$CHROOT_INSTALL" ] ; then
835   if ! [ -d "$CHROOT_INSTALL" ] ; then
836      log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
837      ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
838   else
839      log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
840      einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
841      rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
842      eend $?
843      einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
844      FORCE_ISO_REBUILD=true
845   fi
846 fi
847
848 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
849    log   "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
850    ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
851 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
852    log   "Skipping stage 'squashfs' as requested via option -q"
853    ewarn "Skipping stage 'squashfs' as requested via option -q" ; eend 0
854 else
855    [ -d "$BUILD_OUTPUT"/live ] || mkdir "$BUILD_OUTPUT"/live
856    # make sure we don't leave (even an empty) base.tgz:
857    [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
858
859    # $SQUASHFS_BINARY is specified in the configuration:
860    if [ -n "$SQUASHFS_BINARY" ] ; then
861       if ! which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
862          log    "Error: specified mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
863          eerror "Error: specified mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
864          bailout
865       fi
866    else # no $SQUASHFS_BINARY configured, let's find the according binary:
867       # Note: this is ALL for backward compability and yes: it's serious PITA.
868       # We'll definitely drop this once people build >2.6.28-grml* only and
869       # the squashfs-tools vs. squashfs-lzma-tools + zlib vs. lzma situation
870       # is settling...
871
872       # assume the safe default if mksquashfs-lzma isn't present:
873       if ! which mksquashfs-lzma >/dev/null 2>&1 ; then
874          SQUASHFS_BINARY='mksquashfs'
875       else # mksquashfs-lzma is available since squashfs-lzma-tools 4.0:
876          # if the user wants to use zlib then don't use mksquashfs-lzma:
877          if echo "$SQUASHFS_OPTIONS" | grep -q -- "-nolzma" || [ -n "$SQUASHFS_ZLIB" ] ; then
878             SQUASHFS_BINARY='mksquashfs'
879          else # neither -nolzma nor -z and mksquashfs-lzma is available:
880             SQUASHFS_BINARY='mksquashfs-lzma'
881
882             # backwards compability: someone has squashfs-lzma-tools >=4 installed but
883             # 1) doesn't use -nolzma in $SQUASHFS_OPTIONS or the grml-live's -z option *and*
884             # 2) builds against kernel version <=2.6.28-grml[64]
885             if ls $CHROOT_OUTPUT/boot/vmlinuz* >/dev/null 2>&1 ; then
886                KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
887
888                case $KERNEL_IMAGE in
889                   *vmlinuz-2.6.28-grml*|*vmlinuz-2.6.26-grml*|*vmlinuz-2.6.23-grml*)
890                   log   "You seem to be building a system with squashfs file format 3 using squashfs-lzma-tools >=4."
891                   ewarn "You seem to be building a system with squashfs file format 3 using squashfs-lzma-tools >=4."
892                   ewarn "|-> Consider installing squashfs-lzma-tools 3.3-1 for support of file format version 3."
893                   ewarn "|-> Trying the mksquashfs binary instead of mksquashfs-lzma (though this might fail)."
894                   ewarn "\`-> Visit http://grml.org/grml-live/#current_state for further details if building fails."
895                   eend 0
896                   SQUASHFS_BINARY='mksquashfs'
897                   ;;
898                esac
899             fi
900
901             # if we still want to use mksquashfs-lzma then let's choose
902             # blocksize 256k as this gives best result with regards to time + comopression
903             [[ "$SQUASHFS_BINARY" == "mksquashfs-lzma" ]] && SQUASHFS_OPTIONS="-b 256k -lzma"
904          fi
905
906       fi
907    fi
908
909    # make sure mksquashfs can handle the according option:
910    if [ -n "$SQUASHFS_ZLIB" ] ; then
911       $SQUASHFS_BINARY --help 2>&1 | grep -q -- "$SQUASHFS_ZLIB" || SQUASHFS_ZLIB=''
912    fi
913
914    # make sure to drop the -nolzma option if it's not available:
915    if echo "$SQUASHFS_OPTIONS" | grep -q -- "-nolzma" ; then
916       if ! $SQUASHFS_BINARY --help 2>&1 | grep -q -- '-nolzma' ; then
917          log   "The $SQUASHFS_BINARY binary does NOT support the nolzma option, dropping it and using default mode."
918          ewarn "The $SQUASHFS_BINARY binary does NOT support the nolzma option, dropping it and using default mode."
919          SQUASHFS_OPTIONS="$(echo $SQUASHFS_OPTIONS | sed 's/-nolzma//g')"
920          eend 0
921       fi
922    fi
923
924    # make sure to drop the -lzma option if it's not available:
925    if echo "$SQUASHFS_OPTIONS" | grep -q -- "-lzma" ; then
926       if ! $SQUASHFS_BINARY --help 2>&1 | grep -q -- '-lzma' ; then
927          log   "The $SQUASHFS_BINARY binary does NOT support the lzma option, dropping it and using default mode."
928          ewarn "The $SQUASHFS_BINARY binary does NOT support the lzma option, dropping it and using default mode."
929          SQUASHFS_OPTIONS="$(echo $SQUASHFS_OPTIONS | sed 's/-lzma//g')"
930          eend 0
931       fi
932    fi
933
934    # support exclusion of files via exclude-file:
935    if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
936       SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE"
937    fi
938
939    # get rid of unnecessary files when building grml-small for final release:
940    if echo "$CLASSES" | grep -q GRML_SMALL ; then
941       SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
942    fi
943
944    # check whether we have the according binary available:
945    if ! which $SQUASHFS_BINARY >/dev/null 2>&1 ; then
946       log    "Error: mksquashfs binary (${SQUASHFS_BINARY}) could not be found. Exiting."
947       eerror "Error: mksquashfs binary (${SQUASHFS_BINARY}) could not be found. Exiting."
948       eerror "|-> Make sure to install either squashfs-tools and/or squashfs-lzma-tools."
949       eerror "\`-> Visit http://grml.org/grml-live/#current_state for further details."
950       eend 1
951       package
952       bailout
953    fi
954
955    SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
956
957    [ -n "$SQUASHFS_OPTIONS" ]  && SQUASHFS_INFO_MSG="$SQUASHFS_OPTIONS"
958    [ -n "$SQUASHFS_ZLIB" ]     && SQUASHFS_INFO_MSG="$SQUASHFS_INFO_MSG $SQUASHFS_ZLIB"
959    [ -n "$SQUASHFS_INFO_MSG" ] && SQUASHFS_INFO_MSG="using options: $SQUASHFS_INFO_MSG"
960    einfo "Squashfs build information: running binary $SQUASHFS_BINARY $SQUASHFS_INFO_MSG"
961
962    log "$SQUASHFS_BINARY $CHROOT_OUTPUT/* $BUILD_OUTPUT/live/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS $SQUASHFS_ZLIB"
963
964    if $SQUASHFS_BINARY $CHROOT_OUTPUT/* $BUILD_OUTPUT/live/"${GRML_NAME}".squashfs \
965       -noappend $SQUASHFS_OPTIONS $SQUASHFS_ZLIB 2>"${SQUASHFS_STDERR}" ; then
966       echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/filesystem.module
967       log "Finished execution of stage 'squashfs' [$(date)]"
968       einfo "Finished execution of stage 'squashfs'" ; eend 0
969    else
970       log    "Error: there was a critical error executing stage 'squashfs' [$(date)]:"
971       log    "$(cat $SQUASHFS_STDERR)"
972       eerror "Error: there was a critical error executing stage 'squashfs':" ; eend 1
973       cat    "${SQUASHFS_STDERR}"
974       bailout
975    fi
976
977    FORCE_ISO_REBUILD=true
978 fi
979
980 # create md5sum file:
981 ( cd $BUILD_OUTPUT/GRML &&
982 find .. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
983 # }}}
984
985 # ISO_OUTPUT - mkisofs {{{
986 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
987 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
988
989 if [ "$BOOT_METHOD" = "isolinux" ] ; then
990    BOOT_FILE="boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
991 elif [ "$BOOT_METHOD" = "grub" ] ; then
992    BOOT_FILE="boot/grub/stage2_eltorito"
993 fi
994
995 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ]  ; then
996    log   "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already."
997    ewarn "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already." ; eend 0
998 elif [ -n "$SKIP_MKISOFS" ] ; then
999    log   "Skipping stage 'iso build' as requested via option -n"
1000    ewarn "Skipping stage 'iso build' as requested via option -n" ; eend 0
1001 else
1002    mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
1003
1004    if $FORCE_ISO_REBUILD && ! [ -f "${ISO_OUTPUT}/${ISO_NAME}" ] ; then
1005       log   "Forcing rebuild of ISO because files on ISO have been modified."
1006       einfo "Forcing rebuild of ISO because files on ISO have been modified."
1007    fi
1008
1009    # support mkisofs as well as genisoimage
1010    if which mkisofs >/dev/null 2>&1; then
1011       MKISOFS='mkisofs'
1012    elif which genisoimage >/dev/null 2>&1; then
1013       MKISOFS='genisoimage'
1014    else
1015       log    "Error: neither mkisofs nor genisoimage available - can not create ISO."
1016       eerror "Error: neither mkisofs nor genisoimage available - can not create ISO." ; eend 1
1017       bailout
1018    fi
1019
1020    CURRENT_DIR=$(pwd)
1021    if cd "$BUILD_OUTPUT" ; then
1022       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} ."
1023       "$MKISOFS" -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
1024               -l -r -J -no-emul-boot -boot-load-size 4 -boot-info-table    \
1025               -b $BOOT_FILE -no-pad \
1026               -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
1027
1028       # pad the output ISO to multiples of 256 KiB for partition table support
1029       siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
1030       cyls=$((siz / 512 / 32 / 16 + 1))   # C=$cyls H=16 S=32
1031       siz=$((cyls * 16 * 32 * 512))   # size after padding
1032       dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
1033          of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
1034
1035       # support disabling hybrid ISO image
1036       if [ "$HYBRID_METHOD" = "disable" ] ; then\
1037          log   "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1038          einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1039          eend 0
1040       # use isohybrid only on request
1041       elif [ "$HYBRID_METHOD" = "isohybrid" ] ; then
1042          if ! which isohybrid >/dev/null 2>&1 ; then
1043            bailout 12 "isohybrid binary not found - please install syslinux/syslinux-common"
1044          else
1045            log "Creating hybrid ISO file with isohybrid method"
1046            einfo "Creating hybrid ISO file with isohybrid method"
1047            isohybrid "${ISO_OUTPUT}/${ISO_NAME}"
1048            eend $?
1049          fi
1050       # by default use our manifold boot method:
1051       else
1052          if ! [ -r boot/grub/core.img ] ; then
1053            ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
1054          else
1055            log "Creating hybrid ISO file with manifold method"
1056            einfo "Creating hybrid ISO file with manifold method"
1057            echo 1 63 | \
1058                mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 1 -p 0x83 -g $cyls:16:32 | \
1059                cat - boot/grub/core.img | \
1060                dd conv=notrunc of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
1061            eend $?
1062          fi
1063       fi
1064
1065       # generate md5sum and sha1sum of ISO if we are using class 'RELEASE':
1066       case $CLASSES in *RELEASE*)
1067          [ "$RC" = 0 ] && \
1068          (
1069            if cd $ISO_OUTPUT ; then
1070              md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
1071              touch -r ${ISO_NAME} ${ISO_NAME}.md5
1072              sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
1073              touch -r ${ISO_NAME} ${ISO_NAME}.sha1
1074            fi
1075          )
1076          ;;
1077       esac
1078
1079       cd $CURRENT_DIR
1080    fi
1081
1082    if [ "$RC" = 0 ] ; then
1083       log   "Finished execution of stage 'iso build' [$(date)]"
1084       einfo "Finished execution of stage 'iso build'" ; eend 0
1085    else
1086       log    "Error: there was a critical error ($RC) executing stage 'iso build' [$(date)]"
1087       eerror "Error: there was a critical error executing stage 'iso build'" ; eend 1
1088       bailout $RC
1089    fi
1090 fi
1091 # }}}
1092
1093 # finalize {{{
1094 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
1095 einfo "Successfully finished execution of $PN [running ${SECONDS} seconds]" ; eend 0
1096 log "Successfully finished execution of $PN [running ${SECONDS} seconds]"
1097 bailout 0
1098 # }}}
1099
1100 ## END OF FILE #################################################################
1101 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=3