check whether arch option and arch class correspond
[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 # validate whether the specified architecture class matches the
420 # architecture (option), otherwise installation of kernel will fail
421 if echo $CLASSES | grep -qi i386 ; then
422    if ! [[ "$ARCH" == "i386" ]] ; then
423       eerror "You specified the I386 class but are trying to build something else (AMD64?)."
424       eerror "-> Either invoke grml-live with '-i i386' or adjust the architecture class. Exiting."
425       bailout
426    fi
427 elif echo $CLASSES | grep -qi amd64 ; then
428    if ! [[ "$ARCH" == "amd64" ]] ; then
429       eerror "You specified the AMD64 class but are trying to build something else (I386?)."
430       eerror "-> Either invoke grml-live with '-i amd64' or adjust the architecture class. Exiting."
431       bailout
432    fi
433 fi
434
435 # set $ARCH
436 [ -n "$ARCH" ] || ARCH="$(dpkg --print-architecture)"
437 if grep -q -- 'FAI_DEBOOTSTRAP_OPTS.*--arch' "$NFSROOT_CONF" ; then
438    sed "s/--arch [a-z0-9]* /--arch $ARCH /" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
439 else
440    sed "s|^FAI_DEBOOTSTRAP_OPTS=\"\(.*\)|FAI_DEBOOTSTRAP_OPTS=\"--arch $ARCH \1|" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
441 fi
442 # }}}
443
444 # CHROOT_OUTPUT - execute FAI {{{
445 if [ -n "$BUILD_DIRTY" ]; then
446   einfo "Skipping FAI" ; eend 0
447 else
448    [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
449
450    if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
451       FAI_ACTION=softupdate
452    else
453       FAI_ACTION=dirinstall
454    fi
455
456    if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
457       if ! [ -r "$CHROOT_OUTPUT/etc/grml_version" ] ; then
458          log "Error: does not look like you have a working chroot. Updating/building not possible."
459          eerror "Error: does not look like you have a working chroot. Updating/building not possible. (Drop -u/-b option?)"
460          eend 1
461          bailout 20
462       fi
463    fi
464
465    if [ -d "$CHROOT_OUTPUT/bin" -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
466       log "$CHROOT_OUTPUT exists already, skipping stage 'fai dirinstall'"
467       ewarn "$CHROOT_OUTPUT exists already, skipping stage 'fai dirinstall'" ; eend 0
468    else
469       mkdir -p "$CHROOT_OUTPUT" || bailout 5 "Problem with creating $CHROOT_OUTPUT for FAI"
470
471       if [ -n "${MIRROR_DIRECTORY}" ] ; then
472          mkdir -p "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
473          mount --bind "${MIRROR_DIRECTORY}" "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
474       fi
475
476       log "Executed FAI command line:"
477       log "BUILD_ONLY=$BUILD_ONLY fai $VERBOSE -C $GRML_FAI_CONFIG -c$CLASSES -u $HOSTNAME $FAI_ACTION $CHROOT_OUTPUT $FAI_ARGS"
478       BUILD_ONLY="$BUILD_ONLY" fai $VERBOSE -C "$GRML_FAI_CONFIG" -c"$CLASSES" -u \
479       "$HOSTNAME" $FAI_ACTION "$CHROOT_OUTPUT" $FAI_ARGS | tee -a $LOGFILE
480       RC="$PIPESTATUS" # notice: bash-only
481
482       if [ "$RC" != 0 ] ; then
483          log "Error while executing fai [exit code ${RC}]. Exiting."
484          eerror "Error while executing fai [exit code ${RC}]. Exiting." ; eend 1
485          bailout 1
486       else
487          log "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$ISO_DATE]"
488          echo "$GRML_NAME $VERSION Release Codename $RELEASENAME [$ISO_DATE]" > $CHROOT_OUTPUT/etc/grml_version
489          chmod 644 $CHROOT_OUTPUT/etc/grml_version
490          einfo "Rebuilding initramfs"
491          # make sure new /etc/grml_version reaches the initramfs:
492          chroot $CHROOT_OUTPUT update-initramfs -u -t
493          eend $?
494       fi
495
496       # Remove all FAI logs from chroot if class RELEASE is used:
497       if [ -f "$CHROOT_OUTPUT"/etc/grml_fai_release ] ; then
498          rm -rf "$CHROOT_OUTPUT"/var/log/fai/*
499       fi
500
501       # make sure we don't leave any mounts - FAI doesn't remove them always
502       umount $CHROOT_OUTPUT/proc 2>/dev/null || /bin/true
503       umount $CHROOT_OUTPUT/sys  2>/dev/null || /bin/true
504       umount $CHROOT_OUTPUT/dev/pts 2>/dev/null || /bin/true
505       umount $CHROOT_OUTPUT/dev 2>/dev/null || /bin/true
506
507       [ -n "$MIRROR_DIRECTORY" ] && umount "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
508
509       # notice: 'fai dirinstall' does not seem to exit appropriate, so:
510       ERROR=''
511       CHECKLOG=/var/log/fai/$HOSTNAME/last
512       if [ -r "$CHECKLOG/software.log" ] ; then
513          # 1 errors during executing of commands
514          grep 'dpkg: error processing' $CHECKLOG/software.log >> $LOGFILE && ERROR=1
515          grep 'E: Method http has died unexpectedly!' $CHECKLOG/software.log >> $LOGFILE && ERROR=2
516          grep 'ERROR: chroot' $CHECKLOG/software.log >> $LOGFILE && ERROR=3
517          grep 'E: Failed to fetch' $CHECKLOG/software.log >> $LOGFILE && ERROR=4
518          grep 'Unable to write mmap - msync (28 No space left on device)' $CHECKLOG/software.log >> $LOGFILE && ERROR=5
519       fi
520
521       if [ -r "$CHECKLOG/shell.log" ] ; then
522          grep 'FAILED with exit code' $CHECKLOG/shell.log >> $LOGFILE && ERROR=2
523       fi
524
525       if [ -n "$ERROR" ] ; then
526          log "There was an error [${ERROR}] during execution of stage 'fai dirinstall' [$(date)]"
527          eerror "There was an error during execution of stage 'fai dirinstall'"
528          echo "   Check out ${CHECKLOG}/ for details. [exit ${ERROR}]"
529          eend 1
530          bailout 1
531       else
532          log "Finished execution of stage 'fai dirinstall' [$(date)]"
533          einfo "Finished execution of stage 'fai dirinstall'"
534       fi
535
536    fi
537 fi # BUILD_DIRTY?
538 # }}}
539
540 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
541 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
542 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
543
544 # i386:
545 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
546    if [ -d "$BUILD_OUTPUT"/boot -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
547       log "$BUILD_OUTPUT/boot exists already, skipping stage 'boot'"
548       ewarn "$BUILD_OUTPUT/boot exists already, skipping stage 'boot'" ; eend 0
549    else
550       # booting stuff:
551       [ -d "$BUILD_OUTPUT"/boot/isolinux ] || mkdir -p "$BUILD_OUTPUT"/boot/isolinux
552       [ -d "$BUILD_OUTPUT"/boot/"${SHORT_GRML_NAME}" ] || mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_GRML_NAME}"
553
554       if [ -z "$NO_ADDONS" ] ; then
555          [ -d "$BUILD_OUTPUT"/boot/addons   ] || mkdir -p "$BUILD_OUTPUT"/boot/addons
556          cp /boot/memtest86+.bin "$BUILD_OUTPUT"/boot/addons/memtest
557       fi
558
559       # if we don't have an initrd we a) can't boot and b) there was an error
560       # during build, so check for the file:
561       INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
562       if [ -n "$INITRD" ] ; then
563          cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_GRML_NAME}"/initrd.gz
564          find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
565       else
566          log "No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
567          eerror "No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
568          bailout 10
569       fi
570
571       KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
572       if [ -n "$KERNEL_IMAGE" ] ; then
573          cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_GRML_NAME}"/linux26
574       else
575          log "No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
576          eerror "No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
577          bailout 11
578       fi
579
580       [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
581       if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
582          log "${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
583          eerror "${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
584          bailout 8
585       fi
586
587       cp ${TEMPLATE_DIRECTORY}/boot/isolinux/*  "$BUILD_OUTPUT"/boot/isolinux/
588
589       if [ -z "$NO_ADDONS" ] ; then
590          if ! [ -d /usr/share/grml-live/templates/boot/addons/bsd4grml ] ; then
591            ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
592          else
593            # copy only files so we can handle bsd4grml on its own
594            for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
595                test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
596            done
597
598            if [ -z "$NO_ADDONS_BSD4GRML" ] ; then
599               cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
600            fi
601          fi
602       fi
603
604       if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
605          cp -a ${TEMPLATE_DIRECTORY}/boot/grub  "$BUILD_OUTPUT"/boot/
606       fi
607       # make sure we have recent template files available, otherwise updating
608       # the strings like $GRML_NAME and $VERSION might be out of date
609       cp ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
610
611       if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
612          log "${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
613          eerror "${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
614          bailout 9
615       fi
616
617       [ -d "$BUILD_OUTPUT"/GRML ] || mkdir "$BUILD_OUTPUT"/GRML
618       cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/
619
620       # adjust boot splash information:
621       RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
622       RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
623       RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
624
625       sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/grml-version
626       sed -i "s/%DATE%/$ISO_DATE/"             "$BUILD_OUTPUT"/GRML/grml-version
627
628       sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/" "$BUILD_OUTPUT"/boot/isolinux/boot.msg
629       sed -i "s/%DATE%/$ISO_DATE/"             "$BUILD_OUTPUT"/boot/isolinux/boot.msg
630
631       sed -i "s/%GRML_NAME%/$SHORT_GRML_NAME/" "$BUILD_OUTPUT"/boot/isolinux/isolinux.cfg
632       sed -i "s/%GRML_NAME%/$SHORT_GRML_NAME/" "$BUILD_OUTPUT"/boot/isolinux/syslinux.cfg
633
634       sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/" "$BUILD_OUTPUT"/boot/isolinux/boot-beep.msg
635       sed -i "s/%DATE%/$ISO_DATE/"             "$BUILD_OUTPUT"/boot/isolinux/boot-beep.msg
636
637       sed -i "s/%VERSION%/$VERSION/"           "$BUILD_OUTPUT"/boot/grub/menu.lst
638       sed -i "s/%GRML_NAME%/$SHORT_GRML_NAME/" "$BUILD_OUTPUT"/boot/grub/menu.lst
639
640       sed -i "s/%VERSION%/$VERSION/"           "$BUILD_OUTPUT"/boot/grub/grub.cfg
641       sed -i "s/%GRML_NAME%/$SHORT_GRML_NAME/" "$BUILD_OUTPUT"/boot/grub/grub.cfg
642
643       # make sure the squashfs filename is set accordingly:
644       GRML_NAME_SQUASHFS="$GRML_NAME.squashfs"
645       sed -i "s/%GRML_NAME_SQUASHFS%/$GRML_NAME_SQUASHFS/" "$BUILD_OUTPUT"/boot/isolinux/isolinux.cfg
646       sed -i "s/%GRML_NAME_SQUASHFS%/$GRML_NAME_SQUASHFS/" "$BUILD_OUTPUT"/boot/isolinux/syslinux.cfg
647       sed -i "s/%GRML_NAME_SQUASHFS%/$GRML_NAME_SQUASHFS/" "$BUILD_OUTPUT"/boot/grub/menu.lst
648
649       GRML_NAME_SQUASHFS="$(cut_string 20 "$GRML_NAME_SQUASHFS")"
650       GRML_NAME_SQUASHFS="$(extend_string_end 20 "$GRML_NAME_SQUASHFS")"
651       sed -i "s/%GRML_NAME_SQUASHFS%/$GRML_NAME_SQUASHFS/" "$BUILD_OUTPUT"/boot/isolinux/f4
652       sed -i "s/%GRML_NAME_SQUASHFS%/$GRML_NAME_SQUASHFS/" "$BUILD_OUTPUT"/boot/isolinux/f5
653
654       # jump back to grub from bsd4grml:
655       if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
656          if [ -e "$BUILD_OUTPUT"/boot/grub/core.img ]; then
657             GRUB_VERSION=2
658          else
659             GRUB_VERSION=1
660          fi
661          if [ -e "$BUILD_OUTPUT"/boot/grub/stage2 ]; then
662             GRUB_LEGACY=stage2
663          else
664             GRUB_LEGACY=stage2_eltorito
665          fi
666
667          # why not ed(1)?
668          for file in "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 \
669                      "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.cfg; do
670              sed -i -e "s!%GRUB_VERSION%!$GRUB_VERSION!g" \
671                     -e "s!%GRUB_LEGACY%!$GRUB_LEGACY!g" "$file"
672          done
673       fi
674
675       # autostart for Windows:
676       if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
677          cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
678       fi
679
680       # windows-binaries:
681       if [ -n "$WINDOWS_BINARIES" ] ; then
682          if [ -f "$BUILD_OUTPUT"/windows/putty.exe ] ; then
683             log "$BUILD_OUTPUT/windows exists already, skipping stage 'WINDOWS_BINARIES'"
684             ewarn "$BUILD_OUTPUT/windows exists already, skipping stage 'WINDOWS_BINARIES'" ; eend 0
685          else
686             if ! [ -d "$BUILD_OUTPUT"/windows ] ; then
687                mkdir "$BUILD_OUTPUT"/windows
688                ( cd "$BUILD_OUTPUT"/windows
689                  for file in pageant plink pscp psftp putty puttygen ; do
690                     wget -O ${file}.exe ${WINDOWS_BINARIES}/${file}.exe
691                     md5sum ${file}.exe > ${file}.exe.md5
692                  done )
693             fi
694          fi
695       log "Finished execution of stage 'WINDOWS_BINARIES' [$(date)]"
696       einfo "Finished execution of stage 'WINDOWS_BINARIES'" ; eend 0
697       fi
698    einfo "Finished execution of stage 'boot'" ; eend 0
699    fi
700 # ppc:
701 elif [ "$ARCH" = powerpc ] ; then
702     ewarn 'Warning: formorer, it is your turn. :)'>&2
703 # unsuported:
704 else
705    eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
706 fi
707
708 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
709    log "$BUILD_OUTPUT/live exists already, skipping stage 'squashfs'"
710    ewarn "$BUILD_OUTPUT/live exists already, skipping stage 'squashfs'" ; eend 0
711 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
712    log "Skipping stage 'squashfs' as requested via option -q"
713    ewarn "Skipping stage 'squashfs' as requested via option -q" ; eend 0
714 else
715    [ -d "$BUILD_OUTPUT"/live ] || mkdir "$BUILD_OUTPUT"/live
716    # make sure we don't leave (even an empty) base.tgz:
717    [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
718
719    # make sure mksquashfs can handle the according option:
720    if [ -n "$SQUASHFS_ZLIB" ] ; then
721       mksquashfs --help 2>&1 | grep -q -- "$SQUASHFS_ZLIB" || SQUASHFS_ZLIB=''
722    fi
723
724    if echo "$SQUASHFS_OPTIONS" | grep -q -- "-nolzma" ; then
725       if ! mksquashfs --help 2>&1 | grep -q -- '-nolzma' ; then
726          ewarn "mksquashfs does NOT support the nolzma option, just using default zlib mode."
727          SQUASHFS_OPTIONS="$(echo $SQUASHFS_OPTIONS | sed 's/-nolzma//g')"
728          eend 0
729       fi
730    fi
731
732    if echo "$SQUASHFS_OPTIONS" | grep -q -- "-lzma" ; then
733       if ! mksquashfs --help 2>&1 | grep -q -- '-lzma' ; then
734          ewarn "mksquashfs does NOT support the lzma option, falling back to zlib mode."
735          SQUASHFS_OPTIONS="$(echo $SQUASHFS_OPTIONS | sed 's/-lzma//g')"
736          eend 0
737       fi
738    fi
739
740    # support exclusion of files via exclude-file:
741    if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
742       SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE"
743    fi
744
745    # get rid of unnecessary files when building grml-small for final release:
746    if echo "$CLASSES" | grep -q GRML_SMALL ; then
747       SQUASHFS_OPTIONS="$SQUASHFS_OUTPUT -e initrd.img* vmlinuz*"
748    fi
749
750    SQUASHFS_OUTPUT="$(mktemp -t grml-live.XXXXXX)"
751    log "mksquashfs $CHROOT_OUTPUT/* $BUILD_OUTPUT/live/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS $SQUASHFS_ZLIB"
752    if mksquashfs $CHROOT_OUTPUT/* $BUILD_OUTPUT/live/"${GRML_NAME}".squashfs \
753       -noappend $SQUASHFS_OPTIONS $SQUASHFS_ZLIB 2>"${SQUASHFS_OUTPUT}" ; then
754       echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/filesystem.module
755       log "Finished execution of stage 'squashfs' [$(date)]"
756       einfo "Finished execution of stage 'squashfs'" ; eend 0
757       rm -f "${SQUASHFS_OUTPUT}"
758    else
759       log "There was an error executing stage 'squashfs' [$(date)]:"
760       log "$(cat $SQUASHFS_OUTPUT)"
761       eerror "There was an error executing stage 'squashfs':" ; eend 1
762       cat "${SQUASHFS_OUTPUT}"
763       rm -f "${SQUASHFS_OUTPUT}"
764       bailout
765    fi
766 fi
767
768 # create md5sum file:
769 ( cd $BUILD_OUTPUT/GRML &&
770 find .. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
771 # }}}
772
773 # ISO_OUTPUT - mkisofs {{{
774 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
775 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
776
777 if [ "$BOOT_METHOD" = "isolinux" ] ; then
778    BOOT_FILE="boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
779 elif [ "$BOOT_METHOD" = "grub" ] ; then
780    BOOT_FILE="boot/grub/stage2_eltorito"
781 fi
782
783 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
784
785    # support mkisofs as well as genisoimage
786    if which mkisofs >/dev/null 2>&1; then
787       MKISOFS='mkisofs'
788    elif which genisoimage >/dev/null 2>&1; then
789       MKISOFS='genisoimage'
790    else
791       log "Sorry, neither mkisofs nor genisoimage available - can not create ISO."
792       eerror "Sorry, neither mkisofs nor genisoimage available - can not create ISO." ; eend 1
793       bailout
794    fi
795
796    log "$ISO_OUTPUT exists already, skipping stage 'iso build'"
797    ewarn "$ISO_OUTPUT exists already, skipping stage 'iso build'" ; eend 0
798 else
799    mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
800
801    CURRENT_DIR=$(pwd)
802    if cd "$BUILD_OUTPUT" ; then
803       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} ."
804       "$MKISOFS" -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
805               -l -r -J -no-emul-boot -boot-load-size 4 -boot-info-table    \
806               -b $BOOT_FILE -no-pad \
807               -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
808
809       # pad the output ISO to multiples of 256 KiB for partition table support
810       siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
811       cyls=$((siz / 512 / 32 / 16 + 1))         # C=$cyls H=16 S=32
812       siz=$((cyls * 16 * 32 * 512))             # size after padding
813       dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
814          of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
815
816       # support disabling hybrid ISO image
817       if [ "$HYBRID_METHOD" = "disable" ] ; then\
818          log "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
819          einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
820          eend 0
821       # use isohybrid only on request
822       elif [ "$HYBRID_METHOD" = "isohybrid" ] ; then
823          if ! which isohybrid >/dev/null 2>&1 ; then
824            bailout 12 "isohybrid binary not found - please install syslinux/syslinux-common"
825          else
826            log "Creating hybrid ISO file with isohybrid method"
827            einfo "Creating hybrid ISO file with isohybrid method"
828            isohybrid "${ISO_OUTPUT}/${ISO_NAME}"
829            eend $?
830          fi
831       # by default use our manifold boot method:
832       else
833          if ! [ -r boot/grub/core.img ] ; then
834            ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
835          else
836            log "Creating hybrid ISO file with manifold method"
837            einfo "Creating hybrid ISO file with manifold method"
838            echo 1 63 | \
839                mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 1 -p 0x83 -g $cyls:16:32 | \
840                cat - boot/grub/core.img | \
841                dd conv=notrunc of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
842            eend $?
843          fi
844       fi
845
846       # generate md5sum and sha1sum of ISO if we are using class 'RELEASE':
847       case $CLASSES in *RELEASE*)
848          [ "$RC" = 0 ] && \
849          (
850            if cd $ISO_OUTPUT ; then
851              md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
852              touch -r ${ISO_NAME} ${ISO_NAME}.md5
853              sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
854              touch -r ${ISO_NAME} ${ISO_NAME}.sha1
855            fi
856          )
857          ;;
858       esac
859
860       cd $CURRENT_DIR
861    fi
862
863    if [ "$RC" = 0 ] ; then
864       log "Finished execution of stage 'iso build' [$(date)]"
865       einfo "Finished execution of stage 'iso build'" ; eend 0
866    else
867       log "There was an error ($RC) executing stage 'iso build' [$(date)]"
868       eerror "There was an error executing stage 'iso build'" ; eend 1
869       bailout $RC
870    fi
871 fi
872 # }}}
873
874 # finalize {{{
875 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
876 einfo "Sucessfully finished execution of $PN [running ${SECONDS} seconds]" ; eend 0
877 log "Sucessfully finished execution of $PN [running ${SECONDS} seconds]"
878 bailout 0
879 # }}}
880
881 ## END OF FILE #################################################################
882 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=3