Fix jumping back from the bsd4grml loader (ldbsd.com) to GNU GRUB
[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.18'
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        CHROOT_OUTPUT="$OUTPUT/grml_chroot"
235        BUILD_OUTPUT="$OUTPUT/grml_cd"
236        ISO_OUTPUT="$OUTPUT/grml_isos"
237        ;;
238     q) SKIP_MKSQUASHFS=1 ;;
239     r) RELEASENAME="$OPTARG" ;;
240     s) SUITE="$OPTARG" ;;
241     t) TEMPLATE_DIRECTORY="$OPTARG";;
242     v) VERSION="$OPTARG" ;;
243     F) FORCE=1 ;;
244     u) UPDATE=1 ;;
245     V) VERBOSE="-v" ;;
246     z) SQUASHFS_ZLIB="-nolzma" ;;
247     ?) echo "invalid option -$OPTARG" >&2; bailout 1 ;;
248   esac
249 done
250 shift $(($OPTIND - 1))  # set ARGV to the first not parsed commandline parameter
251 # }}}
252
253 # some misc checks before executing FAI {{{
254 [ -n "$CLASSES" ] || bailout 1 "Error: \$CLASSES unset, please set it in $LIVE_CONF or
255 specify it on the command line using the -c option."
256 [ -n "$OUTPUT" ] || bailout 1 "Error: \$OUTPUT unset, please set it in $LIVE_CONF or
257 specify it on the command line using the -o option."
258
259 # trim characters that are known to cause problems inside $GRML_NAME;
260 # for example isolinux does not like '-' inside the directory name
261 [ -n "$GRML_NAME" ] && export SHORT_GRML_NAME="$(echo $GRML_NAME | tr -d ',./;\- ')"
262
263 # export variables to have them available in fai scripts:
264 [ -n "$GRML_NAME" ]   && export GRML_NAME="$GRML_NAME"
265 [ -n "$RELEASENAME" ] && export RELEASENAME="$RELEASENAME"
266 # }}}
267
268 # clean/zero grml-live logfile {{{
269 if [ -n "$ZERO_LOGFILE" ] ; then
270    echo -n > $LOGFILE
271 fi
272 # }}}
273
274 # clean/zero/remove old FAI directory {{{
275 if [ -n "$ZERO_FAI_LOGFILE" ] ; then
276    if [ -d /var/log/fai/"$HOSTNAME" ] ; then
277       rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last)"
278       rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-dirinstall)"
279       rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-softupdate)"
280       rm -f /var/log/fai/"$HOSTNAME"/last \
281             /var/log/fai/"$HOSTNAME"/last-dirinstall \
282             /var/log/fai/"$HOSTNAME"/last-softupdate
283    fi
284 fi
285 # }}}
286
287 # ask user whether the setup is ok {{{
288 if [ -z "$FORCE" ] ; then
289    echo
290    echo "${PN} [${GRML_LIVE_VERSION}]: check your configuration (or use -F to force execution):"
291    echo
292    echo "  FAI classes:       $CLASSES"
293    [ -r "$LOCAL_CONFIG" ]       && echo "  local config:      /etc/grml/grml-live.local"
294    [ -n "$CONFIG" ]             && echo "  configuration:     $CONFIG"
295    echo "  main directory:    $OUTPUT"
296    [ -n "$CHROOT_OUTPUT" ]      && echo "  chroot target:     $CHROOT_OUTPUT"
297    [ -n "$BUILD_OUTPUT" ]       && echo "  build target:      $BUILD_OUTPUT"
298    [ -n "$ISO_OUTPUT" ]         && echo "  ISO target:        $ISO_OUTPUT"
299    [ -n "$GRML_NAME" ]          && echo "  grml name:         $GRML_NAME"
300    [ -n "$RELEASENAME" ]        && echo "  release name:      $RELEASENAME"
301    [ -n "$VERSION" ]            && echo "  grml version:      $VERSION"
302    [ -n "$SUITE" ]              && echo "  Debian suite:      $SUITE"
303    [ -n "$ARCH" ]               && echo "  Architecture:      $ARCH"
304    [ -n "$BOOT_METHOD" ]        && echo "  Boot method:       $BOOT_METHOD"
305    [ -n "$TEMPLATE_DIRECTORY" ] && echo "  Template files:    $TEMPLATE_DIRECTORY"
306    [ -n "$FAI_ARGS" ]           && echo "  additional arguments for FAI: $FAI_ARGS"
307    [ -n "$LOGFILE" ]            && echo "  Logging to file:   $LOGFILE"
308    [ -n "$SQUASHFS_ZLIB" ]      && echo "  Using ZLIB (instead of LZMA) compression."
309    [ -n "$SQUASHFS_OPTIONS" ]   && echo "  Using SQUASHFS_OPTIONS ${SQUASHFS_OPTIONS}"
310    [ -n "$VERBOSE" ]            && echo "  Using VERBOSE mode."
311    [ -n "$UPDATE" ]             && echo "  Executing UPDATE instead of fresh installation."
312    [ -n "$SKIP_MKSQUASHFS" ]    && echo "  Skipping creation of SQUASHFS file."
313    [ -n "$BUILD_ONLY" ]         && echo "  Executing BUILD_ONLY instead of fresh installation or UPDATE."
314    [ -n "$BUILD_DIRTY" ]        && echo "  Executing BUILD_DIRTY to leave chroot untouched."
315    echo
316    echo -n "Is this ok for you? [y/N] "
317    read a
318    if ! [ "$a" = 'y' -o "$a" = 'Y' ] ; then
319       bailout 1 "Exiting as requested."
320    fi
321    echo
322 fi
323
324 if [ -n "$CONFIG" ] ; then
325    if ! [ -f "$CONFIG" ] ; then
326       log "Sorry, $CONFIG could not be read. Exiting. [$(date)]"
327       eerror "Sorry, $CONFIG could not be read. Exiting."
328       bailout 1
329    else
330       log "Sourcing $CONFIG"
331       . $CONFIG
332    fi
333 fi
334
335 start_seconds=$(cut -d . -f 1 /proc/uptime)
336 log "------------------------------------------------------------------------------"
337 log "Starting grml-live [${GRML_LIVE_VERSION}] run on $(date)"
338 log "Executed grml-live command line:"
339 log "$CMDLINE"
340
341 einfo "Logging actions to logfile $LOGFILE"
342 # }}}
343
344 # on-the-fly configuration {{{
345 if [ -n "$MIRROR_DIRECTORY" ] ; then
346    if ! [ -d "$MIRROR_DIRECTORY/debian" ] ; then
347       log "Sorry, $MIRROR_DIRECTORY/debian does not seem to exist. Exiting. [$(date)]"
348       eerror "Sorry, $MIRROR_DIRECTORY/debian does not seem to exist. Exiting."
349       bailout 1
350    fi
351    cat > "$SOURCES_LIST_FILE" << EOF
352 # NOTE: This file is *NOT* meant for manual customisation! This file is
353 # modified by grml-live and any changes might be overriden.
354 # You might consider using GRML_LIVE_SOURCES in /etc/grml/grml-live.conf*
355 # and using /etc/grml/fai/files/etc/apt instead!'
356 EOF
357    echo "$MIRROR_SOURCES" >> "$SOURCES_LIST_FILE"
358    if [ -n "$GRML_LIVE_SOURCES" ] ; then
359       echo "$GRML_LIVE_SOURCES" >> "$SOURCES_LIST_FILE"
360    fi
361 elif [ -n "$GRML_LIVE_SOURCES" ] ; then
362    cat > "$SOURCES_LIST_FILE" << EOF
363 # NOTE: This file is *NOT* meant for manual customisation! This file is
364 # modified by grml-live and any changes might be overriden.
365 # You might consider using GRML_LIVE_SOURCES in /etc/grml/grml-live.conf*
366 # and using /etc/grml/fai/files/etc/apt instead!'
367 EOF
368    echo "$GRML_LIVE_SOURCES" >> "$SOURCES_LIST_FILE"
369 fi
370
371 if [ -n "$FAI_DEBOOTSTRAP" ] ; then
372    sed "s#^FAI_DEBOOTSTRAP=.*#FAI_DEBOOTSTRAP=\"$FAI_DEBOOTSTRAP\"#" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
373 fi
374
375 # does this suck? YES!
376 if [ -n "$SUITE" ] ; then
377
378    # /usr/share/debootstrap/scripts/unstable does not exist, instead use 'sid':
379    case $SUITE in
380       unstable) SUITE='sid' ;;
381    esac
382
383    DIST=" etch\| stable\| lenny\| squeeze\| testing\| sid\| unstable"
384    sed "s/\(^deb .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/" "$SOURCES_LIST_FILE" | sponge "$SOURCES_LIST_FILE"
385    for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" ; do
386        if [ -n "$file" ] ; then
387           sed "s/^SUITE=.*/SUITE=\"$SUITE\"/" $file | sponge $file
388           sed "s/\(^deb .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/" "$file" | sponge "$file"
389        fi
390    done
391
392    # notice: activate grml-live pool only if we are building against unstable:
393    if grep -qe unstable -qe sid "$SOURCES_LIST_FILE" ; then
394       grep -q 'grml-live.*main' "$SOURCES_LIST_FILE" || \
395       grep grml-stable "$SOURCES_LIST_FILE" | \
396            sed 's/grml-stable/grml-live/' >> "$SOURCES_LIST_FILE"
397    else
398       grep -q 'grml-live.*main' "$SOURCES_LIST_FILE" && \
399       sed 's/.*grml-live.*/# removed grml-live repository/' "$SOURCES_LIST_FILE" | sponge "$SOURCES_LIST_FILE"
400    fi
401
402    for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" "$NFSROOT_CONF" ; do
403        if [ -n "$file" ] ; then
404           sed "s|^FAI_DEBOOTSTRAP=\"[a-z]* |FAI_DEBOOTSTRAP=\"$SUITE |" "$file" | sponge "$file"
405        fi
406    done
407 fi
408
409 # set $ARCH
410 [ -n "$ARCH" ] || ARCH="$(dpkg --print-architecture)"
411 if grep -q -- 'FAI_DEBOOTSTRAP_OPTS.*--arch' "$NFSROOT_CONF" ; then
412    sed "s/--arch [a-z0-9]* /--arch $ARCH /" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
413 else
414    sed "s|^FAI_DEBOOTSTRAP_OPTS=\"\(.*\)|FAI_DEBOOTSTRAP_OPTS=\"--arch $ARCH \1|" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
415 fi
416 # }}}
417
418 # CHROOT_OUTPUT - execute FAI {{{
419 if [ -n "$BUILD_DIRTY" ]; then
420   einfo "Skipping FAI" ; eend 0
421 else
422    [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
423
424    if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
425       FAI_ACTION=softupdate
426    else
427       FAI_ACTION=dirinstall
428    fi
429
430    if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
431       if ! [ -r "$CHROOT_OUTPUT/etc/grml_version" ] ; then
432          log "Error: does not look like you have a working chroot. Updating/building not possible."
433          eerror "Error: does not look like you have a working chroot. Updating/building not possible. (Drop -u/-b option?)"
434          eend 1
435          bailout 20
436       fi
437    fi
438
439    if [ -d "$CHROOT_OUTPUT/bin" -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
440       log "$CHROOT_OUTPUT exists already, skipping stage 'fai dirinstall'"
441       ewarn "$CHROOT_OUTPUT exists already, skipping stage 'fai dirinstall'" ; eend 0
442    else
443       mkdir -p "$CHROOT_OUTPUT" || bailout 5 "Problem with creating $CHROOT_OUTPUT for FAI"
444
445       if [ -n "${MIRROR_DIRECTORY}" ] ; then
446          mkdir -p "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
447          mount --bind "${MIRROR_DIRECTORY}" "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
448       fi
449
450       log "Executed FAI command line:"
451       log "BUILD_ONLY=$BUILD_ONLY fai $VERBOSE -C $GRML_FAI_CONFIG -c$CLASSES -u $HOSTNAME $FAI_ACTION $CHROOT_OUTPUT $FAI_ARGS"
452       BUILD_ONLY="$BUILD_ONLY" fai $VERBOSE -C "$GRML_FAI_CONFIG" -c"$CLASSES" -u \
453       "$HOSTNAME" $FAI_ACTION "$CHROOT_OUTPUT" $FAI_ARGS | tee -a $LOGFILE
454       RC="$PIPESTATUS" # notice: bash-only
455
456       if [ "$RC" != 0 ] ; then
457          log "Error while executing fai [exit code ${RC}]. Exiting."
458          eerror "Error while executing fai [exit code ${RC}]. Exiting." ; eend 1
459          bailout 1
460       else
461          log "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$ISO_DATE]"
462          echo "$GRML_NAME $VERSION Release Codename $RELEASENAME [$ISO_DATE]" > $CHROOT_OUTPUT/etc/grml_version
463          chmod 644 $CHROOT_OUTPUT/etc/grml_version
464          einfo "Rebuilding initramfs"
465          # make sure new /etc/grml_version reaches the initramfs:
466          chroot $CHROOT_OUTPUT update-initramfs -u -t
467          eend $?
468       fi
469
470       # Remove all FAI logs from chroot if class RELEASE is used:
471       if [ -f "$CHROOT_OUTPUT"/etc/grml_fai_release ] ; then
472          rm -rf "$CHROOT_OUTPUT"/var/log/fai/*
473       fi
474
475       # make sure we don't leave any mounts - FAI doesn't remove them always
476       umount $CHROOT_OUTPUT/proc 2>/dev/null || /bin/true
477       umount $CHROOT_OUTPUT/sys  2>/dev/null || /bin/true
478       umount $CHROOT_OUTPUT/dev/pts 2>/dev/null || /bin/true
479       umount $CHROOT_OUTPUT/dev 2>/dev/null || /bin/true
480
481       [ -n "$MIRROR_DIRECTORY" ] && umount "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
482
483       # notice: 'fai dirinstall' does not seem to exit appropriate, so:
484       ERROR=''
485       CHECKLOG=/var/log/fai/$HOSTNAME/last
486       if [ -r "$CHECKLOG/software.log" ] ; then
487          # 1 errors during executing of commands
488          grep 'dpkg: error processing' $CHECKLOG/software.log >> $LOGFILE && ERROR=1
489          grep 'E: Method http has died unexpectedly!' $CHECKLOG/software.log >> $LOGFILE && ERROR=2
490          grep 'ERROR: chroot' $CHECKLOG/software.log >> $LOGFILE && ERROR=3
491          grep 'E: Failed to fetch' $CHECKLOG/software.log >> $LOGFILE && ERROR=4
492          grep 'Unable to write mmap - msync (28 No space left on device)' $CHECKLOG/software.log >> $LOGFILE && ERROR=5
493       fi
494
495       if [ -r "$CHECKLOG/shell.log" ] ; then
496          grep 'FAILED with exit code' $CHECKLOG/shell.log >> $LOGFILE && ERROR=2
497       fi
498
499       if [ -n "$ERROR" ] ; then
500          log "There was an error [${ERROR}] during execution of stage 'fai dirinstall' [$(date)]"
501          eerror "There was an error during execution of stage 'fai dirinstall'"
502          echo "   Check out ${CHECKLOG}/ for details. [exit ${ERROR}]"
503          eend 1
504          bailout 1
505       else
506          log "Finished execution of stage 'fai dirinstall' [$(date)]"
507          einfo "Finished execution of stage 'fai dirinstall'"
508       fi
509
510    fi
511 fi # BUILD_DIRTY?
512 # }}}
513
514 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
515 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
516 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
517
518 # i386:
519 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
520    if [ -d "$BUILD_OUTPUT"/boot -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
521       log "$BUILD_OUTPUT/boot exists already, skipping stage 'boot'"
522       ewarn "$BUILD_OUTPUT/boot exists already, skipping stage 'boot'" ; eend 0
523    else
524       # booting stuff:
525       [ -d "$BUILD_OUTPUT"/boot/isolinux ] || mkdir -p "$BUILD_OUTPUT"/boot/isolinux
526       [ -d "$BUILD_OUTPUT"/boot/"${SHORT_GRML_NAME}" ] || mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_GRML_NAME}"
527
528       if [ -z "$NO_ADDONS" ] ; then
529          [ -d "$BUILD_OUTPUT"/boot/addons   ] || mkdir -p "$BUILD_OUTPUT"/boot/addons
530          cp /boot/memtest86+.bin "$BUILD_OUTPUT"/boot/addons/memtest
531       fi
532
533       # if we don't have an initrd we a) can't boot and b) there was an error
534       # during build, so check for the file:
535       INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
536       if [ -n "$INITRD" ] ; then
537          cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_GRML_NAME}"/initrd.gz
538          find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
539       else
540          log "No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
541          eerror "No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
542          bailout 10
543       fi
544
545       KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
546       if [ -n "$KERNEL_IMAGE" ] ; then
547          cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_GRML_NAME}"/linux26
548       else
549          log "No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
550          eerror "No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
551          bailout 11
552       fi
553
554       [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
555       if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
556          log "${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
557          eerror "${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
558          bailout 8
559       fi
560
561       cp ${TEMPLATE_DIRECTORY}/boot/isolinux/*  "$BUILD_OUTPUT"/boot/isolinux/
562
563       if [ -z "$NO_ADDONS" ] ; then
564          if ! [ -d /usr/share/grml-live/templates/boot/addons/bsd4grml ] ; then
565            ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
566          else
567            # copy only files so we can handle bsd4grml on its own
568            for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
569                test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
570            done
571
572            if [ -z "$NO_ADDONS_BSD4GRML" ] ; then
573               cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
574            fi
575          fi
576       fi
577
578       if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
579          cp -a ${TEMPLATE_DIRECTORY}/boot/grub  "$BUILD_OUTPUT"/boot/
580       fi
581       # make sure we have recent template files available, otherwise updating
582       # the strings like $GRML_NAME and $VERSION might be out of date
583       cp ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
584
585       if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
586          log "${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
587          eerror "${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
588          bailout 9
589       fi
590
591       [ -d "$BUILD_OUTPUT"/GRML ] || mkdir "$BUILD_OUTPUT"/GRML
592       cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/
593
594       # adjust boot splash information:
595       RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
596       RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
597       RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
598
599       sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/grml-version
600       sed -i "s/%DATE%/$ISO_DATE/"             "$BUILD_OUTPUT"/GRML/grml-version
601
602       sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/" "$BUILD_OUTPUT"/boot/isolinux/boot.msg
603       sed -i "s/%DATE%/$ISO_DATE/"             "$BUILD_OUTPUT"/boot/isolinux/boot.msg
604
605       sed -i "s/%GRML_NAME%/$SHORT_GRML_NAME/" "$BUILD_OUTPUT"/boot/isolinux/isolinux.cfg
606       sed -i "s/%GRML_NAME%/$SHORT_GRML_NAME/" "$BUILD_OUTPUT"/boot/isolinux/syslinux.cfg
607
608       sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/" "$BUILD_OUTPUT"/boot/isolinux/boot-beep.msg
609       sed -i "s/%DATE%/$ISO_DATE/"             "$BUILD_OUTPUT"/boot/isolinux/boot-beep.msg
610
611       sed -i "s/%VERSION%/$VERSION/"           "$BUILD_OUTPUT"/boot/grub/menu.lst
612       sed -i "s/%GRML_NAME%/$SHORT_GRML_NAME/" "$BUILD_OUTPUT"/boot/grub/menu.lst
613
614       sed -i "s/%VERSION%/$VERSION/"           "$BUILD_OUTPUT"/boot/grub/grub.cfg
615       sed -i "s/%GRML_NAME%/$SHORT_GRML_NAME/" "$BUILD_OUTPUT"/boot/grub/grub.cfg
616
617       # make sure the squashfs filename is set accordingly:
618       GRML_NAME_SQUASHFS="$GRML_NAME.squashfs"
619       sed -i "s/%GRML_NAME_SQUASHFS%/$GRML_NAME_SQUASHFS/" "$BUILD_OUTPUT"/boot/isolinux/isolinux.cfg
620       sed -i "s/%GRML_NAME_SQUASHFS%/$GRML_NAME_SQUASHFS/" "$BUILD_OUTPUT"/boot/isolinux/syslinux.cfg
621       sed -i "s/%GRML_NAME_SQUASHFS%/$GRML_NAME_SQUASHFS/" "$BUILD_OUTPUT"/boot/grub/menu.lst
622
623       GRML_NAME_SQUASHFS="$(cut_string 20 "$GRML_NAME_SQUASHFS")"
624       GRML_NAME_SQUASHFS="$(extend_string_end 20 "$GRML_NAME_SQUASHFS")"
625       sed -i "s/%GRML_NAME_SQUASHFS%/$GRML_NAME_SQUASHFS/" "$BUILD_OUTPUT"/boot/isolinux/f4
626       sed -i "s/%GRML_NAME_SQUASHFS%/$GRML_NAME_SQUASHFS/" "$BUILD_OUTPUT"/boot/isolinux/f5
627
628       # jump back to grub from bsd4grml:
629       if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
630          if [ -e "$BUILD_OUTPUT"/boot/grub/core.img ]; then
631             GRUB_VERSION=2
632          else
633             GRUB_VERSION=1
634          fi
635          if [ -e "$BUILD_OUTPUT"/boot/grub/stage2 ]; then
636             GRUB_LEGACY=stage2
637          else
638             GRUB_LEGACY=stage2_eltorito
639          fi
640
641          # why not ed(1)?
642          for file in "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 \
643                      "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.cfg; do
644              sed -i -e "s!%GRUB_VERSION%!$GRUB_VERSION!g" \
645                     -e "s!%GRUB_LEGACY%!$GRUB_LEGACY!g" "$file"
646          done
647       fi
648
649       # autostart for Windows:
650       if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
651          cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
652       fi
653
654       # windows-binaries:
655       if [ -n "$WINDOWS_BINARIES" ] ; then
656          if [ -f "$BUILD_OUTPUT"/windows/putty.exe ] ; then
657             log "$BUILD_OUTPUT/windows exists already, skipping stage 'WINDOWS_BINARIES'"
658             ewarn "$BUILD_OUTPUT/windows exists already, skipping stage 'WINDOWS_BINARIES'" ; eend 0
659          else
660             if ! [ -d "$BUILD_OUTPUT"/windows ] ; then
661                mkdir "$BUILD_OUTPUT"/windows
662                ( cd "$BUILD_OUTPUT"/windows
663                  for file in pageant plink pscp psftp putty puttygen ; do
664                     wget -O ${file}.exe ${WINDOWS_BINARIES}/${file}.exe
665                     md5sum ${file}.exe > ${file}.exe.md5
666                  done )
667             fi
668          fi
669       log "Finished execution of stage 'WINDOWS_BINARIES' [$(date)]"
670       einfo "Finished execution of stage 'WINDOWS_BINARIES'" ; eend 0
671       fi
672    einfo "Finished execution of stage 'boot'" ; eend 0
673    fi
674 # ppc:
675 elif [ "$ARCH" = powerpc ] ; then
676     ewarn 'Warning: formorer, it is your turn. :)'>&2
677 # unsuported:
678 else
679    eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
680 fi
681
682 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
683    log "$BUILD_OUTPUT/live exists already, skipping stage 'squashfs'"
684    ewarn "$BUILD_OUTPUT/live exists already, skipping stage 'squashfs'" ; eend 0
685 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
686    log "Skipping stage 'squashfs' as requested via option -q"
687    ewarn "Skipping stage 'squashfs' as requested via option -q" ; eend 0
688 else
689    [ -d "$BUILD_OUTPUT"/live ] || mkdir "$BUILD_OUTPUT"/live
690    # make sure we don't leave (even an empty) base.tgz:
691    [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
692
693    # make sure mksquashfs can handle the according option:
694    if [ -n "$SQUASHFS_ZLIB" ] ; then
695       mksquashfs --help 2>&1 | grep -q -- "$SQUASHFS_ZLIB" || SQUASHFS_ZLIB=''
696    fi
697
698    if echo "$SQUASHFS_OPTIONS" | grep -q -- "-nolzma" ; then
699       if ! mksquashfs --help 2>&1 | grep -q -- '-nolzma' ; then
700          ewarn "mksquashfs does NOT support the nolzma option, just using default zlib mode."
701          SQUASHFS_OPTIONS="$(echo $SQUASHFS_OPTIONS | sed 's/-nolzma//g')"
702          eend 0
703       fi
704    fi
705
706    if echo "$SQUASHFS_OPTIONS" | grep -q -- "-lzma" ; then
707       if ! mksquashfs --help 2>&1 | grep -q -- '-lzma' ; then
708          ewarn "mksquashfs does NOT support the lzma option, falling back to zlib mode."
709          SQUASHFS_OPTIONS="$(echo $SQUASHFS_OPTIONS | sed 's/-lzma//g')"
710          eend 0
711       fi
712    fi
713
714    # support exclusion of files via exclude-file:
715    if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
716       SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE"
717    fi
718
719    # get rid of unnecessary files when building grml-small for final release:
720    if echo "$CLASSES" | grep -q GRML_SMALL ; then
721       SQUASHFS_OPTIONS="$SQUASHFS_OUTPUT -e initrd.img* vmlinuz*"
722    fi
723
724    SQUASHFS_OUTPUT="$(mktemp -t grml-live.XXXXXX)"
725    log "mksquashfs $CHROOT_OUTPUT/* $BUILD_OUTPUT/live/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS $SQUASHFS_ZLIB"
726    if mksquashfs $CHROOT_OUTPUT/* $BUILD_OUTPUT/live/"${GRML_NAME}".squashfs \
727       -noappend $SQUASHFS_OPTIONS $SQUASHFS_ZLIB 2>"${SQUASHFS_OUTPUT}" ; then
728       echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/filesystem.module
729       log "Finished execution of stage 'squashfs' [$(date)]"
730       einfo "Finished execution of stage 'squashfs'" ; eend 0
731       rm -f "${SQUASHFS_OUTPUT}"
732    else
733       log "There was an error executing stage 'squashfs' [$(date)]:"
734       log "$(cat $SQUASHFS_OUTPUT)"
735       eerror "There was an error executing stage 'squashfs':" ; eend 1
736       cat "${SQUASHFS_OUTPUT}"
737       rm -f "${SQUASHFS_OUTPUT}"
738       bailout
739    fi
740 fi
741
742 # create md5sum file:
743 ( cd $BUILD_OUTPUT/GRML &&
744 find .. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
745 # }}}
746
747 # ISO_OUTPUT - mkisofs {{{
748 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
749 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
750
751 if [ "$BOOT_METHOD" = "isolinux" ] ; then
752    BOOT_FILE="boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
753 elif [ "$BOOT_METHOD" = "grub" ] ; then
754    BOOT_FILE="boot/grub/stage2_eltorito"
755 fi
756
757 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
758    log "$ISO_OUTPUT exists already, skipping stage 'iso build'"
759    ewarn "$ISO_OUTPUT exists already, skipping stage 'iso build'" ; eend 0
760 else
761    mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
762
763    CURRENT_DIR=$(pwd)
764    if cd "$BUILD_OUTPUT" ; then
765       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} ."
766       mkisofs -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
767               -l -r -J -no-emul-boot -boot-load-size 4 -boot-info-table    \
768               -b $BOOT_FILE -no-pad \
769               -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
770
771       # pad the output ISO to multiples of 256 KiB for partition table support
772       siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
773       cyls=$((siz / 512 / 32 / 16 + 1))         # C=$cyls H=16 S=32
774       siz=$((cyls * 16 * 32 * 512))             # size after padding
775       dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
776          of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
777
778       # support disabling hybrid ISO image
779       if [ "$HYBRID_METHOD" = "disable" ] ; then\
780          log "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
781          einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
782          eend 0
783       # use isohybrid only on request
784       elif [ "$HYBRID_METHOD" = "isohybrid" ] ; then
785          if ! which isohybrid >/dev/null 2>&1 ; then
786            bailout 12 "isohybrid binary not found - please install syslinux/syslinux-common"
787          else
788            log "Creating hybrid ISO file with isohybrid method"
789            einfo "Creating hybrid ISO file with isohybrid method"
790            isohybrid "${ISO_OUTPUT}/${ISO_NAME}"
791            eend $?
792          fi
793       # by default use our manifold boot method:
794       else
795          if ! [ -r boot/grub/core.img ] ; then
796            ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
797          else
798            log "Creating hybrid ISO file with manifold method"
799            einfo "Creating hybrid ISO file with manifold method"
800            echo 1 63 | \
801                mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 1 -p 0x83 -g $cyls:16:32 | \
802                cat - boot/grub/core.img | \
803                dd conv=notrunc of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
804            eend $?
805          fi
806       fi
807
808       # generate md5sum and sha1sum of ISO if we are using class 'RELEASE':
809       case $CLASSES in *RELEASE*)
810          [ "$RC" = 0 ] && \
811          (
812            if cd $ISO_OUTPUT ; then
813              md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
814              touch -r ${ISO_NAME} ${ISO_NAME}.md5
815              sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
816              touch -r ${ISO_NAME} ${ISO_NAME}.sha1
817            fi
818          )
819          ;;
820       esac
821
822       cd $CURRENT_DIR
823    fi
824
825    if [ "$RC" = 0 ] ; then
826       log "Finished execution of stage 'iso build' [$(date)]"
827       einfo "Finished execution of stage 'iso build'" ; eend 0
828    else
829       log "There was an error ($RC) executing stage 'iso build' [$(date)]"
830       eerror "There was an error executing stage 'iso build'" ; eend 1
831       bailout $RC
832    fi
833 fi
834 # }}}
835
836 # finalize {{{
837 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
838 einfo "Sucessfully finished execution of $PN [running ${SECONDS} seconds]" ; eend 0
839 log "Sucessfully finished execution of $PN [running ${SECONDS} seconds]"
840 bailout 0
841 # }}}
842
843 ## END OF FILE #################################################################
844 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=3