Update changelog and grml-live version number.
[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.25-pre1'
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_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_NAME}" ] || mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_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_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_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       # *always* copy files to output directory so the variables
629       # get adjusted according to the build
630       cp ${TEMPLATE_DIRECTORY}/boot/isolinux/*  "$BUILD_OUTPUT"/boot/isolinux/
631
632       if [ -n "$NO_ADDONS" ] ; then
633          log "Skipping installation boot addons requested via \$NO_ADDONS."
634          einfo "Skipping installation boot addons requested via \$NO_ADDONS."
635          eend 0
636       else
637          if ! [ -d /usr/share/grml-live/templates/boot/addons/bsd4grml ] ; then
638            ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
639          else
640            # copy only files so we can handle bsd4grml on its own
641            for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
642                test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
643            done
644
645            if [ -z "$NO_ADDONS_BSD4GRML" ] ; then
646               cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
647            fi
648          fi
649       fi
650
651       if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
652          cp -a ${TEMPLATE_DIRECTORY}/boot/grub  "$BUILD_OUTPUT"/boot/
653       fi
654       # make sure we have recent template files available, otherwise updating
655       # the strings like $GRML_NAME and $VERSION might be out of date
656       cp ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
657
658       if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
659          log    "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
660          eerror "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
661          bailout 9
662       fi
663
664       [ -d "$BUILD_OUTPUT"/GRML ] || mkdir "$BUILD_OUTPUT"/GRML
665       cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/
666
667       # adjust boot splash information:
668       RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
669       RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
670       RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
671
672       sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/grml-version
673       sed -i "s/%DATE%/$ISO_DATE/"                                  "$BUILD_OUTPUT"/GRML/grml-version
674
675       # make sure the squashfs filename is set accordingly:
676       SQUASHFS_NAME="$GRML_NAME.squashfs"
677
678       # adjust all variables in the templates with the according distribution information
679       for file in "${BUILD_OUTPUT}"/boot/isolinux/*.cfg "${BUILD_OUTPUT}"/boot/isolinux/*.msg \
680                   "${BUILD_OUTPUT}"/boot/grub/* ; do
681         sed -i "s/%ARCH%/$ARCH/g"                    "${file}"
682         sed -i "s/%DATE%/$ISO_DATE/g"                "${file}"
683         sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/g"      "${file}"
684         sed -i "s/%DISTRI_NAME%/$DISTRI_NAME/g"      "${file}"
685         sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/g"  "${file}"
686         sed -i "s/%GRML_NAME%/$GRML_NAME/g"          "${file}"
687         sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/g"  "${file}"
688         sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/g"    "${file}"
689         sed -i "s/%SHORT_NAME%/$SHORT_NAME/g"        "${file}"
690         sed -i "s/%VERSION%/$VERSION/g"              "${file}"
691       done
692
693       # adjust bootsplash accordingly but make sure the string has the according lenght
694       SQUASHFS_NAME="$(cut_string 20 "$SQUASHFS_NAME")"
695       SQUASHFS_NAME="$(extend_string_end 20 "$SQUASHFS_NAME")"
696       sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "$BUILD_OUTPUT"/boot/isolinux/f4
697       sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "$BUILD_OUTPUT"/boot/isolinux/f5
698
699       if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
700          log "including grmlmain.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
701          echo "include grmlmain.cfg"    >  "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
702          echo "include default.cfg"     >  "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
703          echo "include menuoptions.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
704          echo "include grml.cfg"        >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
705          echo "include options.cfg"     >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
706          if [ ! -n "$NO_ADDONS" ] ; then
707            echo "include addons.cfg"    >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
708          fi
709          echo "include isoprompt.cfg"   >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
710          echo "include hd.cfg"          >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
711          echo "include hidden.cfg"      >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
712       else # assume we are building a custom distribution:
713          log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
714          einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
715          if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
716            log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
717            eindent
718            einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
719            eoutdent
720            eend $?
721         else
722            log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
723            echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
724            [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
725          fi
726       fi
727
728       # use old style console based isolinux method only if requested:
729       if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
730          log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
731          einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
732          if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
733            einfo "include for console.cfg already foud, nothing to do."
734            eend 0
735          else
736            log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
737            einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
738            echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
739            eend $?
740          fi
741       else
742          log 'Using graphical boot menu.'
743          if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
744            log "include for vesamenu.cfg already foud, nothing to do."
745          else
746            log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
747            echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
748          fi
749       fi
750
751       # jump back to grub from bsd4grml:
752       if [ -e "$BUILD_OUTPUT"/boot/grub/stage2 ]; then
753          GRUB_LEGACY=stage2
754       else
755          GRUB_LEGACY=stage2_eltorito
756       fi
757       if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
758          if [ -e "$BUILD_OUTPUT"/boot/grub/core.img ]; then
759             GRUB_VERSION=2
760          else
761             GRUB_VERSION=1
762          fi
763
764          # why not ed(1)?
765          for file in "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 \
766                      "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.cfg; do
767              sed -i -e "s!%GRUB_VERSION%!$GRUB_VERSION!g" \
768                     -e "s!%GRUB_LEGACY%!$GRUB_LEGACY!g" "$file"
769          done
770
771          sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
772       fi
773       if [ -e "$BUILD_OUTPUT"/boot/grub/$GRUB_LEGACY ]; then
774          sed -i "s/%GRUB_LEGACY%/$GRUB_LEGACY/g" "$BUILD_OUTPUT"/boot/grub/menu.lst
775          sed -i "s/%GRUB_LEGACY%/$GRUB_LEGACY/g" "$BUILD_OUTPUT"/boot/grub/grub.cfg
776       else
777          sed -i "/%GRUB_LEGACY%/d" "$BUILD_OUTPUT"/boot/grub/menu.lst
778          sed -i "/%GRUB_LEGACY%/d" "$BUILD_OUTPUT"/boot/grub/grub.cfg
779       fi
780
781       # autostart for Windows:
782       if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
783          cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
784       fi
785
786       # windows-binaries:
787       if [ -n "$NO_WINDOWS_BINARIES" ] ; then
788          log   "Skipping download of windows binaries as requested via \$NO_WINDOWS_BINARIES."
789          einfo "Skipping download of windows binaries as requested via \$NO_WINDOWS_BINARIES."
790          eend 0
791       else
792          if [ -f "$BUILD_OUTPUT"/windows/putty.exe ] ; then
793             log   "Skipping stage 'WINDOWS_BINARIES' as $BUILD_OUTPUT/windows exists already."
794             ewarn "Skipping stage 'WINDOWS_BINARIES' as $BUILD_OUTPUT/windows exists already." ; eend 0
795          else
796             if ! [ -d "$BUILD_OUTPUT"/windows ] ; then
797                mkdir "$BUILD_OUTPUT"/windows
798                ( cd "$BUILD_OUTPUT"/windows
799                  for file in pageant plink pscp psftp putty puttygen ; do
800                     wget -O ${file}.exe ${WINDOWS_BINARIES}/${file}.exe
801                     md5sum ${file}.exe > ${file}.exe.md5
802                  done )
803             fi
804
805             log "Finished execution of stage 'WINDOWS_BINARIES' [$(date)]"
806             einfo "Finished execution of stage 'WINDOWS_BINARIES'" ; eend 0
807          fi
808       fi
809
810    FORCE_ISO_REBUILD=true
811    einfo "Finished execution of stage 'boot'" ; eend 0
812    fi
813 else
814    log    'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
815    eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
816    bailout
817 fi
818
819 # support installation of local files into the chroot/ISO
820 if [ -n "$CHROOT_INSTALL" ] ; then
821   if ! [ -d "$CHROOT_INSTALL" ] ; then
822      log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
823      ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
824   else
825      log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
826      einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
827      rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
828      eend $?
829      einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
830      FORCE_ISO_REBUILD=true
831   fi
832 fi
833
834 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
835    log   "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
836    ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
837 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
838    log   "Skipping stage 'squashfs' as requested via option -q"
839    ewarn "Skipping stage 'squashfs' as requested via option -q" ; eend 0
840 else
841    [ -d "$BUILD_OUTPUT"/live ] || mkdir "$BUILD_OUTPUT"/live
842    # make sure we don't leave (even an empty) base.tgz:
843    [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
844
845    # $SQUASHFS_BINARY is specified in the configuration:
846    if [ -n "$SQUASHFS_BINARY" ] ; then
847       if ! which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
848          log    "Error: specified mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
849          eerror "Error: specified mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
850          bailout
851       fi
852    else # no $SQUASHFS_BINARY configured, let's find the according binary:
853       # Note: this is ALL for backward compability and yes: it's serious PITA.
854       # We'll definitely drop this once people build >2.6.28-grml* only and
855       # the squashfs-tools vs. squashfs-lzma-tools + zlib vs. lzma situation
856       # is settling...
857
858       # assume the safe default if mksquashfs-lzma isn't present:
859       if ! which mksquashfs-lzma >/dev/null 2>&1 ; then
860          SQUASHFS_BINARY='mksquashfs'
861       else # mksquashfs-lzma is available since squashfs-lzma-tools 4.0:
862          # if the user wants to use zlib then don't use mksquashfs-lzma:
863          if echo "$SQUASHFS_OPTIONS" | grep -q -- "-nolzma" || [ -n "$SQUASHFS_ZLIB" ] ; then
864             SQUASHFS_BINARY='mksquashfs'
865          else # neither -nolzma nor -z and mksquashfs-lzma is available:
866             SQUASHFS_BINARY='mksquashfs-lzma'
867
868             # backwards compability: someone has squashfs-lzma-tools >=4 installed but
869             # 1) doesn't use -nolzma in $SQUASHFS_OPTIONS or the grml-live's -z option *and*
870             # 2) builds against kernel version <=2.6.28-grml[64]
871             if ls $CHROOT_OUTPUT/boot/vmlinuz* >/dev/null 2>&1 ; then
872                KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
873
874                case $KERNEL_IMAGE in
875                   *vmlinuz-2.6.28-grml*|*vmlinuz-2.6.26-grml*|*vmlinuz-2.6.23-grml*)
876                   log   "You seem to be building a system with squashfs file format 3 using squashfs-lzma-tools >=4."
877                   ewarn "You seem to be building a system with squashfs file format 3 using squashfs-lzma-tools >=4."
878                   ewarn "|-> Consider installing squashfs-lzma-tools 3.3-1 for support of file format version 3."
879                   ewarn "|-> Trying the mksquashfs binary instead of mksquashfs-lzma (though this might fail)."
880                   ewarn "\`-> Visit http://grml.org/grml-live/#current_state for further details if building fails."
881                   eend 0
882                   SQUASHFS_BINARY='mksquashfs'
883                   ;;
884                esac
885             fi
886
887             # if we still want to use mksquashfs-lzma then let's choose
888             # blocksize 256k as this gives best result with regards to time + comopression
889             [[ "$SQUASHFS_BINARY" == "mksquashfs-lzma" ]] && SQUASHFS_OPTIONS="-b 256k -lzma"
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   "The $SQUASHFS_BINARY binary does NOT support the nolzma option, dropping it and using default mode."
904          ewarn "The $SQUASHFS_BINARY 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   "The $SQUASHFS_BINARY binary does NOT support the lzma option, dropping it and using default mode."
914          ewarn "The $SQUASHFS_BINARY 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 && ! [ -f "${ISO_OUTPUT}/${ISO_NAME}" ] ; 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