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