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