Add backwards compability for ZERO_LOGFILE and document it accordingly.
[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.34-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 # clean/zero grml-live logfile {{{
292
293 # keep for backwards compability reasons (default behaviour until grml-live 0.9.34)
294 if [ -n "$ZERO_LOGFILE" -a -z "$PRESERVE_LOGFILE" ] ; then
295   echo -n > $LOGFILE
296   einfo "Zeroing logfile $LOGFILE as requested via \$ZERO_LOGFILE."
297   ewarn "Please consider disabling the \$ZERO_LOGFILE option as grml-live clears..."
298   ewarn "... the logfile $LOGFILE by default (unless \$PRESERVE_LOGFILE is set) nowadays."
299   eend 0
300 fi
301
302 if [ -n "$PRESERVE_LOGFILE" ] ; then
303   echo "Preserving logfile $LOGFILE as requested via \$PRESERVE_LOGFILE"
304 else
305   echo -n > $LOGFILE
306 fi
307 # }}}
308
309 # clean/zero/remove old FAI directory {{{
310 if [ -n "$ZERO_FAI_LOGFILE" ] ; then
311    if [ -d /var/log/fai/"$HOSTNAME" ] ; then
312       rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last)"
313       rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-dirinstall)"
314       rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-softupdate)"
315       rm -f /var/log/fai/"$HOSTNAME"/last \
316             /var/log/fai/"$HOSTNAME"/last-dirinstall \
317             /var/log/fai/"$HOSTNAME"/last-softupdate
318    fi
319 fi
320 # }}}
321
322 # ask user whether the setup is ok {{{
323 if [ -z "$FORCE" ] ; then
324    echo
325    echo "${PN} [${GRML_LIVE_VERSION}]: check your configuration (or use -F to force execution):"
326    echo
327    echo "  FAI classes:       $CLASSES"
328    [ -r "$LOCAL_CONFIG" ]       && echo "  local config:      /etc/grml/grml-live.local"
329    [ -n "$CONFIG" ]             && echo "  configuration:     $CONFIG"
330    echo "  main directory:    $OUTPUT"
331    [ -n "$CHROOT_OUTPUT" ]      && echo "  chroot target:     $CHROOT_OUTPUT"
332    [ -n "$BUILD_OUTPUT" ]       && echo "  build target:      $BUILD_OUTPUT"
333    [ -n "$ISO_OUTPUT" ]         && echo "  ISO target:        $ISO_OUTPUT"
334    [ -n "$GRML_NAME" ]          && echo "  grml name:         $GRML_NAME"
335    [ -n "$RELEASENAME" ]        && echo "  release name:      $RELEASENAME"
336    [ -n "$DATE" ]               && echo "  build date:        $DATE"
337    [ -n "$VERSION" ]            && echo "  grml version:      $VERSION"
338    [ -n "$SUITE" ]              && echo "  Debian suite:      $SUITE"
339    [ -n "$ARCH" ]               && echo "  Architecture:      $ARCH"
340    [ -n "$BOOT_METHOD" ]        && echo "  Boot method:       $BOOT_METHOD"
341    [ -n "$TEMPLATE_DIRECTORY" ] && echo "  Template files:    $TEMPLATE_DIRECTORY"
342    [ -n "$CHROOT_INSTALL" ]     && echo "  Install files from directory to chroot:  $CHROOT_INSTALL"
343    [ -n "$FAI_ARGS" ]           && echo "  additional arguments for FAI: $FAI_ARGS"
344    [ -n "$LOGFILE" ]            && echo "  Logging to file:   $LOGFILE"
345    [ -n "$SQUASHFS_ZLIB" ]      && echo "  Using ZLIB (instead of LZMA) compression."
346    [ -n "$SQUASHFS_OPTIONS" ]   && echo "  Using SQUASHFS_OPTIONS ${SQUASHFS_OPTIONS}"
347    [ -n "$VERBOSE" ]            && echo "  Using VERBOSE mode."
348    [ -n "$UPDATE" ]             && echo "  Executing UPDATE instead of fresh installation."
349    [ -n "$SKIP_MKSQUASHFS" ]    && echo "  Skipping creation of SQUASHFS file."
350    [ -n "$SKIP_MKISOFS" ]       && echo "  Skipping creation of ISO file."
351    [ -n "$BUILD_ONLY" ]         && echo "  Executing BUILD_ONLY instead of fresh installation or UPDATE."
352    [ -n "$BUILD_DIRTY" ]        && echo "  Executing BUILD_DIRTY to leave chroot untouched."
353    echo
354    echo -n "Is this ok for you? [y/N] "
355    read a
356    if ! [ "$a" = 'y' -o "$a" = 'Y' ] ; then
357       bailout 1 "Exiting as requested."
358    fi
359    echo
360 fi
361
362 if [ -n "$CONFIG" ] ; then
363    if ! [ -f "$CONFIG" ] ; then
364       log    "Error: $CONFIG could not be read. Exiting. [$(date)]"
365       eerror "Error: $CONFIG could not be read. Exiting." ; eend 1
366       bailout 1
367    else
368       log "Sourcing $CONFIG"
369       . $CONFIG
370    fi
371 fi
372
373 start_seconds=$(cut -d . -f 1 /proc/uptime)
374 log "------------------------------------------------------------------------------"
375 log "Starting grml-live [${GRML_LIVE_VERSION}] run on $(date)"
376 log "Executed grml-live command line:"
377 log "$CMDLINE"
378
379 einfo "Logging actions to logfile $LOGFILE"
380 # }}}
381
382 # on-the-fly configuration {{{
383 if [ -n "$MIRROR_DIRECTORY" ] ; then
384    if ! [ -d "$MIRROR_DIRECTORY/debian" ] ; then
385       log    "Error: $MIRROR_DIRECTORY/debian does not seem to exist. Exiting. [$(date)]"
386       eerror "Error: $MIRROR_DIRECTORY/debian does not seem to exist. Exiting." ; eend 1
387       bailout 1
388    fi
389    cat > "$SOURCES_LIST_FILE" << EOF
390 # NOTE: This file is *NOT* meant for manual customisation! This file is
391 # modified by grml-live and any changes might be overriden.
392 # You might consider using GRML_LIVE_SOURCES in /etc/grml/grml-live.conf*
393 # and using /etc/grml/fai/files/etc/apt instead!'
394 EOF
395    echo "$MIRROR_SOURCES" >> "$SOURCES_LIST_FILE"
396    if [ -n "$GRML_LIVE_SOURCES" ] ; then
397       echo "$GRML_LIVE_SOURCES" >> "$SOURCES_LIST_FILE"
398    fi
399 elif [ -n "$GRML_LIVE_SOURCES" ] ; then
400    cat > "$SOURCES_LIST_FILE" << EOF
401 # NOTE: This file is *NOT* meant for manual customisation! This file is
402 # modified by grml-live and any changes might be overriden.
403 # You might consider using GRML_LIVE_SOURCES in /etc/grml/grml-live.conf*
404 # and using /etc/grml/fai/files/etc/apt instead!'
405 EOF
406    echo "$GRML_LIVE_SOURCES" >> "$SOURCES_LIST_FILE"
407 fi
408
409 if [ -n "$FAI_DEBOOTSTRAP" ] ; then
410    sed "s#^FAI_DEBOOTSTRAP=.*#FAI_DEBOOTSTRAP=\"$FAI_DEBOOTSTRAP\"#" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
411 fi
412
413 # does this suck? YES!
414 # /usr/share/debootstrap/scripts/unstable does not exist, instead use 'sid':
415 case $SUITE in
416    unstable) SUITE='sid' ;;
417    # make sure that we *NEVER* write any broken suite name to sources.list,
418    # otherwise we won't be able to adjust it one next (correct) execution
419    stable)   ;;
420    testing)  ;;
421    etch)     ;;
422    lenny)    ;;
423    squeeze)  ;;
424    sid)      ;;
425    *) echo "Sorry, $SUITE is not a valid Debian suite, exiting.">&2; bailout 1 ;;
426 esac
427
428 DIST=" etch\| stable\| lenny\| squeeze\| testing\| sid\| unstable"
429 sed "s/\(^deb .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/" "$SOURCES_LIST_FILE" | sponge "$SOURCES_LIST_FILE"
430 for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" ; do
431     if [ -n "$file" ] ; then
432        sed "s/^SUITE=.*/SUITE=\"$SUITE\"/" $file | sponge $file
433        sed "s/\(^deb .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/" "$file" | sponge "$file"
434     fi
435 done
436
437 # notice: activate grml-live pool only if we are building against unstable:
438 if grep -qe unstable -qe sid "$SOURCES_LIST_FILE" ; then
439    grep -q 'grml-live.*main' "$SOURCES_LIST_FILE" || \
440    grep grml-stable "$SOURCES_LIST_FILE" | \
441         sed 's/grml-stable/grml-live/' >> "$SOURCES_LIST_FILE"
442 else
443    grep -q 'grml-live.*main' "$SOURCES_LIST_FILE" && \
444    sed 's/.*grml-live.*/# removed grml-live repository/' "$SOURCES_LIST_FILE" | sponge "$SOURCES_LIST_FILE"
445 fi
446
447 for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" "$NFSROOT_CONF" ; do
448     if [ -n "$file" ] ; then
449        sed "s|^FAI_DEBOOTSTRAP=\"[a-z]* |FAI_DEBOOTSTRAP=\"$SUITE |" "$file" | sponge "$file"
450     fi
451 done
452
453 # validate whether the specified architecture class matches the
454 # architecture (option), otherwise installation of kernel will fail
455 if echo $CLASSES | grep -qi i386 ; then
456    if ! [[ "$ARCH" == "i386" ]] ; then
457       log    "Error: You specified the I386 class but are trying to build something else (AMD64?)."
458       eerror "Error: You specified the I386 class but are trying to build something else (AMD64?)."
459       eerror "Tip:   Either invoke grml-live with '-a i386' or adjust the architecture class. Exiting."
460       eend 1
461       bailout
462    fi
463 elif echo $CLASSES | grep -qi amd64 ; then
464    if ! [[ "$ARCH" == "amd64" ]] ; then
465       log    "Error: You specified the AMD64 class but are trying to build something else (I386?)."
466       eerror "Error: You specified the AMD64 class but are trying to build something else (I386?)."
467       eerror "Tip:   Either invoke grml-live with '-a amd64' or adjust the architecture class. Exiting."
468       eend 1
469       bailout
470    fi
471 fi
472
473 if grep -q -- 'FAI_DEBOOTSTRAP_OPTS.*--arch' "$NFSROOT_CONF" ; then
474    sed "s/--arch [a-z0-9]* /--arch $ARCH /" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
475 else
476    sed "s|^FAI_DEBOOTSTRAP_OPTS=\"\(.*\)|FAI_DEBOOTSTRAP_OPTS=\"--arch $ARCH \1|" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
477 fi
478 # }}}
479
480 # CHROOT_OUTPUT - execute FAI {{{
481 if [ -n "$BUILD_DIRTY" ]; then
482    log   "Skipping stage 'fai' as requested via option -B"
483    ewarn "Skipping stage 'fai' as requested via option -B" ; eend 0
484 else
485    [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
486
487    # provide inform fai about the ISO we build
488    [ -d "$CHROOT_OUTPUT/etc/" ] || mkdir -p "$CHROOT_OUTPUT/etc/"
489    echo '# This file has been generated by grml-live.' > "$CHROOT_OUTPUT/etc/grml_live_version"
490    [ -n "$GRML_LIVE_VERSION" ] && echo "GRML_LIVE_VERSION=$GRML_LIVE_VERSION" >> "$CHROOT_OUTPUT/etc/grml_live_version"
491    [ -n "$SUITE" ] && echo "SUITE=$SUITE" >> "$CHROOT_OUTPUT/etc/grml_live_version"
492
493    if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
494       FAI_ACTION=softupdate
495    else
496       FAI_ACTION=dirinstall
497    fi
498
499    if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
500       if ! [ -r "$CHROOT_OUTPUT/etc/debian_version" ] ; then
501          log    "Error: does not look like you have a working chroot. Updating/building not possible."
502          eerror "Error: does not look like you have a working chroot. Updating/building not possible. (Drop -u/-b option?)"
503          eend 1
504          bailout 20
505       fi
506    fi
507
508    if [ -d "$CHROOT_OUTPUT/bin" -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
509       log   "Skiping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already."
510       ewarn "Skiping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already." ; eend 0
511    else
512       mkdir -p "$CHROOT_OUTPUT" || bailout 5 "Problem with creating $CHROOT_OUTPUT for FAI"
513
514       if [ -n "${MIRROR_DIRECTORY}" ] ; then
515          mkdir -p "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
516          mount --bind "${MIRROR_DIRECTORY}" "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
517       fi
518
519       log "Executed FAI command line:"
520       log "BUILD_ONLY=$BUILD_ONLY fai $VERBOSE -C $GRML_FAI_CONFIG -c$CLASSES -u $HOSTNAME $FAI_ACTION $CHROOT_OUTPUT $FAI_ARGS"
521       BUILD_ONLY="$BUILD_ONLY" fai $VERBOSE -C "$GRML_FAI_CONFIG" -c"$CLASSES" -u \
522       "$HOSTNAME" $FAI_ACTION "$CHROOT_OUTPUT" $FAI_ARGS | tee -a $LOGFILE
523       RC="$PIPESTATUS" # notice: bash-only
524
525       FORCE_ISO_REBUILD=true
526
527       if [ "$RC" != 0 ] ; then
528          log    "Error: critical error while executing fai [exit code ${RC}]. Exiting."
529          eerror "Error: critical error while executing fai [exit code ${RC}]. Exiting." ; eend 1
530          bailout 1
531       else
532          log "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
533          echo "$GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]" > $CHROOT_OUTPUT/etc/grml_version
534          chmod 644 $CHROOT_OUTPUT/etc/grml_version
535          einfo "Rebuilding initramfs"
536          # make sure new /etc/grml_version reaches the initramfs:
537          # chroot $CHROOT_OUTPUT update-initramfs -u -t => might break when using kernel-package :(
538          chroot $CHROOT_OUTPUT update-initramfs -u -k all
539          eend $?
540       fi
541
542       # Remove all FAI logs from chroot if class RELEASE is used:
543       if [ -f "$CHROOT_OUTPUT"/etc/grml_fai_release ] ; then
544          rm -rf "$CHROOT_OUTPUT"/var/log/fai/*
545       fi
546
547       # make sure we don't leave any mounts - FAI doesn't remove them always
548       umount $CHROOT_OUTPUT/proc 2>/dev/null || /bin/true
549       umount $CHROOT_OUTPUT/sys  2>/dev/null || /bin/true
550       umount $CHROOT_OUTPUT/dev/pts 2>/dev/null || /bin/true
551       umount $CHROOT_OUTPUT/dev 2>/dev/null || /bin/true
552
553       [ -n "$MIRROR_DIRECTORY" ] && umount "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
554
555       # notice: 'fai dirinstall' does not seem to exit appropriate, so:
556       ERROR=''
557       CHECKLOG=/var/log/fai/$HOSTNAME/last
558       if [ -r "$CHECKLOG/software.log" ] ; then
559          # 1 errors during executing of commands
560          grep 'dpkg: error processing' $CHECKLOG/software.log >> $LOGFILE && ERROR=1
561          grep 'E: Method http has died unexpectedly!' $CHECKLOG/software.log >> $LOGFILE && ERROR=2
562          grep 'ERROR: chroot' $CHECKLOG/software.log >> $LOGFILE && ERROR=3
563          grep 'E: Failed to fetch' $CHECKLOG/software.log >> $LOGFILE && ERROR=4
564          grep 'Unable to write mmap - msync (28 No space left on device)' $CHECKLOG/software.log >> $LOGFILE && ERROR=5
565       fi
566
567       if [ -r "$CHECKLOG/shell.log" ] ; then
568          grep 'FAILED with exit code' $CHECKLOG/shell.log >> $LOGFILE && ERROR=2
569       fi
570
571       if [ -n "$ERROR" ] ; then
572          log    "Error: there was a critical error [${ERROR}] during execution of stage 'fai dirinstall' [$(date)]"
573          eerror "Error: there was a critical error during execution of stage 'fai dirinstall'"
574          eerror "Note:  check out ${CHECKLOG}/ for details. [exit ${ERROR}]"
575          eend 1
576          bailout 1
577       else
578          log "Finished execution of stage 'fai dirinstall' [$(date)]"
579          einfo "Finished execution of stage 'fai dirinstall'"
580       fi
581
582       einfo "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
583       log   "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
584       eend 0
585    fi
586 fi # BUILD_DIRTY?
587 # }}}
588
589 # package validator {{{
590 CHECKLOG=/var/log/fai/$HOSTNAME/last
591 # package validator
592 if [ -r "$CHECKLOG/package_errors.log" ] && grep -q '[a-z]' "$CHECKLOG/package_errors.log" ; then
593
594    if [ -n "$EXIT_ON_MISSING_PACKAGES" ] ; then
595       eerror "The following packages were requested for installation but could not be processed:"
596       cat $CHECKLOG/package_errors.log
597       eerror "... exiting as requested via \$EXIT_ON_MISSING_PACKAGES."
598       eend 1
599       bailout 13
600    else
601       ewarn "The following packages were requested for installation but could not be processed:"
602       cat $CHECKLOG/package_errors.log
603       eend 0
604    fi
605 fi
606 # }}}
607
608 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
609 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
610 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
611
612 # i386:
613 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
614    if [ -d "$BUILD_OUTPUT"/boot/isolinux -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
615       log   "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already."
616       ewarn "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already." ; eend 0
617    else
618       # booting stuff:
619       [ -d "$BUILD_OUTPUT"/boot/isolinux ] || mkdir -p "$BUILD_OUTPUT"/boot/isolinux
620       [ -d "$BUILD_OUTPUT"/boot/"${SHORT_NAME}" ] || mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"
621
622       if [ -z "$NO_ADDONS" ] ; then
623          [ -d "$BUILD_OUTPUT"/boot/addons   ] || mkdir -p "$BUILD_OUTPUT"/boot/addons
624          if [ -r "$TEMPLATE_DIRECTORY"/boot/addons/memtest ] ; then
625             log "Installing $TEMPLATE_DIRECTORY/boot/addons/memtest"
626             cp "$TEMPLATE_DIRECTORY"/boot/addons/memtest "$BUILD_OUTPUT"/boot/addons/memtest
627          elif [ -r /boot/memtest86+.bin ] ; then
628             log "Installing /boot/memtest86+.bin"
629             cp /boot/memtest86+.bin "$BUILD_OUTPUT"/boot/addons/memtest
630          else
631             ewarn "No memtest binary found (either install package grml-live-addons or memtest86+), skipping."
632             log "No memtest binary found (either install package grml-live-addons or memtest86+), skipping."
633             eend 0
634          fi
635       fi
636
637       # if we don't have an initrd we a) can't boot and b) there was an error
638       # during build, so check for the file:
639       INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
640       if [ -n "$INITRD" ] ; then
641          cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/initrd.gz
642          find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
643       else
644          log    "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
645          eerror "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
646          bailout 10
647       fi
648
649       KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
650       if [ -n "$KERNEL_IMAGE" ] ; then
651          cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/linux26
652       else
653          log    "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
654          eerror "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
655          bailout 11
656       fi
657
658       [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
659       if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
660          log    "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
661          eerror "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
662          bailout 8
663       fi
664
665       # *always* copy files to output directory so the variables
666       # get adjusted according to the build
667       cp ${TEMPLATE_DIRECTORY}/boot/isolinux/*  "$BUILD_OUTPUT"/boot/isolinux/
668
669       if [ -n "$NO_ADDONS" ] ; then
670          log "Skipping installation boot addons requested via \$NO_ADDONS."
671          einfo "Skipping installation boot addons requested via \$NO_ADDONS."
672          eend 0
673       else
674          if ! [ -d "$TEMPLATE_DIRECTORY"/boot/addons/bsd4grml ] ; then
675            ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
676          else
677            # copy only files so we can handle bsd4grml on its own
678            for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
679                test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
680            done
681
682            if [ -z "$NO_ADDONS_BSD4GRML" ] ; then
683               cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
684            fi
685          fi
686       fi
687
688       if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
689          cp -a ${TEMPLATE_DIRECTORY}/boot/grub  "$BUILD_OUTPUT"/boot/
690       fi
691       # make sure we have recent template files available, otherwise updating
692       # the strings like $GRML_NAME and $VERSION might be out of date
693       cp ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
694
695       if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
696          log    "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
697          eerror "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
698          bailout 9
699       fi
700
701       [ -d "$BUILD_OUTPUT"/GRML ] || mkdir "$BUILD_OUTPUT"/GRML
702       cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/
703
704       # adjust boot splash information:
705       RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
706       RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
707       RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
708
709       sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/grml-version
710       sed -i "s/%DATE%/$DATE/"                                      "$BUILD_OUTPUT"/GRML/grml-version
711
712       # make sure the squashfs filename is set accordingly:
713       SQUASHFS_NAME="$GRML_NAME.squashfs"
714
715       # adjust all variables in the templates with the according distribution information
716       for file in "${BUILD_OUTPUT}"/boot/isolinux/*.cfg "${BUILD_OUTPUT}"/boot/isolinux/*.msg \
717                   "${BUILD_OUTPUT}"/boot/grub/* ; do
718         sed -i "s/%ARCH%/$ARCH/g"                    "${file}"
719         sed -i "s/%DATE%/$DATE/g"                    "${file}"
720         sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/g"      "${file}"
721         sed -i "s/%DISTRI_NAME%/$DISTRI_NAME/g"      "${file}"
722         sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/g"  "${file}"
723         sed -i "s/%GRML_NAME%/$GRML_NAME/g"          "${file}"
724         sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/g"  "${file}"
725         sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/g"    "${file}"
726         sed -i "s/%SHORT_NAME%/$SHORT_NAME/g"        "${file}"
727         sed -i "s/%VERSION%/$VERSION/g"              "${file}"
728       done
729
730       # adjust bootsplash accordingly but make sure the string has the according lenght
731       SQUASHFS_NAME="$(cut_string 20 "$SQUASHFS_NAME")"
732       SQUASHFS_NAME="$(extend_string_end 20 "$SQUASHFS_NAME")"
733       sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "$BUILD_OUTPUT"/boot/isolinux/f4
734       sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "$BUILD_OUTPUT"/boot/isolinux/f5
735
736       # generate addon list
737       rm "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
738       for name in $(ls "${BUILD_OUTPUT}"/boot/isolinux/addon_*.cfg) ; do
739         include_name=$(basename "$name")
740         echo "include $include_name"  >> "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
741       done
742
743       if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
744          log "including grmlmain.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
745          echo "include grmlmain.cfg"    >  "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
746          echo "include default.cfg"     >  "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
747          echo "include menuoptions.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
748          echo "include grml.cfg"        >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
749          echo "include options.cfg"     >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
750          if [ ! -n "$NO_ADDONS" ] ; then
751            echo "include addons.cfg"    >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
752          fi
753          echo "include isoprompt.cfg"   >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
754          echo "include hd.cfg"          >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
755          echo "include hidden.cfg"      >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
756       else # assume we are building a custom distribution:
757          log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
758          einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
759          if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
760            log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
761            eindent
762            einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
763            eoutdent
764            eend $?
765         else
766            log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
767            echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
768            [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
769          fi
770       fi
771
772       # use old style console based isolinux method only if requested:
773       if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
774          log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
775          einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
776          if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
777            einfo "include for console.cfg already foud, nothing to do."
778            eend 0
779          else
780            log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
781            einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
782            echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
783            eend $?
784          fi
785       else
786          log 'Using graphical boot menu.'
787          if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
788            log "include for vesamenu.cfg already foud, nothing to do."
789          else
790            log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
791            echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
792          fi
793       fi
794
795       # jump back to grub from bsd4grml (/boot/grub/stage2):
796       GRUB_LEGACY=stage2
797
798       if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
799          if [ -e "$BUILD_OUTPUT"/boot/grub/core.img ]; then
800             GRUB_VERSION=2
801          else
802             GRUB_VERSION=1
803          fi
804
805          for file in "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 \
806                      "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.cfg \
807                      "$BUILD_OUTPUT"/boot/isolinux/*.cfg \
808                      "$BUILD_OUTPUT"/boot/grub/grub.cfg \
809                      "$BUILD_OUTPUT"/boot/grub/menu.lst ; do
810              if [ -e "$file" ] ; then
811                sed -i -e "s!%GRUB_VERSION%!$GRUB_VERSION!g" \
812                       -e "s!%GRUB_LEGACY%!$GRUB_LEGACY!g" "$file"
813              fi
814          done
815
816          sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
817       fi
818
819       if [ -e "$BUILD_OUTPUT"/boot/grub/$GRUB_LEGACY ]; then
820          sed -i "s/%GRUB_LEGACY%/$GRUB_LEGACY/g" "$BUILD_OUTPUT"/boot/grub/menu.lst
821          sed -i "s/%GRUB_LEGACY%/$GRUB_LEGACY/g" "$BUILD_OUTPUT"/boot/grub/grub.cfg
822       else
823          sed -i "/%GRUB_LEGACY%/d" "$BUILD_OUTPUT"/boot/grub/menu.lst
824          sed -i "/%GRUB_LEGACY%/d" "$BUILD_OUTPUT"/boot/grub/grub.cfg
825       fi
826
827       # autostart for Windows:
828       if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
829          cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
830       fi
831
832       # windows-binaries:
833       if [ -n "$NO_WINDOWS_BINARIES" ] ; then
834          log   "Skipping download of windows binaries as requested via \$NO_WINDOWS_BINARIES."
835          einfo "Skipping download of windows binaries as requested via \$NO_WINDOWS_BINARIES."
836          eend 0
837       else
838          if [ -f "$BUILD_OUTPUT"/windows/putty.exe ] ; then
839             log   "Skipping stage 'WINDOWS_BINARIES' as $BUILD_OUTPUT/windows exists already."
840             ewarn "Skipping stage 'WINDOWS_BINARIES' as $BUILD_OUTPUT/windows exists already." ; eend 0
841          else
842             if ! [ -d "$BUILD_OUTPUT"/windows ] ; then
843                mkdir "$BUILD_OUTPUT"/windows
844                ( cd "$BUILD_OUTPUT"/windows
845                  for file in pageant plink pscp psftp putty puttygen ; do
846                     wget -O ${file}.exe ${WINDOWS_BINARIES}/${file}.exe
847                     md5sum ${file}.exe > ${file}.exe.md5
848                  done )
849             fi
850
851             log "Finished execution of stage 'WINDOWS_BINARIES' [$(date)]"
852             einfo "Finished execution of stage 'WINDOWS_BINARIES'" ; eend 0
853          fi
854       fi
855
856    FORCE_ISO_REBUILD=true
857    einfo "Finished execution of stage 'boot'" ; eend 0
858    fi
859 else
860    log    'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
861    eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
862    bailout
863 fi
864
865 # support installation of local files into the chroot/ISO
866 if [ -n "$CHROOT_INSTALL" ] ; then
867   if ! [ -d "$CHROOT_INSTALL" ] ; then
868      log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
869      ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
870   else
871      log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
872      einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
873      rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
874      eend $?
875      einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
876      FORCE_ISO_REBUILD=true
877   fi
878 fi
879
880 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
881    log   "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
882    ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
883 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
884    log   "Skipping stage 'squashfs' as requested via option -q"
885    ewarn "Skipping stage 'squashfs' as requested via option -q" ; eend 0
886 else
887    [ -d "$BUILD_OUTPUT"/live ] || mkdir "$BUILD_OUTPUT"/live
888    # make sure we don't leave (even an empty) base.tgz:
889    [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
890
891    # $SQUASHFS_BINARY is specified in the configuration:
892    if [ -n "$SQUASHFS_BINARY" ] ; then
893       if ! which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
894          log    "Error: specified mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
895          eerror "Error: specified mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
896          bailout
897       fi
898    else # no $SQUASHFS_BINARY configured, let's find the according binary:
899       # Note: this is ALL for backward compability and yes: it's serious PITA.
900       # We'll definitely drop this once people build >2.6.28-grml* only and
901       # the squashfs-tools vs. squashfs-lzma-tools + zlib vs. lzma situation
902       # is settling...
903
904       # assume the safe default if mksquashfs-lzma isn't present:
905       if ! which mksquashfs-lzma >/dev/null 2>&1 ; then
906          SQUASHFS_BINARY='mksquashfs'
907       else # mksquashfs-lzma is available since squashfs-lzma-tools 4.0:
908          # if the user wants to use zlib then don't use mksquashfs-lzma:
909          if echo "$SQUASHFS_OPTIONS" | grep -q -- "-nolzma" || [ -n "$SQUASHFS_ZLIB" ] ; then
910             SQUASHFS_BINARY='mksquashfs'
911          else # neither -nolzma nor -z and mksquashfs-lzma is available:
912             SQUASHFS_BINARY='mksquashfs-lzma'
913
914             # backwards compability: someone has squashfs-lzma-tools >=4 installed but
915             # 1) doesn't use -nolzma in $SQUASHFS_OPTIONS or the grml-live's -z option *and*
916             # 2) builds against kernel version <=2.6.28-grml[64]
917             if ls $CHROOT_OUTPUT/boot/vmlinuz* >/dev/null 2>&1 ; then
918                KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
919
920                case $KERNEL_IMAGE in
921                   *vmlinuz-2.6.28-grml*|*vmlinuz-2.6.26-grml*|*vmlinuz-2.6.23-grml*)
922                   log   "You seem to be building a system with squashfs file format 3 using squashfs-lzma-tools >=4."
923                   ewarn "You seem to be building a system with squashfs file format 3 using squashfs-lzma-tools >=4."
924                   ewarn "|-> Consider installing squashfs-lzma-tools 3.3-1 for support of file format version 3."
925                   ewarn "|-> Trying the mksquashfs binary instead of mksquashfs-lzma (though this might fail)."
926                   ewarn "\`-> Visit http://grml.org/grml-live/#current_state for further details if building fails."
927                   eend 0
928                   SQUASHFS_BINARY='mksquashfs'
929                   ;;
930                esac
931             fi
932
933             # if we still want to use mksquashfs-lzma then let's choose
934             # blocksize 256k as this gives best result with regards to time + comopression
935             [[ "$SQUASHFS_BINARY" == "mksquashfs-lzma" ]] && SQUASHFS_OPTIONS="-b 256k -lzma"
936          fi
937
938       fi
939    fi
940
941    # make sure mksquashfs can handle the according option:
942    if [ -n "$SQUASHFS_ZLIB" ] ; then
943       $SQUASHFS_BINARY --help 2>&1 | grep -q -- "$SQUASHFS_ZLIB" || SQUASHFS_ZLIB=''
944    fi
945
946    # make sure to drop the -nolzma option if it's not available:
947    if echo "$SQUASHFS_OPTIONS" | grep -q -- "-nolzma" ; then
948       if ! $SQUASHFS_BINARY --help 2>&1 | grep -q -- '-nolzma' ; then
949          log   "The $SQUASHFS_BINARY binary does NOT support the nolzma option, dropping it and using default mode."
950          ewarn "The $SQUASHFS_BINARY binary does NOT support the nolzma option, dropping it and using default mode."
951          SQUASHFS_OPTIONS="$(echo $SQUASHFS_OPTIONS | sed 's/-nolzma//g')"
952          eend 0
953       fi
954    fi
955
956    # make sure to drop the -lzma option if it's not available:
957    if echo "$SQUASHFS_OPTIONS" | grep -q -- "-lzma" ; then
958       if ! $SQUASHFS_BINARY --help 2>&1 | grep -q -- '-lzma' ; then
959          log   "The $SQUASHFS_BINARY binary does NOT support the lzma option, dropping it and using default mode."
960          ewarn "The $SQUASHFS_BINARY binary does NOT support the lzma option, dropping it and using default mode."
961          SQUASHFS_OPTIONS="$(echo $SQUASHFS_OPTIONS | sed 's/-lzma//g')"
962          eend 0
963       fi
964    fi
965
966    # support exclusion of files via exclude-file:
967    if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
968       SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE"
969    fi
970
971    # get rid of unnecessary files when building grml-small for final release:
972    if echo "$CLASSES" | grep -q GRML_SMALL ; then
973       SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
974    fi
975
976    # check whether we have the according binary available:
977    if ! which $SQUASHFS_BINARY >/dev/null 2>&1 ; then
978       log    "Error: mksquashfs binary (${SQUASHFS_BINARY}) could not be found. Exiting."
979       eerror "Error: mksquashfs binary (${SQUASHFS_BINARY}) could not be found. Exiting."
980       eerror "|-> Make sure to install either squashfs-tools and/or squashfs-lzma-tools."
981       eerror "\`-> Visit http://grml.org/grml-live/#current_state for further details."
982       eend 1
983       bailout
984    fi
985
986    SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
987
988    [ -n "$SQUASHFS_OPTIONS" ]  && SQUASHFS_INFO_MSG="$SQUASHFS_OPTIONS"
989    [ -n "$SQUASHFS_ZLIB" ]     && SQUASHFS_INFO_MSG="$SQUASHFS_INFO_MSG $SQUASHFS_ZLIB"
990    [ -n "$SQUASHFS_INFO_MSG" ] && SQUASHFS_INFO_MSG="using options: $SQUASHFS_INFO_MSG"
991    einfo "Squashfs build information: running binary $SQUASHFS_BINARY $SQUASHFS_INFO_MSG"
992
993    log "$SQUASHFS_BINARY $CHROOT_OUTPUT/* $BUILD_OUTPUT/live/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS $SQUASHFS_ZLIB"
994
995    if $SQUASHFS_BINARY $CHROOT_OUTPUT/* $BUILD_OUTPUT/live/"${GRML_NAME}".squashfs \
996       -noappend $SQUASHFS_OPTIONS $SQUASHFS_ZLIB 2>"${SQUASHFS_STDERR}" ; then
997       echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/filesystem.module
998       log "Finished execution of stage 'squashfs' [$(date)]"
999       einfo "Finished execution of stage 'squashfs'" ; eend 0
1000    else
1001       log    "Error: there was a critical error executing stage 'squashfs' [$(date)]:"
1002       log    "$(cat $SQUASHFS_STDERR)"
1003       eerror "Error: there was a critical error executing stage 'squashfs':" ; eend 1
1004       cat    "${SQUASHFS_STDERR}"
1005       bailout
1006    fi
1007
1008    FORCE_ISO_REBUILD=true
1009 fi
1010
1011 # create md5sum file:
1012 ( cd $BUILD_OUTPUT/GRML &&
1013 find .. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
1014 # }}}
1015
1016 # ISO_OUTPUT - mkisofs {{{
1017 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
1018 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
1019
1020 if [ "$BOOT_METHOD" = "isolinux" ] ; then
1021    BOOT_FILE="boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
1022 elif [ "$BOOT_METHOD" = "grub" ] ; then
1023    BOOT_FILE="boot/grub/stage2"
1024 fi
1025
1026 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ]  ; then
1027    log   "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already."
1028    ewarn "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already." ; eend 0
1029 elif [ -n "$SKIP_MKISOFS" ] ; then
1030    log   "Skipping stage 'iso build' as requested via option -n"
1031    ewarn "Skipping stage 'iso build' as requested via option -n" ; eend 0
1032 else
1033    mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
1034
1035    if $FORCE_ISO_REBUILD && ! [ -f "${ISO_OUTPUT}/${ISO_NAME}" ] ; then
1036       log   "Forcing rebuild of ISO because files on ISO have been modified."
1037       einfo "Forcing rebuild of ISO because files on ISO have been modified."
1038    fi
1039
1040    # support mkisofs as well as genisoimage
1041    if which mkisofs >/dev/null 2>&1; then
1042       MKISOFS='mkisofs'
1043    elif which genisoimage >/dev/null 2>&1; then
1044       MKISOFS='genisoimage'
1045    else
1046       log    "Error: neither mkisofs nor genisoimage available - can not create ISO."
1047       eerror "Error: neither mkisofs nor genisoimage available - can not create ISO." ; eend 1
1048       bailout
1049    fi
1050
1051    CURRENT_DIR=$(pwd)
1052    if cd "$BUILD_OUTPUT" ; then
1053       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} ."
1054       "$MKISOFS" -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
1055               -l -r -J -no-emul-boot -boot-load-size 4 -boot-info-table    \
1056               -b $BOOT_FILE -no-pad \
1057               -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
1058
1059       # pad the output ISO to multiples of 256 KiB for partition table support
1060       siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
1061       cyls=$((siz / 512 / 32 / 16 + 1))   # C=$cyls H=16 S=32
1062       siz=$((cyls * 16 * 32 * 512))   # size after padding
1063       dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
1064          of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
1065
1066       # support disabling hybrid ISO image
1067       if [ "$HYBRID_METHOD" = "disable" ] ; then\
1068          log   "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1069          einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1070          eend 0
1071       # use isohybrid only on request
1072       elif [ "$HYBRID_METHOD" = "isohybrid" ] ; then
1073          if ! which isohybrid >/dev/null 2>&1 ; then
1074            bailout 12 "isohybrid binary not found - please install syslinux/syslinux-common"
1075          else
1076            log "Creating hybrid ISO file with isohybrid method"
1077            einfo "Creating hybrid ISO file with isohybrid method"
1078            # Notes for consideration:
1079            # "-entry 4 -type 1c"
1080            # * using 4 as the partition number is supposed to help with BIOSes
1081            #   that only support USB-Zip boot
1082            # * using 1c (i.e. hidden FAT32 LBA), instead of the default 0x17
1083            #   (hidden NTFS, IIRC), as the partition type is sometimes needed
1084            #   to get the BIOS even look at the partition created by isohybrid
1085            isohybrid "${ISO_OUTPUT}/${ISO_NAME}"
1086            eend $?
1087          fi
1088       # by default use our manifold boot method:
1089       else
1090          if ! [ -r boot/grub/core.img ] ; then
1091            ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
1092          else
1093            log "Creating hybrid ISO file with manifold method"
1094            einfo "Creating hybrid ISO file with manifold method"
1095            (
1096                # 512 bytes: MBR, partition table, load GRUB 2
1097                echo 4 63 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 4:0x96 -g $cyls:16:32
1098                # pad to a whole of 2048 bytes (one CD sector)
1099                dd if=/dev/zero bs=512 count=3 2>/dev/null
1100                # append GRUB 2 (must be <=30720 bytes)
1101                cat boot/grub/core.img
1102            ) | dd of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
1103            eend $?
1104          fi
1105       fi
1106
1107       # generate md5sum and sha1sum of ISO if we are using class 'RELEASE':
1108       case $CLASSES in *RELEASE*)
1109          [ "$RC" = 0 ] && \
1110          (
1111            if cd $ISO_OUTPUT ; then
1112              md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
1113              touch -r ${ISO_NAME} ${ISO_NAME}.md5
1114              sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
1115              touch -r ${ISO_NAME} ${ISO_NAME}.sha1
1116            fi
1117          )
1118          ;;
1119       esac
1120
1121       cd $CURRENT_DIR
1122    fi
1123
1124    if [ "$RC" = 0 ] ; then
1125       log   "Finished execution of stage 'iso build' [$(date)]"
1126       einfo "Finished execution of stage 'iso build'" ; eend 0
1127    else
1128       log    "Error: there was a critical error ($RC) executing stage 'iso build' [$(date)]"
1129       eerror "Error: there was a critical error executing stage 'iso build'" ; eend 1
1130       bailout $RC
1131    fi
1132 fi
1133 # }}}
1134
1135 # log build information to database if grml-live-db is installed and enabled {{{
1136 dpkg_to_db() {
1137 if [ -d /usr/share/grml-live-db ] ; then
1138
1139   # safe defaults
1140   DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot:
1141   [ -n "$DPKG_DATABASE" ]  || DPKG_DATABASE=/var/log/grml-live.db
1142   [ -n "$DPKG_DBSCRIPT" ]  || DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
1143   [ -n "$DPKG_DBOPTIONS" ] || DPKG_DBOPTIONS="-d $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME < $DPKG_LIST"
1144
1145   if ! [ -x "$DPKG_DBSCRIPT" ] ; then
1146     eerror "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information." ; eend 1
1147     bailout 14
1148   fi
1149
1150   # disable by default for now, not sure whether really everyone is using a local db file
1151   #if ! touch "$DPKG_DATABASE" ; then
1152   #  eerror "Error: can not write to ${DPKG_DATABASE}, can not log dpkg information." ; eend 1
1153   #  bailout 14
1154   #fi
1155
1156   if ! [ -r "$DPKG_LIST" ] ; then
1157      eerror "Error reading $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT" ; eend 1
1158      bailout 14
1159   else
1160      einfo "Logging $DPKG_LIST to database $DPKG_DATABASE"
1161      eindent
1162
1163      if DB_INFO=$("$DPKG_DBSCRIPT" $DPKG_DBOPTIONS 2>&1) ; then
1164        einfo "$DB_INFO"
1165        eend 0
1166      else
1167        eerror "$DB_INFO"
1168        eend 1
1169      fi
1170
1171      eoutdent
1172   fi
1173
1174 fi
1175 }
1176 # }}}
1177
1178 # finalize {{{
1179 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
1180 log "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]"
1181
1182 dpkg_to_db # make sure we catch the last log line as well, therefore execute between log + einfo
1183
1184 einfo "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]" ; eend 0
1185 bailout 0
1186 # }}}
1187
1188 ## END OF FILE #################################################################
1189 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=3