New cmdline option: "-n" skips generation of the ISO file
[grml-live.git] / grml-live
1 #!/bin/bash
2 # Filename:      grml-live
3 # Purpose:       build process script for generating a (grml based) Linux Live-ISO
4 # Authors:       grml-team (grml.org),
5 #                (c) Michael Prokop <mika@grml.org>,
6 #                (c) Thorsten Glaser <tg@mirbsd.org>
7 # Bug-Reports:   see http://grml.org/bugs/
8 # License:       This file is licensed under the GPL v2 or any later version.
9 ################################################################################
10
11 # some misc and global stuff {{{
12 export LANG=C
13 export LC_ALL=C
14
15 # define function getfilesize before "set -e"
16 if stat --help >/dev/null 2>&1; then
17   getfilesize='stat -c %s'  # GNU stat
18 else
19   getfilesize='stat -f %z'  # BSD stat
20 fi
21
22 # exit on any error:
23 set -e
24
25 # global variables
26 GRML_LIVE_VERSION='0.9.22'
27 PN="$(basename $0)"
28 CMDLINE="$0 $@"
29 ISO_DATE="$(date +%Y-%m-%d)"
30 SOURCES_LIST_FILE='/etc/grml/fai/apt/sources.list'
31 # }}}
32
33 # usage information {{{
34 usage()
35 {
36   echo "
37 $PN - build process script for generating a (grml based) Linux Live-ISO
38
39 Usage: $PN [options, see as follows]
40
41    -a <architecture>       architecture; available values: i386 and amd64
42    -b                      build the ISO without updating the chroot via FAI
43    -B                      build the ISO without touching the chroot (skips cleanup)
44    -c <classe[s]>          classes to be used for building the ISO via FAI
45    -C <configfile>         configuration file for grml-live
46    -F                      force execution without prompting
47    -g <grml_name>]         set the grml flavour name
48    -h                      display short usage information and exit
49    -i <iso_name>           name of ISO
50    -I <src_directory>      directory which provides files that should become
51                            part of the chroot/ISO
52    -n                      skip generation of ISO
53    -o <output_directory>   main output directory of the build process
54    -q                      skip mksquashfs
55    -r <release_name<       release name
56    -s <suite>              Debian suite; values: etch, lenny, squeeze, sid
57    -t <template_directory> place of the templates
58    -u                      update existing chroot instead of rebuilding it from scratch
59    -v <version_number>     specify version number of the release
60    -V                      increase verbosity in the build process
61    -z                      use ZLIB instead of LZMA compression (depends on
62                            squashfs-tools version)
63
64 Usage examples:
65
66     $PN
67     $PN -c GRMLBASE,GRML_MEDIUM,I386 -o /dev/shm/grml
68     $PN -c GRMLBASE,GRML_SMALL,REMOVE_DOCS,I386 -g grml-small -v 1.0
69     $PN -c GRMLBASE,GRML_FULL,I386 -i grml_0.0-1.iso -v 0.0-1
70     $PN -c GRMLBASE,GRML_FULL,I386 -s sid -V -r 'grml-live rocks'
71
72 More details: man grml-live + /usr/share/doc/grml-live/grml-live.html
73               http://grml.org/grml-live/
74
75 Please send your bug reports and feedback to the grml-team: http://grml.org/bugs/
76 "
77 }
78
79 # make sure it's possible to get usage information without being
80 # root or actually executing the script
81 if [ "$1" = '-h' -o "$1" = '--help' ] ; then
82    usage
83    [ "$(id -u 2>/dev/null)" != 0 ] && echo "Please notice that this script requires root permissions."
84    exit 0
85 fi
86 # }}}
87
88 # some runtime checks {{{
89 # we need root permissions for the build-process:
90 if [ "$(id -u 2>/dev/null)" != 0 ] ; then
91    echo "Error: please run this script with uid 0 (root)." >&2
92    exit 1
93 fi
94
95 if [ -r /var/run/fai/FAI_INSTALLATION_IN_PROGRESS ] ; then
96    echo "/usr/sbin/fai already running or was aborted before.">&2
97    echo "You may remove /var/run/fai/FAI_INSTALLATION_IN_PROGRESS and try again.">&2
98    exit 1
99 fi
100
101 # see #449236
102 if [ -r /var/run/fai/fai_softupdate_is_running ] ; then
103    echo "/usr/sbin/fai softupdate already running or was aborted before.">&2
104    echo "You may remove /var/run/fai/fai_softupdate_is_running and try again.">&2
105    exit 1
106 fi
107 # }}}
108
109 # lsb-functions and configuration stuff {{{
110 # make sure they are not set by default
111 VERBOSE=''
112 FORCE=''
113 UPDATE=''
114 BUILD_ONLY=''
115 BUILD_DIRTY=''
116 HOSTNAME=''
117
118 if [ -r /etc/grml/lsb-functions ] ; then
119    . /etc/grml/lsb-functions
120 else
121    einfo()  { echo "  [*] $*" ;}
122    eerror() { echo "  [!] $*">&2 ;}
123    ewarn()  { echo "  [x] $*" ;}
124    eend()   { return 0 ;}
125 fi
126
127 # source main configuration file:
128 LIVE_CONF=/etc/grml/grml-live.conf
129 . $LIVE_CONF
130 # }}}
131
132 # clean exit {{{
133 bailout() {
134   rm -f /var/run/fai/fai_softupdate_is_running \
135         /var/run/fai/FAI_INSTALLATION_IN_PROGRESS
136   [ -n "$SQUASHFS_STDERR" ]  && rm -rf "$SQUASHFS_STDERR"
137   [ -n "$MIRROR_DIRECTORY" ] && umount "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
138   [ -n "$1" ] && EXIT="$1" || EXIT="1"
139   [ -n "$2" ] && eerror "$2">&2
140   log "------------------------------------------------------------------------------"
141   exit "$EXIT"
142 }
143 trap bailout 1 2 3 3 6 9 14 15
144 # }}}
145
146 # log file stuff {{{
147 [ -n "$LOGFILE" ] || LOGFILE=/var/log/grml-live.log
148 touch $LOGFILE
149 chown root:adm $LOGFILE
150 chmod 664 $LOGFILE
151 # }}}
152
153 # some important functions {{{
154
155 # log output:
156 # usage: log "string to log"
157 log() { echo "$*" >> $LOGFILE ; }
158
159 # cut string at character number int = $1
160 # usage: cut_string 5 "1234567890" will output "12345"
161 cut_string() {
162   [ -n "$2" ] || return 1
163   echo "$2" | head -c "$1"; echo -ne "\n"
164 }
165
166 # prepend int = $1 spaces before string = $2
167 # usage: extend_string_begin 5 "123" will output "  123"
168 extend_string_begin() {
169   [ -n "$2" ] || return 1
170   local COUNT="$(echo $2 | wc -c)"
171   local FILL="$(expr $COUNT - $1)"
172   while [ "$FILL" -gt 1 ] ; do
173     echo -n " "
174     local FILL=$(expr $FILL - 1)
175   done
176   while [ "$FILL" -lt 1 ] ; do
177     echo -n " "
178     local FILL=$(expr $FILL + 1)
179   done
180   echo "$2" | head -c "$1"; echo -ne "\n"
181 }
182
183 # append int = $1 spaces to string = $2
184 # usage: extend_string_begin 5 "123" will output "123  "
185 extend_string_end() {
186   [ -n "$2" ] || return 1
187   echo -n "$2" | head -c "$1"
188   local COUNT="$(echo $2 | wc -c)"
189   local FILL="$(expr $COUNT - $1)"
190   while [ "$FILL" -gt 1 ] ; do
191     echo -n " "
192     local FILL=$(expr $FILL - 1)
193   done
194   while [ "$FILL" -lt 1 ] ; do
195     echo -n " "
196     local FILL=$(expr $FILL + 1)
197   done
198   echo -ne "\n"
199 }
200 # }}}
201
202 # read local (non-packaged) configuration {{{
203 LOCAL_CONFIG=/etc/grml/grml-live.local
204 if [ -r "$LOCAL_CONFIG" ] ; then
205    log "Sourcing $LOCAL_CONFIG"
206    . $LOCAL_CONFIG
207 else
208    log "No $LOCAL_CONFIG found, not sourcing it"
209    LOCAL_CONFIG=''
210 fi
211 # }}}
212
213 # command line parsing {{{
214 while getopts "a:C:c:g:i:I:o:r:s:t:v:bBFnquVz" opt; do
215   case "$opt" in
216     a) ARCH="$OPTARG" ;;
217     b) BUILD_ONLY=1 ;;
218     B) BUILD_DIRTY=1 ;;
219     c) CLASSES="$OPTARG" ;;
220     C) CONFIG="$OPTARG" ;;
221     g) GRML_NAME="$OPTARG" ;;
222     i) ISO_NAME="$OPTARG" ;;
223     I) CHROOT_INSTALL="$OPTARG" ;;
224     n) SKIP_MKISOFS=1 ;;
225     o) OUTPUT="$OPTARG" ;;
226     q) SKIP_MKSQUASHFS=1 ;;
227     r) RELEASENAME="$OPTARG" ;;
228     s) SUITE="$OPTARG" ;;
229     t) TEMPLATE_DIRECTORY="$OPTARG";;
230     v) VERSION="$OPTARG" ;;
231     F) FORCE=1 ;;
232     u) UPDATE=1 ;;
233     V) VERBOSE="-v" ;;
234     z) SQUASHFS_ZLIB="-nolzma" ;;
235     ?) echo "invalid option -$OPTARG" >&2; bailout 1 ;;
236   esac
237 done
238 shift $(($OPTIND - 1))  # set ARGV to the first not parsed commandline parameter
239 # }}}
240
241 # assume sane defaults (if not set already) {{{
242 [ -n "$ARCH" ]             || ARCH="$(dpkg --print-architecture)"
243 [ -n "$BOOT_METHOD" ]      || BOOT_METHOD='isolinux'
244 [ -n "$BUILD_OUTPUT" ]     || BUILD_OUTPUT="$OUTPUT/grml_cd"
245 [ -n "$CHROOT_OUTPUT" ]    || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
246 [ -n "$CLASSES" ]          || CLASSES="GRMLBASE,GRML_MEDIUM,I386"
247 [ -n "$DISTRI_INFO" ]      || DISTRI_INFO='Grml - Live Linux for system administrators   '
248 [ -n "$DISTRI_NAME" ]      || DISTRI_NAME="grml"
249 [ -n "$DISTRI_SPLASH" ]    || DISTRI_SPLASH='grml.png'
250 [ -n "$FORCE_ISO_REBUILD" ] || FORCE_ISO_REBUILD="false"
251 [ -n "$GRML_FAI_CONFIG" ]  || GRML_FAI_CONFIG='/etc/grml/fai'
252 [ -n "$GRML_NAME" ]        || GRML_NAME='grml'
253 [ -n "$HOSTNAME" ]         || HOSTNAME='grml'
254 [ -n "$ISO_OUTPUT" ]       || ISO_OUTPUT="$OUTPUT/grml_isos"
255 [ -n "$NFSROOT_CONF" ]     || NFSROOT_CONF='/etc/grml/fai/make-fai-nfsroot.conf'
256 [ -n "$OUTPUT" ]           || OUTPUT='/grml/grml-live'
257 [ -n "$RELEASENAME" ]      || RELEASENAME='grml-live rocks'
258 [ -n "$SQUASHFS_EXCLUDES_FILE " ] || SQUASHFS_EXCLUDES_FILE='/etc/grml/fai/squashfs-excludes'
259 [ -n "$SUITE" ]            || SUITE='stable'
260 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
261 [ -n "$USERNAME" ]         || USERNAME='grml'
262 [ -n "$VERSION" ]          || VERSION='0.0.1'
263 [ -n "$WINDOWS_BINARIES" ] || WINDOWS_BINARIES='http://the.earth.li/~sgtatham/putty/latest/x86/'
264 # }}}
265
266 # some misc checks before executing FAI {{{
267 [ -n "$CLASSES" ] || bailout 1 "Error: \$CLASSES unset, please set it in $LIVE_CONF or
268 specify it on the command line using the -c option."
269 [ -n "$OUTPUT" ] || bailout 1 "Error: \$OUTPUT unset, please set it in $LIVE_CONF or
270 specify it on the command line using the -o option."
271
272 # set subdirectories according to $OUTPUT:
273 CHROOT_OUTPUT="$OUTPUT/grml_chroot"
274 BUILD_OUTPUT="$OUTPUT/grml_cd"
275 ISO_OUTPUT="$OUTPUT/grml_isos"
276
277 # trim characters that are known to cause problems inside $GRML_NAME;
278 # for example isolinux does not like '-' inside the directory name
279 [ -n "$GRML_NAME" ] && export SHORT_GRML_NAME="$(echo $GRML_NAME | tr -d ',./;\- ')"
280
281 # export variables to have them available in fai scripts:
282 [ -n "$GRML_NAME" ]   && export GRML_NAME="$GRML_NAME"
283 [ -n "$RELEASENAME" ] && export RELEASENAME="$RELEASENAME"
284 # }}}
285
286 # clean/zero grml-live logfile {{{
287 if [ -n "$ZERO_LOGFILE" ] ; then
288    echo -n > $LOGFILE
289 fi
290 # }}}
291
292 # clean/zero/remove old FAI directory {{{
293 if [ -n "$ZERO_FAI_LOGFILE" ] ; then
294    if [ -d /var/log/fai/"$HOSTNAME" ] ; then
295       rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last)"
296       rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-dirinstall)"
297       rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-softupdate)"
298       rm -f /var/log/fai/"$HOSTNAME"/last \
299             /var/log/fai/"$HOSTNAME"/last-dirinstall \
300             /var/log/fai/"$HOSTNAME"/last-softupdate
301    fi
302 fi
303 # }}}
304
305 # ask user whether the setup is ok {{{
306 if [ -z "$FORCE" ] ; then
307    echo
308    echo "${PN} [${GRML_LIVE_VERSION}]: check your configuration (or use -F to force execution):"
309    echo
310    echo "  FAI classes:       $CLASSES"
311    [ -r "$LOCAL_CONFIG" ]       && echo "  local config:      /etc/grml/grml-live.local"
312    [ -n "$CONFIG" ]             && echo "  configuration:     $CONFIG"
313    echo "  main directory:    $OUTPUT"
314    [ -n "$CHROOT_OUTPUT" ]      && echo "  chroot target:     $CHROOT_OUTPUT"
315    [ -n "$BUILD_OUTPUT" ]       && echo "  build target:      $BUILD_OUTPUT"
316    [ -n "$ISO_OUTPUT" ]         && echo "  ISO target:        $ISO_OUTPUT"
317    [ -n "$GRML_NAME" ]          && echo "  grml name:         $GRML_NAME"
318    [ -n "$RELEASENAME" ]        && echo "  release name:      $RELEASENAME"
319    [ -n "$VERSION" ]            && echo "  grml version:      $VERSION"
320    [ -n "$SUITE" ]              && echo "  Debian suite:      $SUITE"
321    [ -n "$ARCH" ]               && echo "  Architecture:      $ARCH"
322    [ -n "$BOOT_METHOD" ]        && echo "  Boot method:       $BOOT_METHOD"
323    [ -n "$TEMPLATE_DIRECTORY" ] && echo "  Template files:    $TEMPLATE_DIRECTORY"
324    [ -n "$CHROOT_INSTALL" ]     && echo "  Install files from directory to chroot:  $CHROOT_INSTALL"
325    [ -n "$FAI_ARGS" ]           && echo "  additional arguments for FAI: $FAI_ARGS"
326    [ -n "$LOGFILE" ]            && echo "  Logging to file:   $LOGFILE"
327    [ -n "$SQUASHFS_ZLIB" ]      && echo "  Using ZLIB (instead of LZMA) compression."
328    [ -n "$SQUASHFS_OPTIONS" ]   && echo "  Using SQUASHFS_OPTIONS ${SQUASHFS_OPTIONS}"
329    [ -n "$VERBOSE" ]            && echo "  Using VERBOSE mode."
330    [ -n "$UPDATE" ]             && echo "  Executing UPDATE instead of fresh installation."
331    [ -n "$SKIP_MKSQUASHFS" ]    && echo "  Skipping creation of SQUASHFS file."
332    [ -n "$SKIP_MKISOFS" ]       && echo "  Skipping creation of ISO file."
333    [ -n "$BUILD_ONLY" ]         && echo "  Executing BUILD_ONLY instead of fresh installation or UPDATE."
334    [ -n "$BUILD_DIRTY" ]        && echo "  Executing BUILD_DIRTY to leave chroot untouched."
335    echo
336    echo -n "Is this ok for you? [y/N] "
337    read a
338    if ! [ "$a" = 'y' -o "$a" = 'Y' ] ; then
339       bailout 1 "Exiting as requested."
340    fi
341    echo
342 fi
343
344 if [ -n "$CONFIG" ] ; then
345    if ! [ -f "$CONFIG" ] ; then
346       log "Sorry, $CONFIG could not be read. Exiting. [$(date)]"
347       eerror "Sorry, $CONFIG could not be read. Exiting."
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 "Sorry, $MIRROR_DIRECTORY/debian does not seem to exist. Exiting. [$(date)]"
368       eerror "Sorry, $MIRROR_DIRECTORY/debian does not seem to exist. Exiting."
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       eerror "You specified the I386 class but are trying to build something else (AMD64?)."
440       eerror "-> Either invoke grml-live with '-i i386' or adjust the architecture class. Exiting."
441       bailout
442    fi
443 elif echo $CLASSES | grep -qi amd64 ; then
444    if ! [[ "$ARCH" == "amd64" ]] ; then
445       eerror "You specified the AMD64 class but are trying to build something else (I386?)."
446       eerror "-> Either invoke grml-live with '-i amd64' or adjust the architecture class. Exiting."
447       bailout
448    fi
449 fi
450
451 if grep -q -- 'FAI_DEBOOTSTRAP_OPTS.*--arch' "$NFSROOT_CONF" ; then
452    sed "s/--arch [a-z0-9]* /--arch $ARCH /" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
453 else
454    sed "s|^FAI_DEBOOTSTRAP_OPTS=\"\(.*\)|FAI_DEBOOTSTRAP_OPTS=\"--arch $ARCH \1|" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
455 fi
456 # }}}
457
458 # CHROOT_OUTPUT - execute FAI {{{
459 if [ -n "$BUILD_DIRTY" ]; then
460   einfo "Skipping FAI" ; eend 0
461 else
462    [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
463
464    # provide inform fai about the ISO we build
465    [ -d "$CHROOT_OUTPUT/etc/" ] || mkdir -p "$CHROOT_OUTPUT/etc/"
466    echo '# This file has been generated by grml-live.' > "$CHROOT_OUTPUT/etc/grml_live_version"
467    [ -n "$GRML_LIVE_VERSION" ] && echo "GRML_LIVE_VERSION=$GRML_LIVE_VERSION" >> "$CHROOT_OUTPUT/etc/grml_live_version"
468    [ -n "$SUITE" ] && echo "SUITE=$SUITE" >> "$CHROOT_OUTPUT/etc/grml_live_version"
469
470    if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
471       FAI_ACTION=softupdate
472    else
473       FAI_ACTION=dirinstall
474    fi
475
476    if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
477       if ! [ -r "$CHROOT_OUTPUT/etc/debian_version" ] ; then
478          log "Error: does not look like you have a working chroot. Updating/building not possible."
479          eerror "Error: does not look like you have a working chroot. Updating/building not possible. (Drop -u/-b option?)"
480          eend 1
481          bailout 20
482       fi
483    fi
484
485    if [ -d "$CHROOT_OUTPUT/bin" -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
486       log "$CHROOT_OUTPUT exists already, skipping stage 'fai dirinstall'"
487       ewarn "$CHROOT_OUTPUT exists already, skipping stage 'fai dirinstall'" ; eend 0
488    else
489       mkdir -p "$CHROOT_OUTPUT" || bailout 5 "Problem with creating $CHROOT_OUTPUT for FAI"
490
491       if [ -n "${MIRROR_DIRECTORY}" ] ; then
492          mkdir -p "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
493          mount --bind "${MIRROR_DIRECTORY}" "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
494       fi
495
496       log "Executed FAI command line:"
497       log "BUILD_ONLY=$BUILD_ONLY fai $VERBOSE -C $GRML_FAI_CONFIG -c$CLASSES -u $HOSTNAME $FAI_ACTION $CHROOT_OUTPUT $FAI_ARGS"
498       BUILD_ONLY="$BUILD_ONLY" fai $VERBOSE -C "$GRML_FAI_CONFIG" -c"$CLASSES" -u \
499       "$HOSTNAME" $FAI_ACTION "$CHROOT_OUTPUT" $FAI_ARGS | tee -a $LOGFILE
500       RC="$PIPESTATUS" # notice: bash-only
501
502       FORCE_ISO_REBUILD=true
503
504       if [ "$RC" != 0 ] ; then
505          log "Error while executing fai [exit code ${RC}]. Exiting."
506          eerror "Error while executing fai [exit code ${RC}]. Exiting." ; eend 1
507          bailout 1
508       else
509          log "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$ISO_DATE]"
510          echo "$GRML_NAME $VERSION Release Codename $RELEASENAME [$ISO_DATE]" > $CHROOT_OUTPUT/etc/grml_version
511          chmod 644 $CHROOT_OUTPUT/etc/grml_version
512          einfo "Rebuilding initramfs"
513          # make sure new /etc/grml_version reaches the initramfs:
514          chroot $CHROOT_OUTPUT update-initramfs -u -t
515          eend $?
516       fi
517
518       # Remove all FAI logs from chroot if class RELEASE is used:
519       if [ -f "$CHROOT_OUTPUT"/etc/grml_fai_release ] ; then
520          rm -rf "$CHROOT_OUTPUT"/var/log/fai/*
521       fi
522
523       # make sure we don't leave any mounts - FAI doesn't remove them always
524       umount $CHROOT_OUTPUT/proc 2>/dev/null || /bin/true
525       umount $CHROOT_OUTPUT/sys  2>/dev/null || /bin/true
526       umount $CHROOT_OUTPUT/dev/pts 2>/dev/null || /bin/true
527       umount $CHROOT_OUTPUT/dev 2>/dev/null || /bin/true
528
529       [ -n "$MIRROR_DIRECTORY" ] && umount "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
530
531       # notice: 'fai dirinstall' does not seem to exit appropriate, so:
532       ERROR=''
533       CHECKLOG=/var/log/fai/$HOSTNAME/last
534       if [ -r "$CHECKLOG/software.log" ] ; then
535          # 1 errors during executing of commands
536          grep 'dpkg: error processing' $CHECKLOG/software.log >> $LOGFILE && ERROR=1
537          grep 'E: Method http has died unexpectedly!' $CHECKLOG/software.log >> $LOGFILE && ERROR=2
538          grep 'ERROR: chroot' $CHECKLOG/software.log >> $LOGFILE && ERROR=3
539          grep 'E: Failed to fetch' $CHECKLOG/software.log >> $LOGFILE && ERROR=4
540          grep 'Unable to write mmap - msync (28 No space left on device)' $CHECKLOG/software.log >> $LOGFILE && ERROR=5
541       fi
542
543       if [ -r "$CHECKLOG/shell.log" ] ; then
544          grep 'FAILED with exit code' $CHECKLOG/shell.log >> $LOGFILE && ERROR=2
545       fi
546
547       if [ -n "$ERROR" ] ; then
548          log "There was an error [${ERROR}] during execution of stage 'fai dirinstall' [$(date)]"
549          eerror "There was an error during execution of stage 'fai dirinstall'"
550          echo "   Check out ${CHECKLOG}/ for details. [exit ${ERROR}]"
551          eend 1
552          bailout 1
553       else
554          log "Finished execution of stage 'fai dirinstall' [$(date)]"
555          einfo "Finished execution of stage 'fai dirinstall'"
556       fi
557
558       einfo "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)."
559       log   "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)."
560       eend 0
561    fi
562 fi # BUILD_DIRTY?
563 # }}}
564
565 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
566 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
567 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
568
569 # i386:
570 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
571    if [ -d "$BUILD_OUTPUT"/boot/isolinux -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
572       log "$BUILD_OUTPUT/boot/isolinux exists already, skipping stage 'boot'"
573       ewarn "$BUILD_OUTPUT/boot/isolinux exists already, skipping stage 'boot'" ; eend 0
574    else
575       # booting stuff:
576       [ -d "$BUILD_OUTPUT"/boot/isolinux ] || mkdir -p "$BUILD_OUTPUT"/boot/isolinux
577       [ -d "$BUILD_OUTPUT"/boot/"${SHORT_GRML_NAME}" ] || mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_GRML_NAME}"
578
579       if [ -z "$NO_ADDONS" ] ; then
580          [ -d "$BUILD_OUTPUT"/boot/addons   ] || mkdir -p "$BUILD_OUTPUT"/boot/addons
581          if [ -r "$TEMPLATE_DIRECTORY"/boot/addons/memtest ] ; then
582             log "Installing $TEMPLATE_DIRECTORY/boot/addons/memtest"
583             cp "$TEMPLATE_DIRECTORY"/boot/addons/memtest "$BUILD_OUTPUT"/boot/addons/memtest
584          elif [ -r /boot/memtest86+.bin ] ; then
585             log "Installing /boot/memtest86+.bin"
586             cp /boot/memtest86+.bin "$BUILD_OUTPUT"/boot/addons/memtest
587          else
588             ewarn "No memtest binary found, skipping."
589             log "No memtest binary found, skipping."
590             eend 0
591          fi
592       fi
593
594       # if we don't have an initrd we a) can't boot and b) there was an error
595       # during build, so check for the file:
596       INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
597       if [ -n "$INITRD" ] ; then
598          cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_GRML_NAME}"/initrd.gz
599          find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
600       else
601          log "No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
602          eerror "No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
603          bailout 10
604       fi
605
606       KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
607       if [ -n "$KERNEL_IMAGE" ] ; then
608          cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_GRML_NAME}"/linux26
609       else
610          log "No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
611          eerror "No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
612          bailout 11
613       fi
614
615       [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
616       if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
617          log "${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
618          eerror "${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
619          bailout 8
620       fi
621
622       cp ${TEMPLATE_DIRECTORY}/boot/isolinux/*  "$BUILD_OUTPUT"/boot/isolinux/
623
624       if [ -n "$NO_ADDONS" ] ; then
625          log "Skipping installation boot addons requested via \$NO_ADDONS."
626          einfo "Skipping installation boot addons requested via \$NO_ADDONS."
627          eend 0
628       else
629          if ! [ -d /usr/share/grml-live/templates/boot/addons/bsd4grml ] ; then
630            ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
631          else
632            # copy only files so we can handle bsd4grml on its own
633            for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
634                test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
635            done
636
637            if [ -z "$NO_ADDONS_BSD4GRML" ] ; then
638               cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
639            fi
640          fi
641       fi
642
643       if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
644          cp -a ${TEMPLATE_DIRECTORY}/boot/grub  "$BUILD_OUTPUT"/boot/
645       fi
646       # make sure we have recent template files available, otherwise updating
647       # the strings like $GRML_NAME and $VERSION might be out of date
648       cp ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
649
650       if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
651          log "${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
652          eerror "${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
653          bailout 9
654       fi
655
656       [ -d "$BUILD_OUTPUT"/GRML ] || mkdir "$BUILD_OUTPUT"/GRML
657       cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/
658
659       # adjust boot splash information:
660       RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
661       RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
662       RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
663
664       sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/grml-version
665       sed -i "s/%DATE%/$ISO_DATE/"             "$BUILD_OUTPUT"/GRML/grml-version
666
667       sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/" "$BUILD_OUTPUT"/boot/isolinux/boot.msg
668       sed -i "s/%DATE%/$ISO_DATE/"             "$BUILD_OUTPUT"/boot/isolinux/boot.msg
669
670       sed -i "s/%GRML_NAME%/$SHORT_GRML_NAME/" "$BUILD_OUTPUT"/boot/isolinux/isolinux.cfg
671       sed -i "s/%GRML_NAME%/$SHORT_GRML_NAME/" "$BUILD_OUTPUT"/boot/isolinux/syslinux.cfg
672
673       sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/" "$BUILD_OUTPUT"/boot/isolinux/boot-beep.msg
674       sed -i "s/%DATE%/$ISO_DATE/"             "$BUILD_OUTPUT"/boot/isolinux/boot-beep.msg
675
676       sed -i "s/%VERSION%/$VERSION/"           "$BUILD_OUTPUT"/boot/grub/menu.lst
677       sed -i "s/%GRML_NAME%/$SHORT_GRML_NAME/" "$BUILD_OUTPUT"/boot/grub/menu.lst
678
679       sed -i "s/%VERSION%/$VERSION/"           "$BUILD_OUTPUT"/boot/grub/grub.cfg
680       sed -i "s/%GRML_NAME%/$SHORT_GRML_NAME/" "$BUILD_OUTPUT"/boot/grub/grub.cfg
681
682       if [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] ; then
683          sed -i "s/%VERSION%/$VERSION/"            "$BUILD_OUTPUT"/boot/isolinux/grml.cfg
684          sed -i "s/%GRML_LONG_NAME%/$DISTRI_NAME/" "$BUILD_OUTPUT"/boot/isolinux/grml.cfg
685          sed -i "s/%GRML_NAME%/$SHORT_GRML_NAME/"  "$BUILD_OUTPUT"/boot/isolinux/grml.cfg
686          sed -i "s/%ARCH%/$ARCH/"                  "$BUILD_OUTPUT"/boot/isolinux/grml.cfg
687       fi
688
689       sed -i "s/%VERSION%/$VERSION/"           "$BUILD_OUTPUT"/boot/isolinux/grml.cfg
690       sed -i "s/%GRML_LONG_NAME%/$GRML_NAME/"  "$BUILD_OUTPUT"/boot/isolinux/grml.cfg
691       sed -i "s/%GRML_NAME%/$SHORT_GRML_NAME/" "$BUILD_OUTPUT"/boot/isolinux/grml.cfg
692       sed -i "s/%ARCH%/$ARCH/"                 "$BUILD_OUTPUT"/boot/isolinux/grml.cfg
693
694       sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/" "$BUILD_OUTPUT"/boot/isolinux/vesamenu.cfg
695       sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/" "$BUILD_OUTPUT"/boot/isolinux/vesamenu.cfg
696
697       # make sure the squashfs filename is set accordingly:
698       GRML_NAME_SQUASHFS="$GRML_NAME.squashfs"
699       sed -i "s/%GRML_NAME_SQUASHFS%/$GRML_NAME_SQUASHFS/" "$BUILD_OUTPUT"/boot/isolinux/isolinux.cfg
700       sed -i "s/%GRML_NAME_SQUASHFS%/$GRML_NAME_SQUASHFS/" "$BUILD_OUTPUT"/boot/isolinux/syslinux.cfg
701       sed -i "s/%GRML_NAME_SQUASHFS%/$GRML_NAME_SQUASHFS/" "$BUILD_OUTPUT"/boot/grub/menu.lst
702
703       GRML_NAME_SQUASHFS="$(cut_string 20 "$GRML_NAME_SQUASHFS")"
704       GRML_NAME_SQUASHFS="$(extend_string_end 20 "$GRML_NAME_SQUASHFS")"
705       sed -i "s/%GRML_NAME_SQUASHFS%/$GRML_NAME_SQUASHFS/" "$BUILD_OUTPUT"/boot/isolinux/f4
706       sed -i "s/%GRML_NAME_SQUASHFS%/$GRML_NAME_SQUASHFS/" "$BUILD_OUTPUT"/boot/isolinux/f5
707
708       if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
709          log "including grml.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
710          echo "include grml.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
711          [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.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 "$BUILD_OUTPUT/windows exists already, skipping stage 'WINDOWS_BINARIES'"
794             ewarn "$BUILD_OUTPUT/windows exists already, skipping stage 'WINDOWS_BINARIES'" ; 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          fi
805          log "Finished execution of stage 'WINDOWS_BINARIES' [$(date)]"
806          einfo "Finished execution of stage 'WINDOWS_BINARIES'" ; eend 0
807       fi
808
809    FORCE_ISO_REBUILD=true
810    einfo "Finished execution of stage 'boot'" ; eend 0
811    fi
812 else
813    log 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
814    eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
815 fi
816
817 # support installation of local files into the chroot/ISO
818 if [ -n "$CHROOT_INSTALL" ] ; then
819   if ! [ -d "$CHROOT_INSTALL" ] ; then
820      log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
821      ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
822   else
823      log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
824      einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
825      rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
826      eend $?
827      einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
828      FORCE_ISO_REBUILD=true
829   fi
830 fi
831
832 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
833    log "$BUILD_OUTPUT/live exists already, skipping stage 'squashfs'"
834    ewarn "$BUILD_OUTPUT/live exists already, skipping stage 'squashfs'" ; eend 0
835 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
836    log "Skipping stage 'squashfs' as requested via option -q"
837    ewarn "Skipping stage 'squashfs' as requested via option -q" ; eend 0
838 else
839    [ -d "$BUILD_OUTPUT"/live ] || mkdir "$BUILD_OUTPUT"/live
840    # make sure we don't leave (even an empty) base.tgz:
841    [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
842
843    # make sure mksquashfs can handle the according option:
844    if [ -n "$SQUASHFS_ZLIB" ] ; then
845       mksquashfs --help 2>&1 | grep -q -- "$SQUASHFS_ZLIB" || SQUASHFS_ZLIB=''
846    fi
847
848    if echo "$SQUASHFS_OPTIONS" | grep -q -- "-nolzma" ; then
849       if ! mksquashfs --help 2>&1 | grep -q -- '-nolzma' ; then
850          ewarn "mksquashfs does NOT support the nolzma option, just using default zlib mode."
851          SQUASHFS_OPTIONS="$(echo $SQUASHFS_OPTIONS | sed 's/-nolzma//g')"
852          eend 0
853       fi
854    fi
855
856    if echo "$SQUASHFS_OPTIONS" | grep -q -- "-lzma" ; then
857       if ! mksquashfs --help 2>&1 | grep -q -- '-lzma' ; then
858          ewarn "mksquashfs does NOT support the lzma option, falling back to zlib mode."
859          SQUASHFS_OPTIONS="$(echo $SQUASHFS_OPTIONS | sed 's/-lzma//g')"
860          eend 0
861       fi
862    fi
863
864    # support exclusion of files via exclude-file:
865    if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
866       SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE"
867    fi
868
869    # get rid of unnecessary files when building grml-small for final release:
870    if echo "$CLASSES" | grep -q GRML_SMALL ; then
871       SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
872    fi
873
874    SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
875
876    log "mksquashfs $CHROOT_OUTPUT/* $BUILD_OUTPUT/live/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS $SQUASHFS_ZLIB"
877    if mksquashfs $CHROOT_OUTPUT/* $BUILD_OUTPUT/live/"${GRML_NAME}".squashfs \
878       -noappend $SQUASHFS_OPTIONS $SQUASHFS_ZLIB 2>"${SQUASHFS_STDERR}" ; then
879       echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/filesystem.module
880       log "Finished execution of stage 'squashfs' [$(date)]"
881       einfo "Finished execution of stage 'squashfs'" ; eend 0
882    else
883       log "There was an error executing stage 'squashfs' [$(date)]:"
884       log "$(cat $SQUASHFS_STDERR)"
885       eerror "There was an error executing stage 'squashfs':" ; eend 1
886       cat "${SQUASHFS_STDERR}"
887       bailout
888    fi
889
890    FORCE_ISO_REBUILD=true
891 fi
892
893 # create md5sum file:
894 ( cd $BUILD_OUTPUT/GRML &&
895 find .. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
896 # }}}
897
898 # ISO_OUTPUT - mkisofs {{{
899 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
900 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
901
902 if [ "$BOOT_METHOD" = "isolinux" ] ; then
903    BOOT_FILE="boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
904 elif [ "$BOOT_METHOD" = "grub" ] ; then
905    BOOT_FILE="boot/grub/stage2_eltorito"
906 fi
907
908 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ]  ; then
909    log "$ISO_OUTPUT/${ISO_NAME} exists already, skipping stage 'iso build'"
910    ewarn "$ISO_OUTPUT/${ISO_NAME} exists already, skipping stage 'iso build'" ; eend 0
911 elif [ -n "$SKIP_MKISOFS" ] ; then
912    log "Skipping stage 'iso build' as requested via option -n"
913    ewarn "Skipping stage 'iso build' as requested via option -n" ; eend 0
914 else
915    mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
916
917    if $FORCE_ISO_REBUILD ; then
918       log "Forcing rebuild of ISO because files on ISO have been modified."
919       einfo "Forcing rebuild of ISO because files on ISO have been modified."
920    fi
921
922    # support mkisofs as well as genisoimage
923    if which mkisofs >/dev/null 2>&1; then
924       MKISOFS='mkisofs'
925    elif which genisoimage >/dev/null 2>&1; then
926       MKISOFS='genisoimage'
927    else
928       log "Sorry, neither mkisofs nor genisoimage available - can not create ISO."
929       eerror "Sorry, neither mkisofs nor genisoimage available - can not create ISO." ; eend 1
930       bailout
931    fi
932
933    CURRENT_DIR=$(pwd)
934    if cd "$BUILD_OUTPUT" ; then
935       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} ."
936       "$MKISOFS" -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
937               -l -r -J -no-emul-boot -boot-load-size 4 -boot-info-table    \
938               -b $BOOT_FILE -no-pad \
939               -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
940
941       # pad the output ISO to multiples of 256 KiB for partition table support
942       siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
943       cyls=$((siz / 512 / 32 / 16 + 1))   # C=$cyls H=16 S=32
944       siz=$((cyls * 16 * 32 * 512))   # size after padding
945       dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
946          of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
947
948       # support disabling hybrid ISO image
949       if [ "$HYBRID_METHOD" = "disable" ] ; then\
950          log "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
951          einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
952          eend 0
953       # use isohybrid only on request
954       elif [ "$HYBRID_METHOD" = "isohybrid" ] ; then
955          if ! which isohybrid >/dev/null 2>&1 ; then
956            bailout 12 "isohybrid binary not found - please install syslinux/syslinux-common"
957          else
958            log "Creating hybrid ISO file with isohybrid method"
959            einfo "Creating hybrid ISO file with isohybrid method"
960            isohybrid "${ISO_OUTPUT}/${ISO_NAME}"
961            eend $?
962          fi
963       # by default use our manifold boot method:
964       else
965          if ! [ -r boot/grub/core.img ] ; then
966            ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
967          else
968            log "Creating hybrid ISO file with manifold method"
969            einfo "Creating hybrid ISO file with manifold method"
970            echo 1 63 | \
971                mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 1 -p 0x83 -g $cyls:16:32 | \
972                cat - boot/grub/core.img | \
973                dd conv=notrunc of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
974            eend $?
975          fi
976       fi
977
978       # generate md5sum and sha1sum of ISO if we are using class 'RELEASE':
979       case $CLASSES in *RELEASE*)
980          [ "$RC" = 0 ] && \
981          (
982            if cd $ISO_OUTPUT ; then
983              md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
984              touch -r ${ISO_NAME} ${ISO_NAME}.md5
985              sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
986              touch -r ${ISO_NAME} ${ISO_NAME}.sha1
987            fi
988          )
989          ;;
990       esac
991
992       cd $CURRENT_DIR
993    fi
994
995    if [ "$RC" = 0 ] ; then
996       log "Finished execution of stage 'iso build' [$(date)]"
997       einfo "Finished execution of stage 'iso build'" ; eend 0
998    else
999       log "There was an error ($RC) executing stage 'iso build' [$(date)]"
1000       eerror "There was an error executing stage 'iso build'" ; eend 1
1001       bailout $RC
1002    fi
1003 fi
1004 # }}}
1005
1006 # finalize {{{
1007 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
1008 einfo "Successfully finished execution of $PN [running ${SECONDS} seconds]" ; eend 0
1009 log "Successfully finished execution of $PN [running ${SECONDS} seconds]"
1010 bailout 0
1011 # }}}
1012
1013 ## END OF FILE #################################################################
1014 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=3