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