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