Fix simple typos in usage information dialog
[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.23'
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='lenny'
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 => might break when using kernel-package :(
520          chroot $CHROOT_OUTPUT update-initramfs -u -k all
521          eend $?
522       fi
523
524       # Remove all FAI logs from chroot if class RELEASE is used:
525       if [ -f "$CHROOT_OUTPUT"/etc/grml_fai_release ] ; then
526          rm -rf "$CHROOT_OUTPUT"/var/log/fai/*
527       fi
528
529       # make sure we don't leave any mounts - FAI doesn't remove them always
530       umount $CHROOT_OUTPUT/proc 2>/dev/null || /bin/true
531       umount $CHROOT_OUTPUT/sys  2>/dev/null || /bin/true
532       umount $CHROOT_OUTPUT/dev/pts 2>/dev/null || /bin/true
533       umount $CHROOT_OUTPUT/dev 2>/dev/null || /bin/true
534
535       [ -n "$MIRROR_DIRECTORY" ] && umount "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
536
537       # notice: 'fai dirinstall' does not seem to exit appropriate, so:
538       ERROR=''
539       CHECKLOG=/var/log/fai/$HOSTNAME/last
540       if [ -r "$CHECKLOG/software.log" ] ; then
541          # 1 errors during executing of commands
542          grep 'dpkg: error processing' $CHECKLOG/software.log >> $LOGFILE && ERROR=1
543          grep 'E: Method http has died unexpectedly!' $CHECKLOG/software.log >> $LOGFILE && ERROR=2
544          grep 'ERROR: chroot' $CHECKLOG/software.log >> $LOGFILE && ERROR=3
545          grep 'E: Failed to fetch' $CHECKLOG/software.log >> $LOGFILE && ERROR=4
546          grep 'Unable to write mmap - msync (28 No space left on device)' $CHECKLOG/software.log >> $LOGFILE && ERROR=5
547       fi
548
549       if [ -r "$CHECKLOG/shell.log" ] ; then
550          grep 'FAILED with exit code' $CHECKLOG/shell.log >> $LOGFILE && ERROR=2
551       fi
552
553       if [ -n "$ERROR" ] ; then
554          log    "Error: there was a critical error [${ERROR}] during execution of stage 'fai dirinstall' [$(date)]"
555          eerror "Error: there was a critical error during execution of stage 'fai dirinstall'"
556          eerror "Note:  check out ${CHECKLOG}/ for details. [exit ${ERROR}]"
557          eend 1
558          bailout 1
559       else
560          log "Finished execution of stage 'fai dirinstall' [$(date)]"
561          einfo "Finished execution of stage 'fai dirinstall'"
562       fi
563
564       einfo "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)."
565       log   "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)."
566       eend 0
567    fi
568 fi # BUILD_DIRTY?
569 # }}}
570
571 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
572 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
573 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
574
575 # i386:
576 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
577    if [ -d "$BUILD_OUTPUT"/boot/isolinux -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
578       log   "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already."
579       ewarn "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already." ; eend 0
580    else
581       # booting stuff:
582       [ -d "$BUILD_OUTPUT"/boot/isolinux ] || mkdir -p "$BUILD_OUTPUT"/boot/isolinux
583       [ -d "$BUILD_OUTPUT"/boot/"${SHORT_GRML_NAME}" ] || mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_GRML_NAME}"
584
585       if [ -z "$NO_ADDONS" ] ; then
586          [ -d "$BUILD_OUTPUT"/boot/addons   ] || mkdir -p "$BUILD_OUTPUT"/boot/addons
587          if [ -r "$TEMPLATE_DIRECTORY"/boot/addons/memtest ] ; then
588             log "Installing $TEMPLATE_DIRECTORY/boot/addons/memtest"
589             cp "$TEMPLATE_DIRECTORY"/boot/addons/memtest "$BUILD_OUTPUT"/boot/addons/memtest
590          elif [ -r /boot/memtest86+.bin ] ; then
591             log "Installing /boot/memtest86+.bin"
592             cp /boot/memtest86+.bin "$BUILD_OUTPUT"/boot/addons/memtest
593          else
594             ewarn "No memtest binary found, skipping."
595             log "No memtest binary found, skipping."
596             eend 0
597          fi
598       fi
599
600       # if we don't have an initrd we a) can't boot and b) there was an error
601       # during build, so check for the file:
602       INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
603       if [ -n "$INITRD" ] ; then
604          cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_GRML_NAME}"/initrd.gz
605          find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
606       else
607          log    "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
608          eerror "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
609          bailout 10
610       fi
611
612       KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
613       if [ -n "$KERNEL_IMAGE" ] ; then
614          cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_GRML_NAME}"/linux26
615       else
616          log    "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
617          eerror "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
618          bailout 11
619       fi
620
621       [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
622       if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
623          log    "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
624          eerror "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
625          bailout 8
626       fi
627
628       cp ${TEMPLATE_DIRECTORY}/boot/isolinux/*  "$BUILD_OUTPUT"/boot/isolinux/
629
630       if [ -n "$NO_ADDONS" ] ; then
631          log "Skipping installation boot addons requested via \$NO_ADDONS."
632          einfo "Skipping installation boot addons requested via \$NO_ADDONS."
633          eend 0
634       else
635          if ! [ -d /usr/share/grml-live/templates/boot/addons/bsd4grml ] ; then
636            ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
637          else
638            # copy only files so we can handle bsd4grml on its own
639            for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
640                test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
641            done
642
643            if [ -z "$NO_ADDONS_BSD4GRML" ] ; then
644               cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
645            fi
646          fi
647       fi
648
649       if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
650          cp -a ${TEMPLATE_DIRECTORY}/boot/grub  "$BUILD_OUTPUT"/boot/
651       fi
652       # make sure we have recent template files available, otherwise updating
653       # the strings like $GRML_NAME and $VERSION might be out of date
654       cp ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
655
656       if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
657          log    "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
658          eerror "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
659          bailout 9
660       fi
661
662       [ -d "$BUILD_OUTPUT"/GRML ] || mkdir "$BUILD_OUTPUT"/GRML
663       cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/
664
665       # adjust boot splash information:
666       RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
667       RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
668       RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
669
670       sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/grml-version
671       sed -i "s/%DATE%/$ISO_DATE/"             "$BUILD_OUTPUT"/GRML/grml-version
672
673       sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/" "$BUILD_OUTPUT"/boot/isolinux/boot.msg
674       sed -i "s/%DATE%/$ISO_DATE/"             "$BUILD_OUTPUT"/boot/isolinux/boot.msg
675
676       sed -i "s/%GRML_NAME%/$SHORT_GRML_NAME/" "$BUILD_OUTPUT"/boot/isolinux/isolinux.cfg
677       sed -i "s/%GRML_NAME%/$SHORT_GRML_NAME/" "$BUILD_OUTPUT"/boot/isolinux/syslinux.cfg
678
679       sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/" "$BUILD_OUTPUT"/boot/isolinux/boot-beep.msg
680       sed -i "s/%DATE%/$ISO_DATE/"             "$BUILD_OUTPUT"/boot/isolinux/boot-beep.msg
681
682       sed -i "s/%VERSION%/$VERSION/"           "$BUILD_OUTPUT"/boot/grub/menu.lst
683       sed -i "s/%GRML_NAME%/$SHORT_GRML_NAME/" "$BUILD_OUTPUT"/boot/grub/menu.lst
684
685       sed -i "s/%VERSION%/$VERSION/"           "$BUILD_OUTPUT"/boot/grub/grub.cfg
686       sed -i "s/%GRML_NAME%/$SHORT_GRML_NAME/" "$BUILD_OUTPUT"/boot/grub/grub.cfg
687
688       if [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] ; then
689          sed -i "s/%VERSION%/$VERSION/"            "$BUILD_OUTPUT"/boot/isolinux/grml.cfg
690          sed -i "s/%GRML_LONG_NAME%/$DISTRI_NAME/" "$BUILD_OUTPUT"/boot/isolinux/grml.cfg
691          sed -i "s/%GRML_NAME%/$SHORT_GRML_NAME/"  "$BUILD_OUTPUT"/boot/isolinux/grml.cfg
692          sed -i "s/%ARCH%/$ARCH/"                  "$BUILD_OUTPUT"/boot/isolinux/grml.cfg
693       fi
694
695       sed -i "s/%VERSION%/$VERSION/"           "$BUILD_OUTPUT"/boot/isolinux/grml.cfg
696       sed -i "s/%GRML_LONG_NAME%/$GRML_NAME/"  "$BUILD_OUTPUT"/boot/isolinux/grml.cfg
697       sed -i "s/%GRML_NAME%/$SHORT_GRML_NAME/" "$BUILD_OUTPUT"/boot/isolinux/grml.cfg
698       sed -i "s/%ARCH%/$ARCH/"                 "$BUILD_OUTPUT"/boot/isolinux/grml.cfg
699
700       sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/" "$BUILD_OUTPUT"/boot/isolinux/vesamenu.cfg
701       sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/" "$BUILD_OUTPUT"/boot/isolinux/vesamenu.cfg
702
703       # make sure the squashfs filename is set accordingly:
704       GRML_NAME_SQUASHFS="$GRML_NAME.squashfs"
705       sed -i "s/%GRML_NAME_SQUASHFS%/$GRML_NAME_SQUASHFS/" "$BUILD_OUTPUT"/boot/isolinux/isolinux.cfg
706       sed -i "s/%GRML_NAME_SQUASHFS%/$GRML_NAME_SQUASHFS/" "$BUILD_OUTPUT"/boot/isolinux/syslinux.cfg
707       sed -i "s/%GRML_NAME_SQUASHFS%/$GRML_NAME_SQUASHFS/" "$BUILD_OUTPUT"/boot/grub/menu.lst
708
709       GRML_NAME_SQUASHFS="$(cut_string 20 "$GRML_NAME_SQUASHFS")"
710       GRML_NAME_SQUASHFS="$(extend_string_end 20 "$GRML_NAME_SQUASHFS")"
711       sed -i "s/%GRML_NAME_SQUASHFS%/$GRML_NAME_SQUASHFS/" "$BUILD_OUTPUT"/boot/isolinux/f4
712       sed -i "s/%GRML_NAME_SQUASHFS%/$GRML_NAME_SQUASHFS/" "$BUILD_OUTPUT"/boot/isolinux/f5
713
714       if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
715          log "including grml.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
716          echo "include grml.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
717          [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
718       else # assume we are building a custom distribution:
719          log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
720          einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
721          if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
722            log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
723            eindent
724            einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
725            eoutdent
726            eend $?
727         else
728            log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
729            echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
730            [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
731          fi
732       fi
733
734       # use old style console based isolinux method only if requested:
735       if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
736          log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
737          einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
738          if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
739            einfo "include for console.cfg already foud, nothing to do."
740            eend 0
741          else
742            log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
743            einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
744            echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
745            eend $?
746          fi
747       else
748          log 'Using graphical boot menu.'
749          if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
750            log "include for vesamenu.cfg already foud, nothing to do."
751          else
752            log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
753            echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
754          fi
755       fi
756
757       # jump back to grub from bsd4grml:
758       if [ -e "$BUILD_OUTPUT"/boot/grub/stage2 ]; then
759          GRUB_LEGACY=stage2
760       else
761          GRUB_LEGACY=stage2_eltorito
762       fi
763       if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
764          if [ -e "$BUILD_OUTPUT"/boot/grub/core.img ]; then
765             GRUB_VERSION=2
766          else
767             GRUB_VERSION=1
768          fi
769
770          # why not ed(1)?
771          for file in "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 \
772                      "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.cfg; do
773              sed -i -e "s!%GRUB_VERSION%!$GRUB_VERSION!g" \
774                     -e "s!%GRUB_LEGACY%!$GRUB_LEGACY!g" "$file"
775          done
776
777          sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
778       fi
779       if [ -e "$BUILD_OUTPUT"/boot/grub/$GRUB_LEGACY ]; then
780          sed -i "s/%GRUB_LEGACY%/$GRUB_LEGACY/g" "$BUILD_OUTPUT"/boot/grub/menu.lst
781          sed -i "s/%GRUB_LEGACY%/$GRUB_LEGACY/g" "$BUILD_OUTPUT"/boot/grub/grub.cfg
782       else
783          sed -i "/%GRUB_LEGACY%/d" "$BUILD_OUTPUT"/boot/grub/menu.lst
784          sed -i "/%GRUB_LEGACY%/d" "$BUILD_OUTPUT"/boot/grub/grub.cfg
785       fi
786
787       # autostart for Windows:
788       if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
789          cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
790       fi
791
792       # windows-binaries:
793       if [ -n "$NO_WINDOWS_BINARIES" ] ; then
794          log   "Skipping download of windows binaries as requested via \$NO_WINDOWS_BINARIES."
795          einfo "Skipping download of windows binaries as requested via \$NO_WINDOWS_BINARIES."
796          eend 0
797       else
798          if [ -f "$BUILD_OUTPUT"/windows/putty.exe ] ; then
799             log   "Skipping stage 'WINDOWS_BINARIES' as $BUILD_OUTPUT/windows exists already."
800             ewarn "Skipping stage 'WINDOWS_BINARIES' as $BUILD_OUTPUT/windows exists already." ; eend 0
801          else
802             if ! [ -d "$BUILD_OUTPUT"/windows ] ; then
803                mkdir "$BUILD_OUTPUT"/windows
804                ( cd "$BUILD_OUTPUT"/windows
805                  for file in pageant plink pscp psftp putty puttygen ; do
806                     wget -O ${file}.exe ${WINDOWS_BINARIES}/${file}.exe
807                     md5sum ${file}.exe > ${file}.exe.md5
808                  done )
809             fi
810
811             log "Finished execution of stage 'WINDOWS_BINARIES' [$(date)]"
812             einfo "Finished execution of stage 'WINDOWS_BINARIES'" ; eend 0
813          fi
814       fi
815
816    FORCE_ISO_REBUILD=true
817    einfo "Finished execution of stage 'boot'" ; eend 0
818    fi
819 else
820    log    'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
821    eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
822    bailout
823 fi
824
825 # support installation of local files into the chroot/ISO
826 if [ -n "$CHROOT_INSTALL" ] ; then
827   if ! [ -d "$CHROOT_INSTALL" ] ; then
828      log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
829      ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
830   else
831      log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
832      einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
833      rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
834      eend $?
835      einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
836      FORCE_ISO_REBUILD=true
837   fi
838 fi
839
840 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
841    log   "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
842    ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
843 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
844    log   "Skipping stage 'squashfs' as requested via option -q"
845    ewarn "Skipping stage 'squashfs' as requested via option -q" ; eend 0
846 else
847    [ -d "$BUILD_OUTPUT"/live ] || mkdir "$BUILD_OUTPUT"/live
848    # make sure we don't leave (even an empty) base.tgz:
849    [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
850
851    # $SQUASHFS_BINARY is specified in the configuration:
852    if [ -n "$SQUASHFS_BINARY" ] ; then
853       if ! which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
854          log    "Error: specified mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
855          eerror "Error: specified mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
856          bailout
857       fi
858    else # no $SQUASHFS_BINARY configured, let's find the according binary:
859       # Note: this is ALL for backward compability and yes: it's serious PITA.
860       # We'll definitely drop this once people build >2.6.28-grml* only and
861       # the squashfs-tools vs. squashfs-lzma-tools + zlib vs. lzma situation
862       # is settling...
863
864       # assume the safe default if mksquashfs-lzma isn't present:
865       if ! which mksquashfs-lzma >/dev/null 2>&1 ; then
866          SQUASHFS_BINARY='mksquashfs'
867       else # mksquashfs-lzma is available since squashfs-lzma-tools 4.0:
868          # if the user wants to use zlib then don't use mksquashfs-lzma:
869          if echo "$SQUASHFS_OPTIONS" | grep -q -- "-nolzma" || [ -n "$SQUASHFS_ZLIB" ] ; then
870             SQUASHFS_BINARY='mksquashfs'
871          else # neither -nolzma nor -z and mksquashfs-lzma is available:
872             SQUASHFS_BINARY='mksquashfs-lzma'
873
874             # backwards compability: someone has squashfs-lzma-tools >=4 installed but
875             # 1) doesn't use -nolzma in $SQUASHFS_OPTIONS or the grml-live's -z option *and*
876             # 2) builds against kernel version <=2.6.28-grml[64]
877             if ls $CHROOT_OUTPUT/boot/vmlinuz* >/dev/null 2>&1 ; then
878                KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
879
880                case $KERNEL_IMAGE in
881                   *vmlinuz-2.6.28-grml*|*vmlinuz-2.6.26-grml*|*vmlinuz-2.6.23-grml*)
882                   log   "You seem to be building a system with squashfs file format 3 using squashfs-lzma-tools >=4."
883                   ewarn "You seem to be building a system with squashfs file format 3 using squashfs-lzma-tools >=4."
884                   ewarn "|-> Consider installing squashfs-lzma-tools 3.3-1 for support of file format version 3."
885                   ewarn "|-> Trying the mksquashfs binary instead of mksquashfs-lzma (though this might fail)."
886                   ewarn "\`-> Visit http://grml.org/grml-live/#current_state for further details if building fails."
887                   eend 0
888                   SQUASHFS_BINARY='mksquashfs'
889                   ;;
890                esac
891             fi
892
893             # if we still want to use mksquashfs-lzma then let's choose
894             # blocksize 256k as this gives best result with regards to time + comopression
895             [[ "$SQUASHFS_BINARY" == "mksquashfs-lzma" ]] && SQUASHFS_OPTIONS="-b 256k -lzma"
896          fi
897
898       fi
899    fi
900
901    # make sure mksquashfs can handle the according option:
902    if [ -n "$SQUASHFS_ZLIB" ] ; then
903       $SQUASHFS_BINARY --help 2>&1 | grep -q -- "$SQUASHFS_ZLIB" || SQUASHFS_ZLIB=''
904    fi
905
906    # make sure to drop the -nolzma option if it's not available:
907    if echo "$SQUASHFS_OPTIONS" | grep -q -- "-nolzma" ; then
908       if ! $SQUASHFS_BINARY --help 2>&1 | grep -q -- '-nolzma' ; then
909          log   "$SQUASHFS_BINARY does NOT support the nolzma option, dropping it and using default mode."
910          ewarn "$SQUASHFS_BINARY does NOT support the nolzma option, dropping it and using default mode."
911          SQUASHFS_OPTIONS="$(echo $SQUASHFS_OPTIONS | sed 's/-nolzma//g')"
912          eend 0
913       fi
914    fi
915
916    # make sure to drop the -lzma option if it's not available:
917    if echo "$SQUASHFS_OPTIONS" | grep -q -- "-lzma" ; then
918       if ! $SQUASHFS_BINARY --help 2>&1 | grep -q -- '-lzma' ; then
919          log   "$SQUASHFS_BINARY does NOT support the lzma option, dropping it and using default mode."
920          ewarn "$SQUASHFS_BINARY does NOT support the lzma option, dropping it and using default mode."
921          SQUASHFS_OPTIONS="$(echo $SQUASHFS_OPTIONS | sed 's/-lzma//g')"
922          eend 0
923       fi
924    fi
925
926    # support exclusion of files via exclude-file:
927    if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
928       SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE"
929    fi
930
931    # get rid of unnecessary files when building grml-small for final release:
932    if echo "$CLASSES" | grep -q GRML_SMALL ; then
933       SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
934    fi
935
936    # check whether we have the according binary available:
937    if ! which $SQUASHFS_BINARY >/dev/null 2>&1 ; then
938       log    "Error: mksquashfs binary (${SQUASHFS_BINARY}) could not be found. Exiting."
939       eerror "Error: mksquashfs binary (${SQUASHFS_BINARY}) could not be found. Exiting."
940       eerror "|-> Make sure to install either squashfs-tools and/or squashfs-lzma-tools."
941       eerror "\`-> Visit http://grml.org/grml-live/#current_state for further details."
942       eend 1
943       package
944       bailout
945    fi
946
947    SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
948
949    [ -n "$SQUASHFS_OPTIONS" ]  && SQUASHFS_INFO_MSG="$SQUASHFS_OPTIONS"
950    [ -n "$SQUASHFS_ZLIB" ]     && SQUASHFS_INFO_MSG="$SQUASHFS_INFO_MSG $SQUASHFS_ZLIB"
951    [ -n "$SQUASHFS_INFO_MSG" ] && SQUASHFS_INFO_MSG="using options: $SQUASHFS_INFO_MSG"
952    einfo "Squashfs build information: running binary $SQUASHFS_BINARY $SQUASHFS_INFO_MSG"
953
954    log "$SQUASHFS_BINARY $CHROOT_OUTPUT/* $BUILD_OUTPUT/live/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS $SQUASHFS_ZLIB"
955
956    if $SQUASHFS_BINARY $CHROOT_OUTPUT/* $BUILD_OUTPUT/live/"${GRML_NAME}".squashfs \
957       -noappend $SQUASHFS_OPTIONS $SQUASHFS_ZLIB 2>"${SQUASHFS_STDERR}" ; then
958       echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/filesystem.module
959       log "Finished execution of stage 'squashfs' [$(date)]"
960       einfo "Finished execution of stage 'squashfs'" ; eend 0
961    else
962       log    "Error: there was a critical error executing stage 'squashfs' [$(date)]:"
963       log    "$(cat $SQUASHFS_STDERR)"
964       eerror "Error: there was a critical error executing stage 'squashfs':" ; eend 1
965       cat    "${SQUASHFS_STDERR}"
966       bailout
967    fi
968
969    FORCE_ISO_REBUILD=true
970 fi
971
972 # create md5sum file:
973 ( cd $BUILD_OUTPUT/GRML &&
974 find .. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
975 # }}}
976
977 # ISO_OUTPUT - mkisofs {{{
978 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
979 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
980
981 if [ "$BOOT_METHOD" = "isolinux" ] ; then
982    BOOT_FILE="boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
983 elif [ "$BOOT_METHOD" = "grub" ] ; then
984    BOOT_FILE="boot/grub/stage2_eltorito"
985 fi
986
987 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ]  ; then
988    log   "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already."
989    ewarn "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already." ; eend 0
990 elif [ -n "$SKIP_MKISOFS" ] ; then
991    log   "Skipping stage 'iso build' as requested via option -n"
992    ewarn "Skipping stage 'iso build' as requested via option -n" ; eend 0
993 else
994    mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
995
996    if $FORCE_ISO_REBUILD ; then
997       log   "Forcing rebuild of ISO because files on ISO have been modified."
998       einfo "Forcing rebuild of ISO because files on ISO have been modified."
999    fi
1000
1001    # support mkisofs as well as genisoimage
1002    if which mkisofs >/dev/null 2>&1; then
1003       MKISOFS='mkisofs'
1004    elif which genisoimage >/dev/null 2>&1; then
1005       MKISOFS='genisoimage'
1006    else
1007       log    "Error: neither mkisofs nor genisoimage available - can not create ISO."
1008       eerror "Error: neither mkisofs nor genisoimage available - can not create ISO." ; eend 1
1009       bailout
1010    fi
1011
1012    CURRENT_DIR=$(pwd)
1013    if cd "$BUILD_OUTPUT" ; then
1014       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} ."
1015       "$MKISOFS" -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
1016               -l -r -J -no-emul-boot -boot-load-size 4 -boot-info-table    \
1017               -b $BOOT_FILE -no-pad \
1018               -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
1019
1020       # pad the output ISO to multiples of 256 KiB for partition table support
1021       siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
1022       cyls=$((siz / 512 / 32 / 16 + 1))   # C=$cyls H=16 S=32
1023       siz=$((cyls * 16 * 32 * 512))   # size after padding
1024       dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
1025          of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
1026
1027       # support disabling hybrid ISO image
1028       if [ "$HYBRID_METHOD" = "disable" ] ; then\
1029          log   "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1030          einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1031          eend 0
1032       # use isohybrid only on request
1033       elif [ "$HYBRID_METHOD" = "isohybrid" ] ; then
1034          if ! which isohybrid >/dev/null 2>&1 ; then
1035            bailout 12 "isohybrid binary not found - please install syslinux/syslinux-common"
1036          else
1037            log "Creating hybrid ISO file with isohybrid method"
1038            einfo "Creating hybrid ISO file with isohybrid method"
1039            isohybrid "${ISO_OUTPUT}/${ISO_NAME}"
1040            eend $?
1041          fi
1042       # by default use our manifold boot method:
1043       else
1044          if ! [ -r boot/grub/core.img ] ; then
1045            ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
1046          else
1047            log "Creating hybrid ISO file with manifold method"
1048            einfo "Creating hybrid ISO file with manifold method"
1049            echo 1 63 | \
1050                mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 1 -p 0x83 -g $cyls:16:32 | \
1051                cat - boot/grub/core.img | \
1052                dd conv=notrunc of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
1053            eend $?
1054          fi
1055       fi
1056
1057       # generate md5sum and sha1sum of ISO if we are using class 'RELEASE':
1058       case $CLASSES in *RELEASE*)
1059          [ "$RC" = 0 ] && \
1060          (
1061            if cd $ISO_OUTPUT ; then
1062              md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
1063              touch -r ${ISO_NAME} ${ISO_NAME}.md5
1064              sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
1065              touch -r ${ISO_NAME} ${ISO_NAME}.sha1
1066            fi
1067          )
1068          ;;
1069       esac
1070
1071       cd $CURRENT_DIR
1072    fi
1073
1074    if [ "$RC" = 0 ] ; then
1075       log   "Finished execution of stage 'iso build' [$(date)]"
1076       einfo "Finished execution of stage 'iso build'" ; eend 0
1077    else
1078       log    "Error: there was a critical error ($RC) executing stage 'iso build' [$(date)]"
1079       eerror "Error: there was a critical error executing stage 'iso build'" ; eend 1
1080       bailout $RC
1081    fi
1082 fi
1083 # }}}
1084
1085 # finalize {{{
1086 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
1087 einfo "Successfully finished execution of $PN [running ${SECONDS} seconds]" ; eend 0
1088 log "Successfully finished execution of $PN [running ${SECONDS} seconds]"
1089 bailout 0
1090 # }}}
1091
1092 ## END OF FILE #################################################################
1093 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=3