Update changelog and version number for pre-release 0.9.40.
[grml-live.git] / grml-live
1 #!/bin/bash
2 # Filename:      grml-live
3 # Purpose:       build process script for generating a (grml based) Linux Live-ISO
4 # Authors:       grml-team (grml.org),
5 #                (c) Michael Prokop <mika@grml.org>,
6 #                (c) Thorsten Glaser <tg@mirbsd.org>
7 # Bug-Reports:   see http://grml.org/bugs/
8 # License:       This file is licensed under the GPL v2 or any later version.
9 ################################################################################
10
11 # some misc and global stuff {{{
12 export LANG=C
13 export LC_ALL=C
14
15 # define function getfilesize before "set -e"
16 if stat --help >/dev/null 2>&1; then
17   getfilesize='stat -c %s'  # GNU stat
18 else
19   getfilesize='stat -f %z'  # BSD stat
20 fi
21
22 # exit on any error:
23 set -e
24
25 # global variables
26 GRML_LIVE_VERSION='0.9.40-pre1'
27 PN="$(basename $0)"
28 CMDLINE="$0 $@"
29 SOURCES_LIST_FILE='/etc/grml/fai/apt/sources.list'
30 ADDONS_LIST_FILE='/boot/isolinux/addons_list.cfg'
31 # }}}
32
33 # usage information {{{
34 usage()
35 {
36   echo "
37 $PN - build process script for generating a (grml based) Linux Live-ISO
38
39 Usage: $PN [options, see as follows]
40
41    -a <architecture>       architecture; available values: i386 and amd64
42    -b                      build the ISO without updating the chroot via FAI
43    -B                      build the ISO without touching the chroot (skips cleanup)
44    -c <classe[s]>          classes to be used for building the ISO via FAI
45    -C <configfile>         configuration file for grml-live
46    -d <date>               use specified date instead of build time as date of release
47    -F                      force execution without prompting
48    -g <grml_name>          set the grml flavour name
49    -h                      display short usage information and exit
50    -i <iso_name>           name of ISO
51    -I <src_directory>      directory which provides files that should become
52                            part of the chroot/ISO
53    -n                      skip generation of ISO
54    -o <output_directory>   main output directory of the build process
55    -q                      skip mksquashfs
56    -r <release_name>       release name
57    -s <suite>              Debian suite; values: etch, lenny, squeeze, sid
58    -t <template_directory> place of the templates
59    -u                      update existing chroot instead of rebuilding it from scratch
60    -v <version_number>     specify version number of the release
61    -V                      increase verbosity in the build process
62    -z                      use ZLIB instead of LZMA compression (depends on
63                            squashfs-tools version)
64
65 Usage examples:
66
67     $PN
68     $PN -c GRMLBASE,GRML_MEDIUM,I386 -o /dev/shm/grml
69     $PN -c GRMLBASE,GRML_SMALL,REMOVE_DOCS,I386 -g grml-small -v 1.0
70     $PN -c GRMLBASE,GRML_FULL,I386 -i grml_0.0-1.iso -v 0.0-1
71     $PN -c GRMLBASE,GRML_FULL,I386 -s sid -V -r 'grml-live rocks'
72
73 More details: man grml-live + /usr/share/doc/grml-live/grml-live.html
74               http://grml.org/grml-live/
75
76 Please send your bug reports and feedback to the grml-team: http://grml.org/bugs/
77 "
78 }
79
80 # make sure it's possible to get usage information without being
81 # root or actually executing the script
82 if [ "$1" = '-h' -o "$1" = '--help' ] ; then
83    usage
84    [ "$(id -u 2>/dev/null)" != 0 ] && echo "Please notice that this script requires root permissions."
85    exit 0
86 fi
87 # }}}
88
89 # some runtime checks {{{
90 # we need root permissions for the build-process:
91 if [ "$(id -u 2>/dev/null)" != 0 ] ; then
92    echo "Error: please run this script with uid 0 (root)." >&2
93    exit 1
94 fi
95
96 if [ -r /var/run/fai/FAI_INSTALLATION_IN_PROGRESS ] ; then
97    echo "/usr/sbin/fai already running or was aborted before.">&2
98    echo "You may remove /var/run/fai/FAI_INSTALLATION_IN_PROGRESS and try again.">&2
99    exit 1
100 fi
101
102 # see #449236
103 if [ -r /var/run/fai/fai_softupdate_is_running ] ; then
104    echo "/usr/sbin/fai softupdate already running or was aborted before.">&2
105    echo "You may remove /var/run/fai/fai_softupdate_is_running and try again.">&2
106    exit 1
107 fi
108 # }}}
109
110 # lsb-functions and configuration stuff {{{
111 # make sure they are not set by default
112 VERBOSE=''
113 FORCE=''
114 UPDATE=''
115 BUILD_ONLY=''
116 BUILD_DIRTY=''
117 HOSTNAME=''
118
119 if [ -r /etc/grml/lsb-functions ] ; then
120    . /etc/grml/lsb-functions
121 else
122    einfo()  { echo "  [*] $*" ;}
123    eerror() { echo "  [!] $*">&2 ;}
124    ewarn()  { echo "  [x] $*" ;}
125    eend()   { return 0 ;}
126    eindent()  { return 0 ;}
127    eoutdent() { return 0 ;}
128 fi
129
130 # source main configuration file:
131 LIVE_CONF=/etc/grml/grml-live.conf
132 . $LIVE_CONF
133 # }}}
134
135 # clean exit {{{
136 bailout() {
137   rm -f /var/run/fai/fai_softupdate_is_running \
138         /var/run/fai/FAI_INSTALLATION_IN_PROGRESS
139   [ -n "$SQUASHFS_STDERR" ]  && rm -rf "$SQUASHFS_STDERR"
140   [ -n "$MIRROR_DIRECTORY" ] && umount "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
141   [ -n "$1" ] && EXIT="$1" || EXIT="1"
142   [ -n "$2" ] && eerror "$2">&2
143   log "------------------------------------------------------------------------------"
144   exit "$EXIT"
145 }
146 trap bailout 1 2 3 3 6 9 14 15
147 # }}}
148
149 # log file stuff {{{
150 [ -n "$LOGFILE" ] || LOGFILE=/var/log/grml-live.log
151 touch $LOGFILE
152 chown root:adm $LOGFILE
153 chmod 664 $LOGFILE
154 # }}}
155
156 # some important functions {{{
157
158 # log output:
159 # usage: log "string to log"
160 log() { echo "$*" >> $LOGFILE ; }
161
162 # cut string at character number int = $1
163 # usage: cut_string 5 "1234567890" will output "12345"
164 cut_string() {
165   [ -n "$2" ] || return 1
166   echo "$2" | head -c "$1"; echo -ne "\n"
167 }
168
169 # prepend int = $1 spaces before string = $2
170 # usage: extend_string_begin 5 "123" will output "  123"
171 extend_string_begin() {
172   [ -n "$2" ] || return 1
173   local COUNT="$(echo $2 | wc -c)"
174   local FILL="$(expr $COUNT - $1)"
175   while [ "$FILL" -gt 1 ] ; do
176     echo -n " "
177     local FILL=$(expr $FILL - 1)
178   done
179   while [ "$FILL" -lt 1 ] ; do
180     echo -n " "
181     local FILL=$(expr $FILL + 1)
182   done
183   echo "$2" | head -c "$1"; echo -ne "\n"
184 }
185
186 # append int = $1 spaces to string = $2
187 # usage: extend_string_begin 5 "123" will output "123  "
188 extend_string_end() {
189   [ -n "$2" ] || return 1
190   echo -n "$2" | head -c "$1"
191   local COUNT="$(echo $2 | wc -c)"
192   local FILL="$(expr $COUNT - $1)"
193   while [ "$FILL" -gt 1 ] ; do
194     echo -n " "
195     local FILL=$(expr $FILL - 1)
196   done
197   while [ "$FILL" -lt 1 ] ; do
198     echo -n " "
199     local FILL=$(expr $FILL + 1)
200   done
201   echo -ne "\n"
202 }
203 # }}}
204
205 # read local (non-packaged) configuration {{{
206 LOCAL_CONFIG=/etc/grml/grml-live.local
207 if [ -r "$LOCAL_CONFIG" ] ; then
208    log "Sourcing $LOCAL_CONFIG"
209    . $LOCAL_CONFIG
210 else
211    log "No $LOCAL_CONFIG found, not sourcing it"
212    LOCAL_CONFIG=''
213 fi
214 # }}}
215
216 # command line parsing {{{
217 while getopts "a:C:c:d:g:i:I:o:r:s:t:v:bBFnquVz" opt; do
218   case "$opt" in
219     a) ARCH="$OPTARG" ;;
220     b) BUILD_ONLY=1 ;;
221     B) BUILD_DIRTY=1 ;;
222     c) CLASSES="$OPTARG" ;;
223     C) CONFIG="$OPTARG" ;;
224     d) DATE="$OPTARG" ;;
225     g) GRML_NAME="$OPTARG" ;;
226     i) ISO_NAME="$OPTARG" ;;
227     I) CHROOT_INSTALL="$OPTARG" ;;
228     n) SKIP_MKISOFS=1 ;;
229     o) OUTPUT="$OPTARG" ;;
230     q) SKIP_MKSQUASHFS=1 ;;
231     r) RELEASENAME="$OPTARG" ;;
232     s) SUITE="$OPTARG" ;;
233     t) TEMPLATE_DIRECTORY="$OPTARG";;
234     v) VERSION="$OPTARG" ;;
235     F) FORCE=1 ;;
236     u) UPDATE=1 ;;
237     V) VERBOSE="-v" ;;
238     z) SQUASHFS_ZLIB="-nolzma" ;;
239     ?) echo "invalid option -$OPTARG" >&2; bailout 1 ;;
240   esac
241 done
242 shift $(($OPTIND - 1))  # set ARGV to the first not parsed commandline parameter
243 # }}}
244
245 # assume sane defaults (if not set already) {{{
246 [ -n "$ARCH" ]             || ARCH="$(dpkg --print-architecture)"
247 [ -n "$BOOT_METHOD" ]      || BOOT_METHOD='isolinux'
248 [ -n "$BUILD_OUTPUT" ]     || BUILD_OUTPUT="$OUTPUT/grml_cd"
249 [ -n "$CHROOT_OUTPUT" ]    || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
250 [ -n "$CLASSES" ]          || CLASSES="GRMLBASE,GRML_MEDIUM,I386"
251 [ -n "$DATE" ]             || DATE="$(date +%Y-%m-%d)"
252 [ -n "$DISTRI_INFO" ]      || DISTRI_INFO='Grml - Live Linux for system administrators   '
253 [ -n "$DISTRI_NAME" ]      || DISTRI_NAME="grml"
254 [ -n "$DISTRI_SPLASH" ]    || DISTRI_SPLASH='grml.png'
255 [ -n "$FORCE_ISO_REBUILD" ] || FORCE_ISO_REBUILD="false"
256 [ -n "$GRML_FAI_CONFIG" ]  || GRML_FAI_CONFIG='/etc/grml/fai'
257 [ -n "$GRML_NAME" ]        || GRML_NAME='grml'
258 [ -n "$HOSTNAME" ]         || HOSTNAME='grml'
259 [ -n "$ISO_OUTPUT" ]       || ISO_OUTPUT="$OUTPUT/grml_isos"
260 [ -n "$NFSROOT_CONF" ]     || NFSROOT_CONF='/etc/grml/fai/make-fai-nfsroot.conf'
261 [ -n "$OUTPUT" ]           || OUTPUT='/grml/grml-live'
262 [ -n "$RELEASENAME" ]      || RELEASENAME='grml-live rocks'
263 [ -n "$SQUASHFS_EXCLUDES_FILE " ] || SQUASHFS_EXCLUDES_FILE='/etc/grml/fai/squashfs-excludes'
264 [ -n "$SUITE" ]            || SUITE='lenny'
265 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
266 [ -n "$USERNAME" ]         || USERNAME='grml'
267 [ -n "$VERSION" ]          || VERSION='0.0.1'
268 [ -n "$WINDOWS_BINARIES" ] || WINDOWS_BINARIES='http://the.earth.li/~sgtatham/putty/latest/x86/'
269 # }}}
270
271 # some misc checks before executing FAI {{{
272 [ -n "$CLASSES" ] || bailout 1 "Error: \$CLASSES unset, please set it in $LIVE_CONF or
273 specify it on the command line using the -c option."
274 [ -n "$OUTPUT" ] || bailout 1 "Error: \$OUTPUT unset, please set it in $LIVE_CONF or
275 specify it on the command line using the -o option."
276
277 # set subdirectories according to $OUTPUT:
278 CHROOT_OUTPUT="$OUTPUT/grml_chroot"
279 BUILD_OUTPUT="$OUTPUT/grml_cd"
280 ISO_OUTPUT="$OUTPUT/grml_isos"
281
282 # trim characters that are known to cause problems inside $GRML_NAME;
283 # for example isolinux does not like '-' inside the directory name
284 [ -n "$GRML_NAME" ] && export SHORT_NAME="$(echo $GRML_NAME | tr -d ',./;\- ')"
285
286 # export variables to have them available in fai scripts:
287 [ -n "$GRML_NAME" ]   && export GRML_NAME="$GRML_NAME"
288 [ -n "$RELEASENAME" ] && export RELEASENAME="$RELEASENAME"
289 # }}}
290
291 # ZERO_LOGFILE - check for backwards compatibility reasons {{{
292 # this was default behaviour until grml-live 0.9.34:
293 if [ -n "$ZERO_LOGFILE" ] ; then
294    PRESERVE_LOGFILE='' # make sure it's cleaned then
295    ewarn "Please consider disabling the \$ZERO_LOGFILE option as grml-live clears..."
296    ewarn "... the logfile $LOGFILE by default (unless \$PRESERVE_LOGFILE is set) nowadays."
297    eend 0
298 fi
299 # }}}
300
301 # ask user whether the setup is ok {{{
302 if [ -z "$FORCE" ] ; then
303    echo
304    echo "${PN} [${GRML_LIVE_VERSION}]: check your configuration (or use -F to force execution):"
305    echo
306    echo "  FAI classes:       $CLASSES"
307    [ -r "$LOCAL_CONFIG" ]        && echo "  Local config:      /etc/grml/grml-live.local"
308    [ -n "$CONFIG" ]              && echo "  Configuration:     $CONFIG"
309    echo "  main directory:    $OUTPUT"
310    [ -n "$CHROOT_OUTPUT" ]       && echo "  Chroot target:     $CHROOT_OUTPUT"
311    [ -n "$BUILD_OUTPUT" ]        && echo "  Build target:      $BUILD_OUTPUT"
312    [ -n "$ISO_OUTPUT" ]          && echo "  ISO target:        $ISO_OUTPUT"
313    [ -n "$GRML_NAME" ]           && echo "  Grml name:         $GRML_NAME"
314    [ -n "$RELEASENAME" ]         && echo "  Release name:      $RELEASENAME"
315    [ -n "$DATE" ]                && echo "  Build date:        $DATE"
316    [ -n "$VERSION" ]             && echo "  Grml version:      $VERSION"
317    [ -n "$SUITE" ]               && echo "  Debian suite:      $SUITE"
318    [ -n "$ARCH" ]                && echo "  Architecture:      $ARCH"
319    [ -n "$BOOT_METHOD" ]         && echo "  Boot method:       $BOOT_METHOD"
320    [ -n "$TEMPLATE_DIRECTORY" ]  && echo "  Template files:    $TEMPLATE_DIRECTORY"
321    [ -n "$CHROOT_INSTALL" ]      && echo "  Install files from directory to chroot:  $CHROOT_INSTALL"
322    [ -n "$BOOTID" ]              && echo "  Boot identifier:   $BOOTID"
323    [ -n "$NO_BOOTID" ]           && echo "  Skipping bootid feature."
324    [ -n "$DEFAULT_BOOTOPTIONS" ] && echo "  Adding default bootoptions: \"$DEFAULT_BOOTOPTIONS\""
325    [ -n "$FAI_ARGS" ]            && echo "  Additional arguments for FAI: $FAI_ARGS"
326    [ -n "$LOGFILE" ]             && echo "  Logging to file:   $LOGFILE"
327    [ -n "$SQUASHFS_ZLIB" ]       && echo "  Using ZLIB (instead of LZMA) compression."
328    [ -n "$SQUASHFS_OPTIONS" ]    && echo "  Using SQUASHFS_OPTIONS ${SQUASHFS_OPTIONS}"
329    [ -n "$VERBOSE" ]             && echo "  Using VERBOSE mode."
330    [ -n "$UPDATE" ]              && echo "  Executing UPDATE instead of fresh installation."
331    [ -n "$SKIP_MKSQUASHFS" ]     && echo "  Skipping creation of SQUASHFS file."
332    [ -n "$SKIP_MKISOFS" ]        && echo "  Skipping creation of ISO file."
333    [ -n "$BUILD_ONLY" ]          && echo "  Executing BUILD_ONLY instead of fresh installation or UPDATE."
334    [ -n "$BUILD_DIRTY" ]         && echo "  Executing BUILD_DIRTY to leave chroot untouched."
335    echo
336    echo -n "Is this ok for you? [y/N] "
337    read a
338    if ! [ "$a" = 'y' -o "$a" = 'Y' ] ; then
339       bailout 1 "Exiting as requested."
340    fi
341    echo
342 fi
343 # }}}
344
345 # clean/zero/remove logfiles {{{
346
347 if [ -n "$PRESERVE_LOGFILE" ] ; then
348    echo "Preserving logfile $LOGFILE as requested via \$PRESERVE_LOGFILE"
349 else
350    # make sure it is empty (as it is e.g. appended to grml-live-db)
351    echo -n > $LOGFILE
352 fi
353
354 if [ -n "$ZERO_FAI_LOGFILE" ] ; then
355    if [ -d /var/log/fai/"$HOSTNAME" ] ; then
356       rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last)"
357       rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-dirinstall)"
358       rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-softupdate)"
359       rm -f /var/log/fai/"$HOSTNAME"/last \
360             /var/log/fai/"$HOSTNAME"/last-dirinstall \
361             /var/log/fai/"$HOSTNAME"/last-softupdate
362    fi
363 fi
364 # }}}
365
366 # source config and startup {{{
367 if [ -n "$CONFIG" ] ; then
368    if ! [ -f "$CONFIG" ] ; then
369       log    "Error: $CONFIG could not be read. Exiting. [$(date)]"
370       eerror "Error: $CONFIG could not be read. Exiting." ; eend 1
371       bailout 1
372    else
373       log "Sourcing $CONFIG"
374       . $CONFIG
375    fi
376 fi
377
378 start_seconds=$(cut -d . -f 1 /proc/uptime)
379 log "------------------------------------------------------------------------------"
380 log "Starting grml-live [${GRML_LIVE_VERSION}] run on $(date)"
381 log "Executed grml-live command line:"
382 log "$CMDLINE"
383
384 einfo "Logging actions to logfile $LOGFILE"
385 # }}}
386
387 # on-the-fly configuration {{{
388 if [ -n "$MIRROR_DIRECTORY" ] ; then
389    if ! [ -d "$MIRROR_DIRECTORY/debian" ] ; then
390       log    "Error: $MIRROR_DIRECTORY/debian does not seem to exist. Exiting. [$(date)]"
391       eerror "Error: $MIRROR_DIRECTORY/debian does not seem to exist. Exiting." ; eend 1
392       bailout 1
393    fi
394    cat > "$SOURCES_LIST_FILE" << EOF
395 # NOTE: This file is *NOT* meant for manual customisation! This file is
396 # modified by grml-live and any changes might be overriden.
397 # You might consider using GRML_LIVE_SOURCES in /etc/grml/grml-live.conf*
398 # or FAI's fcopy command with /etc/grml/fai/config/files instead!
399 EOF
400    echo "$MIRROR_SOURCES" >> "$SOURCES_LIST_FILE"
401    if [ -n "$GRML_LIVE_SOURCES" ] ; then
402       echo "$GRML_LIVE_SOURCES" >> "$SOURCES_LIST_FILE"
403    fi
404 elif [ -n "$GRML_LIVE_SOURCES" ] ; then
405    cat > "$SOURCES_LIST_FILE" << EOF
406 # NOTE: This file is *NOT* meant for manual customisation! This file is
407 # modified by grml-live and any changes might be overriden.
408 # You might consider using GRML_LIVE_SOURCES in /etc/grml/grml-live.conf*
409 # or FAI's fcopy command with /etc/grml/fai/config/files instead!
410 EOF
411    echo "$GRML_LIVE_SOURCES" >> "$SOURCES_LIST_FILE"
412 fi
413
414 if [ -n "$FAI_DEBOOTSTRAP" ] ; then
415    sed "s#^FAI_DEBOOTSTRAP=.*#FAI_DEBOOTSTRAP=\"$FAI_DEBOOTSTRAP\"#" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
416 fi
417
418 # does this suck? YES!
419 # /usr/share/debootstrap/scripts/unstable does not exist, instead use 'sid':
420 case $SUITE in
421    unstable) SUITE='sid' ;;
422    # make sure that we *NEVER* write any broken suite name to sources.list,
423    # otherwise we won't be able to adjust it one next (correct) execution
424    stable)   ;;
425    testing)  ;;
426    etch)     ;;
427    lenny)    ;;
428    squeeze)  ;;
429    sid)      ;;
430    *) echo "Sorry, $SUITE is not a valid Debian suite, exiting.">&2; bailout 1 ;;
431 esac
432
433 DIST=" etch\| stable\| lenny\| squeeze\| testing\| sid\| unstable"
434 sed "s/\(^deb .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/" "$SOURCES_LIST_FILE" | sponge "$SOURCES_LIST_FILE"
435 for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" ; do
436     if [ -n "$file" ] ; then
437        sed "s/^SUITE=.*/SUITE=\"$SUITE\"/" $file | sponge $file
438        sed "s/\(^deb .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/" "$file" | sponge "$file"
439     fi
440 done
441
442 # notice: activate grml-live pool only if we are building against unstable:
443 if grep -qe unstable -qe sid "$SOURCES_LIST_FILE" ; then
444    grep -q 'grml-live.*main' "$SOURCES_LIST_FILE" || \
445    grep grml-stable "$SOURCES_LIST_FILE" | \
446         sed 's/grml-stable/grml-live/' >> "$SOURCES_LIST_FILE"
447 else
448    grep -q 'grml-live.*main' "$SOURCES_LIST_FILE" && \
449    sed 's/.*grml-live.*/# removed grml-live repository/' "$SOURCES_LIST_FILE" | sponge "$SOURCES_LIST_FILE"
450 fi
451
452 for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" "$NFSROOT_CONF" ; do
453     if [ -n "$file" ] ; then
454        sed "s|^FAI_DEBOOTSTRAP=\"[a-z]* |FAI_DEBOOTSTRAP=\"$SUITE |" "$file" | sponge "$file"
455     fi
456 done
457
458 # validate whether the specified architecture class matches the
459 # architecture (option), otherwise installation of kernel will fail
460 if echo $CLASSES | grep -qi i386 ; then
461    if ! [[ "$ARCH" == "i386" ]] ; then
462       log    "Error: You specified the I386 class but are trying to build something else (AMD64?)."
463       eerror "Error: You specified the I386 class but are trying to build something else (AMD64?)."
464       eerror "Tip:   Either invoke grml-live with '-a i386' or adjust the architecture class. Exiting."
465       eend 1
466       bailout
467    fi
468 elif echo $CLASSES | grep -qi amd64 ; then
469    if ! [[ "$ARCH" == "amd64" ]] ; then
470       log    "Error: You specified the AMD64 class but are trying to build something else (I386?)."
471       eerror "Error: You specified the AMD64 class but are trying to build something else (I386?)."
472       eerror "Tip:   Either invoke grml-live with '-a amd64' or adjust the architecture class. Exiting."
473       eend 1
474       bailout
475    fi
476 fi
477
478 if grep -q -- 'FAI_DEBOOTSTRAP_OPTS.*--arch' "$NFSROOT_CONF" ; then
479    sed "s/--arch [a-z0-9]* /--arch $ARCH /" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
480 else
481    sed "s|^FAI_DEBOOTSTRAP_OPTS=\"\(.*\)|FAI_DEBOOTSTRAP_OPTS=\"--arch $ARCH \1|" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
482 fi
483 # }}}
484
485 # CHROOT_OUTPUT - execute FAI {{{
486 if [ -n "$BUILD_DIRTY" ]; then
487    log   "Skipping stage 'fai' as requested via option -B"
488    ewarn "Skipping stage 'fai' as requested via option -B" ; eend 0
489 else
490    [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
491
492    # provide inform fai about the ISO we build
493    [ -d "$CHROOT_OUTPUT/etc/" ] || mkdir -p "$CHROOT_OUTPUT/etc/"
494    echo '# This file has been generated by grml-live.' > "$CHROOT_OUTPUT/etc/grml_live_version"
495    [ -n "$GRML_LIVE_VERSION" ] && echo "GRML_LIVE_VERSION=$GRML_LIVE_VERSION" >> "$CHROOT_OUTPUT/etc/grml_live_version"
496    [ -n "$SUITE" ] && echo "SUITE=$SUITE" >> "$CHROOT_OUTPUT/etc/grml_live_version"
497
498    if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
499       FAI_ACTION=softupdate
500    else
501       FAI_ACTION=dirinstall
502    fi
503
504    if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
505       if ! [ -r "$CHROOT_OUTPUT/etc/debian_version" ] ; then
506          log    "Error: does not look like you have a working chroot. Updating/building not possible."
507          eerror "Error: does not look like you have a working chroot. Updating/building not possible. (Drop -u/-b option?)"
508          eend 1
509          bailout 20
510       fi
511    fi
512
513    if [ -d "$CHROOT_OUTPUT/bin" -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
514       log   "Skiping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already."
515       ewarn "Skiping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already." ; eend 0
516    else
517       mkdir -p "$CHROOT_OUTPUT" || bailout 5 "Problem with creating $CHROOT_OUTPUT for FAI"
518
519       if [ -n "${MIRROR_DIRECTORY}" ] ; then
520          mkdir -p "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
521          mount --bind "${MIRROR_DIRECTORY}" "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
522       fi
523
524       log "Executed FAI command line:"
525       log "BUILD_ONLY=$BUILD_ONLY fai $VERBOSE -C $GRML_FAI_CONFIG -c$CLASSES -u $HOSTNAME $FAI_ACTION $CHROOT_OUTPUT $FAI_ARGS"
526       BUILD_ONLY="$BUILD_ONLY" fai $VERBOSE -C "$GRML_FAI_CONFIG" -c"$CLASSES" -u \
527       "$HOSTNAME" $FAI_ACTION "$CHROOT_OUTPUT" $FAI_ARGS | tee -a $LOGFILE
528       RC="$PIPESTATUS" # notice: bash-only
529
530       FORCE_ISO_REBUILD=true
531
532       if [ "$RC" != 0 ] ; then
533          log    "Error: critical error while executing fai [exit code ${RC}]. Exiting."
534          eerror "Error: critical error while executing fai [exit code ${RC}]. Exiting." ; eend 1
535          bailout 1
536       else
537          log "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
538          echo "$GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]" > $CHROOT_OUTPUT/etc/grml_version
539          chmod 644 $CHROOT_OUTPUT/etc/grml_version
540          einfo "Rebuilding initramfs"
541          # make sure new /etc/grml_version reaches the initramfs:
542          # chroot $CHROOT_OUTPUT update-initramfs -u -t => might break when using kernel-package :(
543          chroot $CHROOT_OUTPUT update-initramfs -u -k all
544          eend $?
545       fi
546
547       # Remove all FAI logs from chroot if class RELEASE is used:
548       if [ -f "$CHROOT_OUTPUT"/etc/grml_fai_release ] ; then
549          rm -rf "$CHROOT_OUTPUT"/var/log/fai/*
550       fi
551
552       # make sure we don't leave any mounts - FAI doesn't remove them always
553       umount $CHROOT_OUTPUT/proc 2>/dev/null || /bin/true
554       umount $CHROOT_OUTPUT/sys  2>/dev/null || /bin/true
555       umount $CHROOT_OUTPUT/dev/pts 2>/dev/null || /bin/true
556       umount $CHROOT_OUTPUT/dev 2>/dev/null || /bin/true
557
558       [ -n "$MIRROR_DIRECTORY" ] && umount "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
559
560       # notice: 'fai dirinstall' does not seem to exit appropriate, so:
561       ERROR=''
562       CHECKLOG=/var/log/fai/$HOSTNAME/last
563       if [ -r "$CHECKLOG/software.log" ] ; then
564          # 1 errors during executing of commands
565          grep 'dpkg: error processing' $CHECKLOG/software.log >> $LOGFILE && ERROR=1
566          grep 'E: Method http has died unexpectedly!' $CHECKLOG/software.log >> $LOGFILE && ERROR=2
567          grep 'ERROR: chroot' $CHECKLOG/software.log >> $LOGFILE && ERROR=3
568          grep 'E: Failed to fetch' $CHECKLOG/software.log >> $LOGFILE && ERROR=4
569          grep 'Unable to write mmap - msync (28 No space left on device)' $CHECKLOG/software.log >> $LOGFILE && ERROR=5
570       fi
571
572       if [ -r "$CHECKLOG/shell.log" ] ; then
573          grep 'FAILED with exit code' $CHECKLOG/shell.log >> $LOGFILE && ERROR=2
574       fi
575
576       if [ -n "$ERROR" ] ; then
577          log    "Error: there was a critical error [${ERROR}] during execution of stage 'fai dirinstall' [$(date)]"
578          eerror "Error: there was a critical error during execution of stage 'fai dirinstall'"
579          eerror "Note:  check out ${CHECKLOG}/ for details. [exit ${ERROR}]"
580          eend 1
581          bailout 1
582       else
583          log "Finished execution of stage 'fai dirinstall' [$(date)]"
584          einfo "Finished execution of stage 'fai dirinstall'"
585       fi
586
587       einfo "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
588       log   "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
589       eend 0
590    fi
591 fi # BUILD_DIRTY?
592 # }}}
593
594 # package validator {{{
595 CHECKLOG=/var/log/fai/$HOSTNAME/last
596 # package validator
597 if [ -r "$CHECKLOG/package_errors.log" ] && grep -q '[a-z]' "$CHECKLOG/package_errors.log" ; then
598
599    if [ -n "$EXIT_ON_MISSING_PACKAGES" -a -z "$BUILD_DIRTY" ] ; then
600       eerror "The following packages were requested for installation but could not be processed:"
601       cat $CHECKLOG/package_errors.log
602       eerror "... exiting as requested via \$EXIT_ON_MISSING_PACKAGES."
603       eend 1
604       bailout 13
605    else
606       ewarn "The following packages were requested for installation but could not be processed:"
607       cat $CHECKLOG/package_errors.log
608       eend 0
609    fi
610 fi
611 # }}}
612
613 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
614 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
615 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
616
617 # i386:
618 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
619    if [ -d "$BUILD_OUTPUT"/boot/isolinux -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
620       log   "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already."
621       ewarn "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already." ; eend 0
622    else
623       # booting stuff:
624       [ -d "$BUILD_OUTPUT"/boot/isolinux ] || mkdir -p "$BUILD_OUTPUT"/boot/isolinux
625       [ -d "$BUILD_OUTPUT"/boot/"${SHORT_NAME}" ] || mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"
626
627       if [ -z "$NO_ADDONS" ] ; then
628          [ -d "$BUILD_OUTPUT"/boot/addons   ] || mkdir -p "$BUILD_OUTPUT"/boot/addons
629          if [ -r "$TEMPLATE_DIRECTORY"/boot/addons/memtest ] ; then
630             log "Installing $TEMPLATE_DIRECTORY/boot/addons/memtest"
631             cp "$TEMPLATE_DIRECTORY"/boot/addons/memtest "$BUILD_OUTPUT"/boot/addons/memtest
632          elif [ -r /boot/memtest86+.bin ] ; then
633             log "Installing /boot/memtest86+.bin"
634             cp /boot/memtest86+.bin "$BUILD_OUTPUT"/boot/addons/memtest
635          else
636             ewarn "No memtest binary found (either install package grml-live-addons or memtest86+), skipping."
637             log "No memtest binary found (either install package grml-live-addons or memtest86+), skipping."
638             eend 0
639          fi
640       fi
641
642       # if we don't have an initrd we a) can't boot and b) there was an error
643       # during build, so check for the file:
644       INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
645       if [ -n "$INITRD" ] ; then
646          cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/initrd.gz
647          find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
648       else
649          log    "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
650          eerror "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
651          bailout 10
652       fi
653
654       KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
655       if [ -n "$KERNEL_IMAGE" ] ; then
656          cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/linux26
657       else
658          log    "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
659          eerror "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
660          bailout 11
661       fi
662
663       [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
664       if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
665          log    "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
666          eerror "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
667          bailout 8
668       fi
669
670       # *always* copy files to output directory so the variables
671       # get adjusted according to the build
672       cp ${TEMPLATE_DIRECTORY}/boot/isolinux/*  "$BUILD_OUTPUT"/boot/isolinux/
673
674       if [ -n "$NO_ADDONS" ] ; then
675          log   "Skipping installation of boot addons as requested via \$NO_ADDONS."
676          einfo "Skipping installation of boot addons as requested via \$NO_ADDONS."; eend 0
677       else
678          if ! [ -d "$TEMPLATE_DIRECTORY"/boot/addons ] ; then
679            log   "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)"
680            ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
681          else
682            # copy only files so we can handle bsd4grml on its own
683            for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
684              test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
685            done
686
687            if [ -n "$NO_ADDONS_BSD4GRML" ] ; then
688               log   "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."
689               einfo "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."; eend 0
690            else
691               if [ -d "$TEMPLATE_DIRECTORY"/boot/addons/bsd4grml ] ; then
692                 cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
693               else
694                 log   "bsd4grml addon not found, skipping therefore."
695                 ewarn "bsd4grml addon not found, skipping therefore." ; eend 0
696               fi
697            fi
698
699          fi # no "$TEMPLATE_DIRECTORY"/boot/addons
700       fi # NO_ADDONS
701
702       if ! [ -d ${TEMPLATE_DIRECTORY}/boot/grub ] ; then
703          log   "grub templates do not exist, skipping therefore."
704          ewarn "grub templates do not exist, skipping therefore." ; eend 0
705       else
706          if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
707             cp -a ${TEMPLATE_DIRECTORY}/boot/grub  "$BUILD_OUTPUT"/boot/
708          fi
709
710          # make sure we have recent template files available, otherwise updating
711          # the strings like $GRML_NAME and $VERSION might be out of date
712          cp ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
713       fi
714
715       if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
716          log    "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
717          eerror "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
718          bailout 9
719       fi
720
721       [ -d "$BUILD_OUTPUT"/GRML ] || mkdir "$BUILD_OUTPUT"/GRML
722       cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/
723
724       # adjust boot splash information:
725       RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
726       RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
727       RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
728
729       if [ -r "$BUILD_OUTPUT"/GRML/grml-version ] ; then
730          sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/grml-version
731          sed -i "s/%DATE%/$DATE/"                                      "$BUILD_OUTPUT"/GRML/grml-version
732       fi
733
734       # make sure the squashfs filename is set accordingly:
735       SQUASHFS_NAME="$GRML_NAME.squashfs"
736
737       if [ -n "$NO_BOOTID" ] ; then
738          log   'Skipping bootid feature as requested via $NO_BOOTID.'
739          einfo 'Skipping bootid feature as requested via $NO_BOOTID.'
740       else
741          [ -n "$BOOTID" ] || BOOTID="$(echo ${GRML_NAME}${VERSION} | tr -d ',./;\- ')"
742          [ -d "$BUILD_OUTPUT"/conf ] || mkdir "$BUILD_OUTPUT"/conf
743          einfo "Generating /conf/bootid.txt with entry ${BOOTID}."
744          log   "Generating /conf/bootid.txt with entry ${BOOTID}."
745          echo "$BOOTID" > "$BUILD_OUTPUT"/conf/bootid.txt
746          eend $?
747       fi
748
749       # adjust all variables in the templates with the according distribution information
750       for file in "${BUILD_OUTPUT}"/boot/isolinux/*.cfg "${BUILD_OUTPUT}"/boot/isolinux/*.msg \
751                   "${BUILD_OUTPUT}"/boot/grub/* ; do
752         if [ -r "${file}" ] ; then
753           sed -i "s/%ARCH%/$ARCH/g"                    "${file}"
754           sed -i "s/%DATE%/$DATE/g"                    "${file}"
755           sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/g"      "${file}"
756           sed -i "s/%DISTRI_NAME%/$DISTRI_NAME/g"      "${file}"
757           sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/g"  "${file}"
758           sed -i "s/%GRML_NAME%/$GRML_NAME/g"          "${file}"
759           sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/g"  "${file}"
760           sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/g"    "${file}"
761           sed -i "s/%SHORT_NAME%/$SHORT_NAME/g"        "${file}"
762           sed -i "s/%VERSION%/$VERSION/g"              "${file}"
763
764           [ -n "$DEFAULT_BOOTOPTIONS" ] && sed -i "s/ boot=live/ boot=live $DEFAULT_BOOTOPTIONS/"  "${file}"
765
766           if [ -n "$NO_BOOTID" ] ; then
767              sed -i "s/ bootid=%BOOTID%//g" "${file}" # drop bootid bootoption
768           else
769              sed -i "s/%BOOTID%/$BOOTID/g" "${file}" # adjust bootid=... argument
770           fi
771         fi
772       done
773
774       # adjust bootsplash accordingly but make sure the string has the according lenght
775       SQUASHFS_NAME="$(cut_string 20 "$SQUASHFS_NAME")"
776       SQUASHFS_NAME="$(extend_string_end 20 "$SQUASHFS_NAME")"
777       for file in f4 f5 ; do
778          if [ -r "${BUILD_OUTPUT}/boot/isolinux/${file}" ] ; then
779             sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
780             sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
781          fi
782       done
783
784       # generate addon list
785       rm "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
786       for name in $(ls "${BUILD_OUTPUT}"/boot/isolinux/addon_*.cfg) ; do
787         include_name=$(basename "$name")
788         echo "include $include_name"  >> "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
789       done
790
791       if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
792          log "including grmlmain.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
793          echo "include grmlmain.cfg"    >  "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
794          echo "include default.cfg"     >  "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
795          echo "include menuoptions.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
796          echo "include grml.cfg"        >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
797
798          for f in "${BUILD_OUTPUT}"/boot/isolinux/submenu*.cfg ; do
799            echo "include $(basename $f)"     >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
800          done
801
802          echo "include options.cfg"     >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
803          if [ ! -n "$NO_ADDONS" ] ; then
804            echo "include addons.cfg"    >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
805          fi
806          echo "include isoprompt.cfg"   >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
807          echo "include hd.cfg"          >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
808          echo "include hidden.cfg"      >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
809       else # assume we are building a custom distribution:
810          log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
811          einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
812          if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
813            log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
814            eindent
815            einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
816            eoutdent
817            eend $?
818         else
819            log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
820            echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
821            [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
822          fi
823       fi
824
825       # use old style console based isolinux method only if requested:
826       if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
827          log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
828          einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
829          if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
830            einfo "include for console.cfg already foud, nothing to do."
831            eend 0
832          else
833            log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
834            einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
835            echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
836            eend $?
837          fi
838       else
839          log 'Using graphical boot menu.'
840          if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
841            log "include for vesamenu.cfg already foud, nothing to do."
842          else
843            log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
844            echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
845          fi
846       fi
847
848       # jump back to grub from bsd4grml (/boot/grub/stage2):
849       GRUB_LEGACY=stage2
850
851       if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
852          if [ -e "$BUILD_OUTPUT"/boot/grub/core.img ]; then
853             GRUB_VERSION=2
854          else
855             GRUB_VERSION=1
856          fi
857
858          for file in "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 \
859                      "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.cfg \
860                      "$BUILD_OUTPUT"/boot/isolinux/*.cfg \
861                      "$BUILD_OUTPUT"/boot/grub/grub.cfg \
862                      "$BUILD_OUTPUT"/boot/grub/menu.lst ; do
863              if [ -e "$file" ] ; then
864                sed -i -e "s!%GRUB_VERSION%!$GRUB_VERSION!g" \
865                       -e "s!%GRUB_LEGACY%!$GRUB_LEGACY!g" "$file"
866              fi
867          done
868
869          sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
870       fi
871
872       if [ -e "$BUILD_OUTPUT"/boot/grub/$GRUB_LEGACY ]; then
873          sed -i "s/%GRUB_LEGACY%/$GRUB_LEGACY/g" "$BUILD_OUTPUT"/boot/grub/menu.lst
874          sed -i "s/%GRUB_LEGACY%/$GRUB_LEGACY/g" "$BUILD_OUTPUT"/boot/grub/grub.cfg
875       elif [ -e "$BUILD_OUTPUT"/boot/grub/menu.lst -a -e "$BUILD_OUTPUT"/boot/grub/grub.cfg ] ; then
876          sed -i "/%GRUB_LEGACY%/d" "$BUILD_OUTPUT"/boot/grub/menu.lst
877          sed -i "/%GRUB_LEGACY%/d" "$BUILD_OUTPUT"/boot/grub/grub.cfg
878       fi
879
880       DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot
881       if ! [ -r "$DPKG_LIST" ] ; then
882          ewarn "$DPKG_LIST could not be read, ignoring to store package information on ISO therefore."
883       else
884          einfo "Storing package list information as /GRML/${GRML_NAME}-packages.txt on ISO."
885          cp "$DPKG_LIST" "${BUILD_OUTPUT}/GRML/${GRML_NAME}-packages.txt"
886          eend $?
887       fi
888
889       # autostart for Windows:
890       if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
891          cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
892       fi
893
894       # windows-binaries:
895       if [ -n "$NO_WINDOWS_BINARIES" ] ; then
896          log   "Skipping download of windows binaries as requested via \$NO_WINDOWS_BINARIES."
897          einfo "Skipping download of windows binaries as requested via \$NO_WINDOWS_BINARIES."
898          eend 0
899       else
900          if [ -f "$BUILD_OUTPUT"/windows/putty.exe ] ; then
901             log   "Skipping stage 'WINDOWS_BINARIES' as $BUILD_OUTPUT/windows exists already."
902             ewarn "Skipping stage 'WINDOWS_BINARIES' as $BUILD_OUTPUT/windows exists already." ; eend 0
903          else
904             if ! [ -d "$BUILD_OUTPUT"/windows ] ; then
905                mkdir "$BUILD_OUTPUT"/windows
906                ( cd "$BUILD_OUTPUT"/windows
907                  for file in pageant plink pscp psftp putty puttygen ; do
908                     wget -O ${file}.exe ${WINDOWS_BINARIES}/${file}.exe
909                     md5sum ${file}.exe > ${file}.exe.md5
910                  done )
911             fi
912
913             log "Finished execution of stage 'WINDOWS_BINARIES' [$(date)]"
914             einfo "Finished execution of stage 'WINDOWS_BINARIES'" ; eend 0
915          fi
916       fi
917
918    FORCE_ISO_REBUILD=true
919    einfo "Finished execution of stage 'boot'" ; eend 0
920    fi
921 else
922    log    'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
923    eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
924    bailout
925 fi
926
927 # support installation of local files into the chroot/ISO
928 if [ -n "$CHROOT_INSTALL" ] ; then
929   if ! [ -d "$CHROOT_INSTALL" ] ; then
930      log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
931      ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
932   else
933      log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
934      einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
935      rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
936      eend $?
937      einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
938      FORCE_ISO_REBUILD=true
939   fi
940 fi
941
942 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
943    log   "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
944    ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
945 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
946    log   "Skipping stage 'squashfs' as requested via option -q"
947    ewarn "Skipping stage 'squashfs' as requested via option -q" ; eend 0
948 else
949    [ -d "$BUILD_OUTPUT"/live ] || mkdir "$BUILD_OUTPUT"/live
950    # make sure we don't leave (even an empty) base.tgz:
951    [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
952
953    # $SQUASHFS_BINARY is specified in the configuration:
954    if [ -n "$SQUASHFS_BINARY" ] ; then
955       if ! which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
956          log    "Error: specified mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
957          eerror "Error: specified mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
958          bailout
959       fi
960    else # no $SQUASHFS_BINARY configured, let's find the according binary:
961       # Note: this is ALL for backward compatibility and yes: it's serious PITA.
962       # We'll definitely drop this once people build >2.6.28-grml* only and
963       # the squashfs-tools vs. squashfs-lzma-tools + zlib vs. lzma situation
964       # is settling...
965
966       # assume the safe default if mksquashfs-lzma isn't present:
967       if ! which mksquashfs-lzma >/dev/null 2>&1 ; then
968          SQUASHFS_BINARY='mksquashfs'
969       else # mksquashfs-lzma is available since squashfs-lzma-tools 4.0:
970          # if the user wants to use zlib then don't use mksquashfs-lzma:
971          if echo "$SQUASHFS_OPTIONS" | grep -q -- "-nolzma" || [ -n "$SQUASHFS_ZLIB" ] ; then
972             SQUASHFS_BINARY='mksquashfs'
973          else # neither -nolzma nor -z and mksquashfs-lzma is available:
974             SQUASHFS_BINARY='mksquashfs-lzma'
975
976             # backwards compatibility: someone has squashfs-lzma-tools >=4 installed but
977             # 1) doesn't use -nolzma in $SQUASHFS_OPTIONS or the grml-live's -z option *and*
978             # 2) builds against kernel version <=2.6.28-grml[64]
979             if ls $CHROOT_OUTPUT/boot/vmlinuz* >/dev/null 2>&1 ; then
980                KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
981
982                case $KERNEL_IMAGE in
983                   *vmlinuz-2.6.28-grml*|*vmlinuz-2.6.26-grml*|*vmlinuz-2.6.23-grml*)
984                   log   "You seem to be building a system with squashfs file format 3 using squashfs-lzma-tools >=4."
985                   ewarn "You seem to be building a system with squashfs file format 3 using squashfs-lzma-tools >=4."
986                   ewarn "|-> Consider installing squashfs-lzma-tools 3.3-1 for support of file format version 3."
987                   ewarn "|-> Trying the mksquashfs binary instead of mksquashfs-lzma (though this might fail)."
988                   ewarn "\`-> Visit http://grml.org/grml-live/#current_state for further details if building fails."
989                   eend 0
990                   SQUASHFS_BINARY='mksquashfs'
991                   ;;
992                esac
993             fi
994
995             # if we still want to use mksquashfs-lzma then let's choose
996             # blocksize 256k as this gives best result with regards to time + comopression
997             [[ "$SQUASHFS_BINARY" == "mksquashfs-lzma" ]] && SQUASHFS_OPTIONS="-b 256k -lzma"
998          fi
999
1000       fi
1001    fi
1002
1003    # make sure mksquashfs can handle the according option:
1004    if [ -n "$SQUASHFS_ZLIB" ] ; then
1005       $SQUASHFS_BINARY --help 2>&1 | grep -q -- "$SQUASHFS_ZLIB" || SQUASHFS_ZLIB=''
1006    fi
1007
1008    # make sure to drop the -nolzma option if it's not available:
1009    if echo "$SQUASHFS_OPTIONS" | grep -q -- "-nolzma" ; then
1010       if ! $SQUASHFS_BINARY --help 2>&1 | grep -q -- '-nolzma' ; then
1011          log   "The $SQUASHFS_BINARY binary does NOT support the nolzma option, dropping it and using default mode."
1012          ewarn "The $SQUASHFS_BINARY binary does NOT support the nolzma option, dropping it and using default mode."
1013          SQUASHFS_OPTIONS="$(echo $SQUASHFS_OPTIONS | sed 's/-nolzma//g')"
1014          eend 0
1015       fi
1016    fi
1017
1018    # make sure to drop the -lzma option if it's not available:
1019    if echo "$SQUASHFS_OPTIONS" | grep -q -- "-lzma" ; then
1020       if ! $SQUASHFS_BINARY --help 2>&1 | grep -q -- '-lzma' ; then
1021          log   "The $SQUASHFS_BINARY binary does NOT support the lzma option, dropping it and using default mode."
1022          ewarn "The $SQUASHFS_BINARY binary does NOT support the lzma option, dropping it and using default mode."
1023          SQUASHFS_OPTIONS="$(echo $SQUASHFS_OPTIONS | sed 's/-lzma//g')"
1024          eend 0
1025       fi
1026    fi
1027
1028    # support exclusion of files via exclude-file:
1029    if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
1030       SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE"
1031    fi
1032
1033    # get rid of unnecessary files when building grml-small for final release:
1034    if echo "$CLASSES" | grep -q GRML_SMALL ; then
1035       SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
1036    fi
1037
1038    # check whether we have the according binary available:
1039    if ! which $SQUASHFS_BINARY >/dev/null 2>&1 ; then
1040       log    "Error: mksquashfs binary (${SQUASHFS_BINARY}) could not be found. Exiting."
1041       eerror "Error: mksquashfs binary (${SQUASHFS_BINARY}) could not be found. Exiting."
1042       eerror "|-> Make sure to install either squashfs-tools and/or squashfs-lzma-tools."
1043       eerror "\`-> Visit http://grml.org/grml-live/#current_state for further details."
1044       eend 1
1045       bailout
1046    fi
1047
1048    SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
1049
1050    [ -n "$SQUASHFS_OPTIONS" ]  && SQUASHFS_INFO_MSG="$SQUASHFS_OPTIONS"
1051    [ -n "$SQUASHFS_ZLIB" ]     && SQUASHFS_INFO_MSG="$SQUASHFS_INFO_MSG $SQUASHFS_ZLIB"
1052    [ -n "$SQUASHFS_INFO_MSG" ] && SQUASHFS_INFO_MSG="using options: $SQUASHFS_INFO_MSG"
1053    einfo "Squashfs build information: running binary $SQUASHFS_BINARY $SQUASHFS_INFO_MSG"
1054
1055    log "$SQUASHFS_BINARY $CHROOT_OUTPUT/* $BUILD_OUTPUT/live/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS $SQUASHFS_ZLIB"
1056
1057    if $SQUASHFS_BINARY $CHROOT_OUTPUT/* $BUILD_OUTPUT/live/"${GRML_NAME}".squashfs \
1058       -noappend $SQUASHFS_OPTIONS $SQUASHFS_ZLIB 2>"${SQUASHFS_STDERR}" ; then
1059       echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/filesystem.module
1060       log "Finished execution of stage 'squashfs' [$(date)]"
1061       einfo "Finished execution of stage 'squashfs'" ; eend 0
1062    else
1063       log    "Error: there was a critical error executing stage 'squashfs' [$(date)]:"
1064       log    "$(cat $SQUASHFS_STDERR)"
1065       eerror "Error: there was a critical error executing stage 'squashfs':" ; eend 1
1066       cat    "${SQUASHFS_STDERR}"
1067       bailout
1068    fi
1069
1070    FORCE_ISO_REBUILD=true
1071 fi
1072
1073 # create md5sum file:
1074 ( cd $BUILD_OUTPUT/GRML &&
1075 find .. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
1076 # }}}
1077
1078 # ISO_OUTPUT - mkisofs {{{
1079 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
1080 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
1081
1082 if [ "$BOOT_METHOD" = "isolinux" ] ; then
1083    BOOT_FILE="boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
1084 elif [ "$BOOT_METHOD" = "grub" ] ; then
1085    BOOT_FILE="boot/grub/stage2"
1086 fi
1087
1088 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ]  ; then
1089    log   "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already."
1090    ewarn "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already." ; eend 0
1091 elif [ -n "$SKIP_MKISOFS" ] ; then
1092    log   "Skipping stage 'iso build' as requested via option -n"
1093    ewarn "Skipping stage 'iso build' as requested via option -n" ; eend 0
1094 else
1095    mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
1096
1097    if $FORCE_ISO_REBUILD && ! [ -f "${ISO_OUTPUT}/${ISO_NAME}" ] ; then
1098       log   "Forcing rebuild of ISO because files on ISO have been modified."
1099       einfo "Forcing rebuild of ISO because files on ISO have been modified."
1100    fi
1101
1102    # support mkisofs as well as genisoimage
1103    if which mkisofs >/dev/null 2>&1; then
1104       MKISOFS='mkisofs'
1105    elif which genisoimage >/dev/null 2>&1; then
1106       MKISOFS='genisoimage'
1107    else
1108       log    "Error: neither mkisofs nor genisoimage available - can not create ISO."
1109       eerror "Error: neither mkisofs nor genisoimage available - can not create ISO." ; eend 1
1110       bailout
1111    fi
1112
1113    CURRENT_DIR=$(pwd)
1114    if cd "$BUILD_OUTPUT" ; then
1115       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} ."
1116       "$MKISOFS" -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
1117               -l -r -J -no-emul-boot -boot-load-size 4 -boot-info-table    \
1118               -b $BOOT_FILE -no-pad \
1119               -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
1120
1121       # pad the output ISO to multiples of 256 KiB for partition table support
1122       siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
1123       cyls=$((siz / 512 / 32 / 16 + 1))   # C=$cyls H=16 S=32
1124       siz=$((cyls * 16 * 32 * 512))   # size after padding
1125       dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
1126          of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
1127
1128       # support disabling hybrid ISO image
1129       if [ "$HYBRID_METHOD" = "disable" ] ; then\
1130          log   "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1131          einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1132          eend 0
1133       # use isohybrid only on request
1134       elif [ "$HYBRID_METHOD" = "isohybrid" ] ; then
1135          if ! which isohybrid >/dev/null 2>&1 ; then
1136            bailout 12 "isohybrid binary not found - please install syslinux/syslinux-common"
1137          else
1138            log "Creating hybrid ISO file with isohybrid method"
1139            einfo "Creating hybrid ISO file with isohybrid method"
1140            # Notes for consideration:
1141            # "-entry 4 -type 1c"
1142            # * using 4 as the partition number is supposed to help with BIOSes
1143            #   that only support USB-Zip boot
1144            # * using 1c (i.e. hidden FAT32 LBA), instead of the default 0x17
1145            #   (hidden NTFS, IIRC), as the partition type is sometimes needed
1146            #   to get the BIOS even look at the partition created by isohybrid
1147            isohybrid "${ISO_OUTPUT}/${ISO_NAME}"
1148            eend $?
1149          fi
1150       # by default use our manifold boot method:
1151       else
1152          if ! [ -r boot/grub/core.img ] ; then
1153            ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
1154          else
1155            log "Creating hybrid ISO file with manifold method"
1156            einfo "Creating hybrid ISO file with manifold method"
1157            (
1158                # 512 bytes: MBR, partition table, load GRUB 2
1159                echo 4 63 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 4:0x96 -g $cyls:16:32
1160                # pad to a whole of 2048 bytes (one CD sector)
1161                dd if=/dev/zero bs=512 count=3 2>/dev/null
1162                # append GRUB 2 (must be <=30720 bytes)
1163                cat boot/grub/core.img
1164            ) | dd of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
1165            eend $?
1166          fi
1167       fi
1168
1169       # generate md5sum and sha1sum of ISO if we are using class 'RELEASE':
1170       case $CLASSES in *RELEASE*)
1171          [ "$RC" = 0 ] && \
1172          (
1173            if cd $ISO_OUTPUT ; then
1174              md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
1175              touch -r ${ISO_NAME} ${ISO_NAME}.md5
1176              sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
1177              touch -r ${ISO_NAME} ${ISO_NAME}.sha1
1178            fi
1179          )
1180          ;;
1181       esac
1182
1183       cd $CURRENT_DIR
1184    fi
1185
1186    if [ "$RC" = 0 ] ; then
1187       log   "Finished execution of stage 'iso build' [$(date)]"
1188       einfo "Finished execution of stage 'iso build'" ; eend 0
1189    else
1190       log    "Error: there was a critical error ($RC) executing stage 'iso build' [$(date)]"
1191       eerror "Error: there was a critical error executing stage 'iso build'" ; eend 1
1192       bailout $RC
1193    fi
1194 fi
1195 # }}}
1196
1197 # log build information to database if grml-live-db is installed and enabled {{{
1198 dpkg_to_db() {
1199 if [ -d /usr/share/grml-live-db ] ; then
1200
1201   # safe defaults
1202   DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot:
1203   [ -n "$DPKG_DATABASE" ]  || DPKG_DATABASE=/var/log/grml-live.db
1204   [ -n "$DPKG_DBSCRIPT" ]  || DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
1205   [ -n "$DPKG_DBOPTIONS" ] || DPKG_DBOPTIONS="--database $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME --dpkg $DPKG_LIST"
1206
1207   if ! [ -x "$DPKG_DBSCRIPT" ] ; then
1208     log "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information."
1209     eerror "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information." ; eend 1
1210     bailout 14
1211   fi
1212
1213   # disable by default for now, not sure whether really everyone is using a local db file
1214   #if ! touch "$DPKG_DATABASE" ; then
1215   #  eerror "Error: can not write to ${DPKG_DATABASE}, can not log dpkg information." ; eend 1
1216   #  bailout 14
1217   #fi
1218
1219   if ! [ -r "$DPKG_LIST" ] ; then
1220      log   "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)"
1221      ewarn "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)" ; eend 0
1222   else
1223      einfo "Logging $DPKG_LIST to database $DPKG_DATABASE"
1224      log "Logging $DPKG_LIST to database $DPKG_DATABASE"
1225      log "Executing $DPKG_DBSCRIPT $DPKG_DBOPTIONS"
1226      eindent
1227
1228      if DB_INFO=$("$DPKG_DBSCRIPT" $DPKG_DBOPTIONS 2>&1) ; then
1229        einfo "$DB_INFO"
1230        eend 0
1231      else
1232        eerror "$DB_INFO"
1233        eend 1
1234      fi
1235
1236      eoutdent
1237   fi
1238
1239 fi
1240 }
1241 # }}}
1242
1243 # finalize {{{
1244 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
1245 log "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]"
1246
1247 dpkg_to_db # make sure we catch the last log line as well, therefore execute between log + einfo
1248
1249 einfo "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]" ; eend 0
1250 bailout 0
1251 # }}}
1252
1253 ## END OF FILE #################################################################
1254 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=3