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