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