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