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 ################################################################################
11 # some misc and global stuff {{{
15 # define function getfilesize before "set -e"
16 if stat --help >/dev/null 2>&1; then
17 getfilesize='stat -c %s' # GNU stat
19 getfilesize='stat -f %z' # BSD stat
26 GRML_LIVE_VERSION='0.12.1'
29 SOURCES_LIST_FILE='/etc/grml/fai/apt/sources.list'
30 ADDONS_LIST_FILE='/boot/isolinux/addons_list.cfg'
33 # usage information {{{
37 $PN - build process script for generating a (grml based) Linux Live-ISO
39 Usage: $PN [options, see as follows]
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
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
67 $PN -c GRMLBASE,GRML_MEDIUM,I386 -o /dev/shm/grml
68 $PN -c GRMLBASE,GRML_SMALL,REMOVE_DOCS,I386 -g grml-small -v 1.0
69 $PN -c GRMLBASE,GRML_FULL,I386 -i grml_0.0-1.iso -v 0.0-1
70 $PN -c GRMLBASE,GRML_FULL,I386 -s sid -V -r 'grml-live rocks'
72 More details: man grml-live + /usr/share/doc/grml-live/grml-live.html
73 http://grml.org/grml-live/
75 Please send your bug reports and feedback to the grml-team: http://grml.org/bugs/
79 # make sure it's possible to get usage information without being
80 # root or actually executing the script
81 if [ "$1" = '-h' -o "$1" = '--help' ] ; then
83 [ "$(id -u 2>/dev/null)" != 0 ] && echo "Please notice that this script requires root permissions."
88 # some runtime checks {{{
89 # we need root permissions for the build-process:
90 if [ "$(id -u 2>/dev/null)" != 0 ] ; then
91 echo "Error: please run this script with uid 0 (root)." >&2
95 if [ -r /var/run/fai/FAI_INSTALLATION_IN_PROGRESS ] ; then
96 echo "/usr/sbin/fai already running or was aborted before.">&2
97 echo "You may remove /var/run/fai/FAI_INSTALLATION_IN_PROGRESS and try again.">&2
102 if [ -r /var/run/fai/fai_softupdate_is_running ] ; then
103 echo "/usr/sbin/fai softupdate already running or was aborted before.">&2
104 echo "You may remove /var/run/fai/fai_softupdate_is_running and try again.">&2
109 # lsb-functions and configuration stuff {{{
110 # make sure they are not set by default
118 if [ -r /etc/grml/lsb-functions ] ; then
119 . /etc/grml/lsb-functions
121 einfo() { echo " [*] $*" ;}
122 eerror() { echo " [!] $*">&2 ;}
123 ewarn() { echo " [x] $*" ;}
125 eindent() { return 0 ;}
126 eoutdent() { return 0 ;}
129 # source main configuration file:
130 LIVE_CONF=/etc/grml/grml-live.conf
136 rm -f /var/run/fai/fai_softupdate_is_running \
137 /var/run/fai/FAI_INSTALLATION_IN_PROGRESS
138 [ -n "$SQUASHFS_STDERR" ] && rm -rf "$SQUASHFS_STDERR"
139 [ -n "$MIRROR_DIRECTORY" ] && umount "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
140 [ -n "$1" ] && EXIT="$1" || EXIT="1"
141 [ -n "$2" ] && eerror "$2">&2
142 log "------------------------------------------------------------------------------"
145 trap bailout 1 2 3 3 6 9 14 15
149 [ -n "$LOGFILE" ] || LOGFILE=/var/log/grml-live.log
151 chown root:adm $LOGFILE
155 # some important functions {{{
158 # usage: log "string to log"
159 log() { echo "$*" >> $LOGFILE ; }
161 # cut string at character number int = $1
162 # usage: cut_string 5 "1234567890" will output "12345"
164 [ -n "$2" ] || return 1
165 echo "$2" | head -c "$1"; echo -ne "\n"
168 # prepend int = $1 spaces before string = $2
169 # usage: extend_string_begin 5 "123" will output " 123"
170 extend_string_begin() {
171 [ -n "$2" ] || return 1
172 local COUNT="$(echo $2 | wc -c)"
173 local FILL="$(expr $COUNT - $1)"
174 while [ "$FILL" -gt 1 ] ; do
176 local FILL=$(expr $FILL - 1)
178 while [ "$FILL" -lt 1 ] ; do
180 local FILL=$(expr $FILL + 1)
182 echo "$2" | head -c "$1"; echo -ne "\n"
185 # append int = $1 spaces to string = $2
186 # usage: extend_string_begin 5 "123" will output "123 "
187 extend_string_end() {
188 [ -n "$2" ] || return 1
189 echo -n "$2" | head -c "$1"
190 local COUNT="$(echo $2 | wc -c)"
191 local FILL="$(expr $COUNT - $1)"
192 while [ "$FILL" -gt 1 ] ; do
194 local FILL=$(expr $FILL - 1)
196 while [ "$FILL" -lt 1 ] ; do
198 local FILL=$(expr $FILL + 1)
204 # read local (non-packaged) configuration {{{
205 LOCAL_CONFIG=/etc/grml/grml-live.local
206 if [ -r "$LOCAL_CONFIG" ] ; then
207 log "Sourcing $LOCAL_CONFIG"
210 log "No $LOCAL_CONFIG found, not sourcing it"
215 # command line parsing {{{
216 while getopts "a:C:c:d:g:i:I:o:r:s:t:v:bBFnquVz" opt; do
221 c) CLASSES="$OPTARG" ;;
222 C) CONFIG="$OPTARG" ;;
224 g) GRML_NAME="$OPTARG" ;;
225 i) ISO_NAME="$OPTARG" ;;
226 I) CHROOT_INSTALL="$OPTARG" ;;
228 o) OUTPUT="$OPTARG" ;;
229 q) SKIP_MKSQUASHFS=1 ;;
230 r) RELEASENAME="$OPTARG" ;;
231 s) SUITE="$OPTARG" ;;
232 t) TEMPLATE_DIRECTORY="$OPTARG";;
233 v) VERSION="$OPTARG" ;;
237 z) SQUASHFS_ZLIB="true" ;;
238 ?) echo "invalid option -$OPTARG" >&2; bailout 1 ;;
241 shift $(($OPTIND - 1)) # set ARGV to the first not parsed commandline parameter
244 # assume sane defaults (if not set already) {{{
245 [ -n "$ARCH" ] || ARCH="$(dpkg --print-architecture)"
246 [ -n "$BOOT_METHOD" ] || BOOT_METHOD='isolinux'
247 [ -n "$CLASSES" ] || CLASSES="GRMLBASE,GRML_MEDIUM,I386"
248 [ -n "$DATE" ] || DATE="$(date +%Y-%m-%d)"
249 [ -n "$DISTRI_INFO" ] || DISTRI_INFO='Grml - Live Linux for system administrators '
250 [ -n "$DISTRI_NAME" ] || DISTRI_NAME="grml"
251 [ -n "$DISTRI_SPLASH" ] || DISTRI_SPLASH='grml.png'
252 [ -n "$FORCE_ISO_REBUILD" ] || FORCE_ISO_REBUILD="false"
253 [ -n "$GRML_FAI_CONFIG" ] || GRML_FAI_CONFIG='/etc/grml/fai'
254 [ -n "$GRML_NAME" ] || GRML_NAME='grml'
255 [ -n "$HOSTNAME" ] || HOSTNAME='grml'
256 [ -n "$HYBRID_METHOD" ] || HYBRID_METHOD='manifold'
257 [ -n "$NFSROOT_CONF" ] || NFSROOT_CONF='/etc/grml/fai/make-fai-nfsroot.conf'
258 [ -n "$RELEASENAME" ] || RELEASENAME='grml-live rocks'
259 [ -n "$SQUASHFS_EXCLUDES_FILE " ] || SQUASHFS_EXCLUDES_FILE='/etc/grml/fai/squashfs-excludes'
260 [ -n "$SUITE" ] || SUITE='lenny'
261 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
262 [ -n "$USERNAME" ] || USERNAME='grml'
263 [ -n "$VERSION" ] || VERSION='0.0.1'
264 [ -n "$WINDOWS_BINARIES" ] || WINDOWS_BINARIES='http://the.earth.li/~sgtatham/putty/latest/x86/'
266 # output specific stuff, depends on $OUTPUT (iff not set):
267 [ -n "$OUTPUT" ] || OUTPUT='/grml/grml-live'
268 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
269 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
270 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
273 # some misc checks before executing FAI {{{
274 [ -n "$CLASSES" ] || bailout 1 "Error: \$CLASSES unset, please set it in $LIVE_CONF or
275 specify it on the command line using the -c option."
276 [ -n "$OUTPUT" ] || bailout 1 "Error: \$OUTPUT unset, please set it in $LIVE_CONF or
277 specify it on the command line using the -o option."
279 # trim characters that are known to cause problems inside $GRML_NAME;
280 # for example isolinux does not like '-' inside the directory name
281 [ -n "$GRML_NAME" ] && export SHORT_NAME="$(echo $GRML_NAME | tr -d ',./;\- ')"
283 # export variables to have them available in fai scripts:
284 [ -n "$GRML_NAME" ] && export GRML_NAME="$GRML_NAME"
285 [ -n "$RELEASENAME" ] && export RELEASENAME="$RELEASENAME"
288 # ZERO_LOGFILE - check for backwards compatibility reasons {{{
289 # this was default behaviour until grml-live 0.9.34:
290 if [ -n "$ZERO_LOGFILE" ] ; then
291 PRESERVE_LOGFILE='' # make sure it's cleaned then
292 ewarn "Please consider disabling the \$ZERO_LOGFILE option as grml-live clears..."
293 ewarn "... the logfile $LOGFILE by default (unless \$PRESERVE_LOGFILE is set) nowadays."
298 # ask user whether the setup is ok {{{
299 if [ -z "$FORCE" ] ; then
301 echo "${PN} [${GRML_LIVE_VERSION}]: check your configuration (or use -F to force execution):"
303 echo " FAI classes: $CLASSES"
304 [ -r "$LOCAL_CONFIG" ] && echo " Local config: /etc/grml/grml-live.local"
305 [ -n "$CONFIG" ] && echo " Configuration: $CONFIG"
306 echo " main directory: $OUTPUT"
307 [ -n "$CHROOT_OUTPUT" ] && echo " Chroot target: $CHROOT_OUTPUT"
308 [ -n "$BUILD_OUTPUT" ] && echo " Build target: $BUILD_OUTPUT"
309 [ -n "$ISO_OUTPUT" ] && echo " ISO target: $ISO_OUTPUT"
310 [ -n "$GRML_NAME" ] && echo " Grml name: $GRML_NAME"
311 [ -n "$RELEASENAME" ] && echo " Release name: $RELEASENAME"
312 [ -n "$DATE" ] && echo " Build date: $DATE"
313 [ -n "$VERSION" ] && echo " Grml version: $VERSION"
314 [ -n "$SUITE" ] && echo " Debian suite: $SUITE"
315 [ -n "$ARCH" ] && echo " Architecture: $ARCH"
316 [ -n "$BOOT_METHOD" ] && echo " Boot method: $BOOT_METHOD"
317 [ -n "$HYBRID_METHOD" ] && echo " Hybrid method: $HYBRID_METHOD"
318 [ -n "$TEMPLATE_DIRECTORY" ] && echo " Template files: $TEMPLATE_DIRECTORY"
319 [ -n "$CHROOT_INSTALL" ] && echo " Install files from directory to chroot: $CHROOT_INSTALL"
320 [ -n "$BOOTID" ] && echo " Boot identifier: $BOOTID"
321 [ -n "$NO_BOOTID" ] && echo " Skipping bootid feature."
322 [ -n "$DEFAULT_BOOTOPTIONS" ] && echo " Adding default bootoptions: \"$DEFAULT_BOOTOPTIONS\""
323 [ -n "$FAI_ARGS" ] && echo " Additional arguments for FAI: $FAI_ARGS"
324 [ -n "$LOGFILE" ] && echo " Logging to file: $LOGFILE"
325 [ -n "$SQUASHFS_ZLIB" ] && echo " Using ZLIB (instead of LZMA) compression."
326 [ -n "$SQUASHFS_OPTIONS" ] && echo " Using SQUASHFS_OPTIONS ${SQUASHFS_OPTIONS}"
327 [ -n "$VERBOSE" ] && echo " Using VERBOSE mode."
328 [ -n "$UPDATE" ] && echo " Executing UPDATE instead of fresh installation."
329 [ -n "$SKIP_MKSQUASHFS" ] && echo " Skipping creation of SQUASHFS file."
330 [ -n "$SKIP_MKISOFS" ] && echo " Skipping creation of ISO file."
331 [ -n "$BUILD_ONLY" ] && echo " Executing BUILD_ONLY instead of fresh installation or UPDATE."
332 [ -n "$BUILD_DIRTY" ] && echo " Executing BUILD_DIRTY to leave chroot untouched."
334 echo -n "Is this ok for you? [y/N] "
336 if ! [ "$a" = 'y' -o "$a" = 'Y' ] ; then
337 bailout 1 "Exiting as requested."
343 # clean/zero/remove logfiles {{{
345 if [ -n "$PRESERVE_LOGFILE" ] ; then
346 echo "Preserving logfile $LOGFILE as requested via \$PRESERVE_LOGFILE"
348 # make sure it is empty (as it is e.g. appended to grml-live-db)
352 if [ -n "$ZERO_FAI_LOGFILE" ] ; then
353 if [ -d /var/log/fai/"$HOSTNAME" ] ; then
354 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last)"
355 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-dirinstall)"
356 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-softupdate)"
357 rm -f /var/log/fai/"$HOSTNAME"/last \
358 /var/log/fai/"$HOSTNAME"/last-dirinstall \
359 /var/log/fai/"$HOSTNAME"/last-softupdate
364 # source config and startup {{{
365 if [ -n "$CONFIG" ] ; then
366 if ! [ -f "$CONFIG" ] ; then
367 log "Error: $CONFIG could not be read. Exiting. [$(date)]"
368 eerror "Error: $CONFIG could not be read. Exiting." ; eend 1
371 log "Sourcing $CONFIG"
376 start_seconds=$(cut -d . -f 1 /proc/uptime)
377 log "------------------------------------------------------------------------------"
378 log "Starting grml-live [${GRML_LIVE_VERSION}] run on $(date)"
379 log "Executed grml-live command line:"
382 einfo "Logging actions to logfile $LOGFILE"
385 # on-the-fly configuration {{{
386 if [ -n "$MIRROR_DIRECTORY" ] ; then
387 if ! [ -d "$MIRROR_DIRECTORY/debian" ] ; then
388 log "Error: $MIRROR_DIRECTORY/debian does not seem to exist. Exiting. [$(date)]"
389 eerror "Error: $MIRROR_DIRECTORY/debian does not seem to exist. Exiting." ; eend 1
392 cat > "$SOURCES_LIST_FILE" << EOF
393 # NOTE: This file is *NOT* meant for manual customisation! This file is
394 # modified by grml-live and any changes might be overridden.
395 # You might consider using GRML_LIVE_SOURCES in /etc/grml/grml-live.conf*
396 # or FAI's fcopy command with /etc/grml/fai/config/files instead!
398 echo "$MIRROR_SOURCES" >> "$SOURCES_LIST_FILE"
399 if [ -n "$GRML_LIVE_SOURCES" ] ; then
400 echo "$GRML_LIVE_SOURCES" >> "$SOURCES_LIST_FILE"
402 elif [ -n "$GRML_LIVE_SOURCES" ] ; then
403 cat > "$SOURCES_LIST_FILE" << EOF
404 # NOTE: This file is *NOT* meant for manual customisation! This file is
405 # modified by grml-live and any changes might be overridden.
406 # You might consider using GRML_LIVE_SOURCES in /etc/grml/grml-live.conf*
407 # or FAI's fcopy command with /etc/grml/fai/config/files instead!
409 echo "$GRML_LIVE_SOURCES" >> "$SOURCES_LIST_FILE"
412 if [ -n "$FAI_DEBOOTSTRAP" ] ; then
413 sed "s#^FAI_DEBOOTSTRAP=.*#FAI_DEBOOTSTRAP=\"$FAI_DEBOOTSTRAP\"#" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
416 # does this suck? YES!
417 # /usr/share/debootstrap/scripts/unstable does not exist, instead use 'sid':
419 unstable) SUITE='sid' ;;
420 # make sure that we *NEVER* write any broken suite name to sources.list,
421 # otherwise we won't be able to adjust it one next (correct) execution
428 *) echo "Sorry, $SUITE is not a valid Debian suite, exiting.">&2; bailout 1 ;;
431 DIST=" etch\| stable\| lenny\| squeeze\| testing\| sid\| unstable"
432 sed "s/\(^deb .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/" "$SOURCES_LIST_FILE" | sponge "$SOURCES_LIST_FILE"
433 for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" ; do
434 if [ -n "$file" ] ; then
435 sed "s/^SUITE=.*/SUITE=\"$SUITE\"/" $file | sponge $file
436 sed "s/\(^deb .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/" "$file" | sponge "$file"
440 # notice: activate grml-live pool only if we are building against unstable:
441 if grep -qe unstable -qe sid "$SOURCES_LIST_FILE" ; then
442 grep -q 'grml-live.*main' "$SOURCES_LIST_FILE" || \
443 grep grml-stable "$SOURCES_LIST_FILE" | \
444 sed 's/grml-stable/grml-live/' >> "$SOURCES_LIST_FILE"
446 grep -q 'grml-live.*main' "$SOURCES_LIST_FILE" && \
447 sed 's/.*grml-live.*/# removed grml-live repository/' "$SOURCES_LIST_FILE" | sponge "$SOURCES_LIST_FILE"
450 for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" "$NFSROOT_CONF" ; do
451 if [ -n "$file" ] ; then
452 sed "s|^FAI_DEBOOTSTRAP=\"[a-z]* |FAI_DEBOOTSTRAP=\"$SUITE |" "$file" | sponge "$file"
456 # validate whether the specified architecture class matches the
457 # architecture (option), otherwise installation of kernel will fail
458 if echo $CLASSES | grep -qi i386 ; then
459 if ! [[ "$ARCH" == "i386" ]] ; then
460 log "Error: You specified the I386 class but are trying to build something else (AMD64?)."
461 eerror "Error: You specified the I386 class but are trying to build something else (AMD64?)."
462 eerror "Tip: Either invoke grml-live with '-a i386' or adjust the architecture class. Exiting."
466 elif echo $CLASSES | grep -qi amd64 ; then
467 if ! [[ "$ARCH" == "amd64" ]] ; then
468 log "Error: You specified the AMD64 class but are trying to build something else (I386?)."
469 eerror "Error: You specified the AMD64 class but are trying to build something else (I386?)."
470 eerror "Tip: Either invoke grml-live with '-a amd64' or adjust the architecture class. Exiting."
476 if grep -q -- 'FAI_DEBOOTSTRAP_OPTS.*--arch' "$NFSROOT_CONF" ; then
477 sed "s/--arch [a-z0-9]* /--arch $ARCH /" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
479 sed "s|^FAI_DEBOOTSTRAP_OPTS=\"\(.*\)|FAI_DEBOOTSTRAP_OPTS=\"--arch $ARCH \1|" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
483 # CHROOT_OUTPUT - execute FAI {{{
484 if [ -n "$BUILD_DIRTY" ]; then
485 log "Skipping stage 'fai' as requested via option -B"
486 ewarn "Skipping stage 'fai' as requested via option -B" ; eend 0
488 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
490 # provide inform fai about the ISO we build
491 [ -d "$CHROOT_OUTPUT/etc/" ] || mkdir -p "$CHROOT_OUTPUT/etc/"
492 echo '# This file has been generated by grml-live.' > "$CHROOT_OUTPUT/etc/grml_live_version"
493 [ -n "$GRML_LIVE_VERSION" ] && echo "GRML_LIVE_VERSION=$GRML_LIVE_VERSION" >> "$CHROOT_OUTPUT/etc/grml_live_version"
494 [ -n "$SUITE" ] && echo "SUITE=$SUITE" >> "$CHROOT_OUTPUT/etc/grml_live_version"
496 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
497 FAI_ACTION=softupdate
499 FAI_ACTION=dirinstall
502 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
503 if ! [ -r "$CHROOT_OUTPUT/etc/debian_version" ] ; then
504 log "Error: does not look like you have a working chroot. Updating/building not possible."
505 eerror "Error: does not look like you have a working chroot. Updating/building not possible. (Drop -u/-b option?)"
511 if [ -d "$CHROOT_OUTPUT/bin" -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
512 log "Skiping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already."
513 ewarn "Skiping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already." ; eend 0
515 mkdir -p "$CHROOT_OUTPUT" || bailout 5 "Problem with creating $CHROOT_OUTPUT for FAI"
517 if [ -n "${MIRROR_DIRECTORY}" ] ; then
518 mkdir -p "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
519 mount --bind "${MIRROR_DIRECTORY}" "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
522 log "Executed FAI command line:"
523 log "BUILD_ONLY=$BUILD_ONLY fai $VERBOSE -C $GRML_FAI_CONFIG -c$CLASSES -u $HOSTNAME $FAI_ACTION $CHROOT_OUTPUT $FAI_ARGS"
524 BUILD_ONLY="$BUILD_ONLY" fai $VERBOSE -C "$GRML_FAI_CONFIG" -c"$CLASSES" -u \
525 "$HOSTNAME" $FAI_ACTION "$CHROOT_OUTPUT" $FAI_ARGS | tee -a $LOGFILE
526 RC="$PIPESTATUS" # notice: bash-only
528 FORCE_ISO_REBUILD=true
530 if [ "$RC" != 0 ] ; then
531 log "Error: critical error while executing fai [exit code ${RC}]. Exiting."
532 eerror "Error: critical error while executing fai [exit code ${RC}]. Exiting." ; eend 1
535 log "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
536 echo "$GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]" > $CHROOT_OUTPUT/etc/grml_version
537 chmod 644 $CHROOT_OUTPUT/etc/grml_version
538 einfo "Rebuilding initramfs"
539 # make sure new /etc/grml_version reaches the initramfs:
540 # chroot $CHROOT_OUTPUT update-initramfs -u -t => might break when using kernel-package :(
541 chroot $CHROOT_OUTPUT update-initramfs -u -k all
545 # Remove all FAI logs from chroot if class RELEASE is used:
546 if [ -f "$CHROOT_OUTPUT"/etc/grml_fai_release ] ; then
547 rm -rf "$CHROOT_OUTPUT"/var/log/fai/*
550 # make sure we don't leave any mounts - FAI doesn't remove them always
551 umount $CHROOT_OUTPUT/proc 2>/dev/null || /bin/true
552 umount $CHROOT_OUTPUT/sys 2>/dev/null || /bin/true
553 umount $CHROOT_OUTPUT/dev/pts 2>/dev/null || /bin/true
554 umount $CHROOT_OUTPUT/dev 2>/dev/null || /bin/true
556 [ -n "$MIRROR_DIRECTORY" ] && umount "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
558 # notice: 'fai dirinstall' does not seem to exit appropriate, so:
560 CHECKLOG=/var/log/fai/$HOSTNAME/last
561 if [ -r "$CHECKLOG/software.log" ] ; then
562 # 1 errors during executing of commands
563 grep 'dpkg: error processing' $CHECKLOG/software.log >> $LOGFILE && ERROR=1
564 grep 'E: Method http has died unexpectedly!' $CHECKLOG/software.log >> $LOGFILE && ERROR=2
565 grep 'ERROR: chroot' $CHECKLOG/software.log >> $LOGFILE && ERROR=3
566 grep 'E: Failed to fetch' $CHECKLOG/software.log >> $LOGFILE && ERROR=4
567 grep 'Unable to write mmap - msync (28 No space left on device)' $CHECKLOG/software.log >> $LOGFILE && ERROR=5
570 if [ -r "$CHECKLOG/shell.log" ] ; then
571 grep 'FAILED with exit code' $CHECKLOG/shell.log >> $LOGFILE && ERROR=6
574 if [ -n "$ERROR" ] ; then
575 log "Error: there was a critical error [${ERROR}] during execution of stage 'fai dirinstall' [$(date)]"
576 eerror "Error: there was a critical error during execution of stage 'fai dirinstall'"
577 eerror "Note: check out ${CHECKLOG}/ for details. [exit ${ERROR}]"
581 log "Finished execution of stage 'fai dirinstall' [$(date)]"
582 einfo "Finished execution of stage 'fai dirinstall'"
585 einfo "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
586 log "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
592 # package validator {{{
593 CHECKLOG=/var/log/fai/$HOSTNAME/last
595 if [ -r "$CHECKLOG/package_errors.log" ] && grep -q '[a-z]' "$CHECKLOG/package_errors.log" ; then
597 if [ -n "$EXIT_ON_MISSING_PACKAGES" -a -z "$BUILD_DIRTY" ] ; then
598 eerror "The following packages were requested for installation but could not be processed:"
599 cat $CHECKLOG/package_errors.log
600 eerror "... exiting as requested via \$EXIT_ON_MISSING_PACKAGES."
604 ewarn "The following packages were requested for installation but could not be processed:"
605 cat $CHECKLOG/package_errors.log
611 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
612 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
613 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
616 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
617 if [ -d "$BUILD_OUTPUT"/boot/isolinux -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
618 log "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already."
619 ewarn "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already." ; eend 0
622 [ -d "$BUILD_OUTPUT"/boot/isolinux ] || mkdir -p "$BUILD_OUTPUT"/boot/isolinux
623 [ -d "$BUILD_OUTPUT"/boot/"${SHORT_NAME}" ] || mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"
625 if [ -z "$NO_ADDONS" ] ; then
626 [ -d "$BUILD_OUTPUT"/boot/addons ] || mkdir -p "$BUILD_OUTPUT"/boot/addons
627 if [ -r "$TEMPLATE_DIRECTORY"/boot/addons/memtest ] ; then
628 log "Installing $TEMPLATE_DIRECTORY/boot/addons/memtest"
629 cp "$TEMPLATE_DIRECTORY"/boot/addons/memtest "$BUILD_OUTPUT"/boot/addons/memtest
630 elif [ -r /boot/memtest86+.bin ] ; then
631 log "Installing /boot/memtest86+.bin"
632 cp /boot/memtest86+.bin "$BUILD_OUTPUT"/boot/addons/memtest
634 ewarn "No memtest binary found (either install package grml-live-addons or memtest86+), skipping."
635 log "No memtest binary found (either install package grml-live-addons or memtest86+), skipping."
640 # if we don't have an initrd we a) can't boot and b) there was an error
641 # during build, so check for the file:
642 INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
643 if [ -n "$INITRD" ] ; then
644 cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/initrd.gz
645 find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
647 log "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
648 eerror "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
652 KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
653 if [ -n "$KERNEL_IMAGE" ] ; then
654 cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/linux26
656 log "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
657 eerror "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
661 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
662 if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
663 log "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
664 eerror "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
668 # *always* copy files to output directory so the variables
669 # get adjusted according to the build
670 cp ${TEMPLATE_DIRECTORY}/boot/isolinux/* "$BUILD_OUTPUT"/boot/isolinux/
672 if [ -n "$NO_ADDONS" ] ; then
673 log "Skipping installation of boot addons as requested via \$NO_ADDONS."
674 einfo "Skipping installation of boot addons as requested via \$NO_ADDONS."; eend 0
676 if ! [ -d "$TEMPLATE_DIRECTORY"/boot/addons ] ; then
677 log "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)"
678 ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
680 # copy only files so we can handle bsd4grml on its own
681 for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
682 test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
685 if [ -n "$NO_ADDONS_BSD4GRML" ] ; then
686 log "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."
687 einfo "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."; eend 0
689 if [ -d "$TEMPLATE_DIRECTORY"/boot/addons/bsd4grml ] ; then
690 cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
692 log "bsd4grml addon not found, skipping therefore."
693 ewarn "bsd4grml addon not found, skipping therefore." ; eend 0
697 fi # no "$TEMPLATE_DIRECTORY"/boot/addons
700 if ! [ -d ${TEMPLATE_DIRECTORY}/boot/grub ] ; then
701 log "grub templates do not exist, skipping therefore."
702 ewarn "grub templates do not exist, skipping therefore." ; eend 0
704 if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
705 cp -a ${TEMPLATE_DIRECTORY}/boot/grub "$BUILD_OUTPUT"/boot/
708 # make sure we have recent template files available, otherwise updating
709 # the strings like $GRML_NAME and $VERSION might be out of date
710 cp ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
713 if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
714 log "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
715 eerror "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
719 [ -d "$BUILD_OUTPUT"/GRML ] || mkdir "$BUILD_OUTPUT"/GRML
720 cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/
722 # adjust boot splash information:
723 RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
724 RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
725 RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
727 if [ -r "$BUILD_OUTPUT"/GRML/grml-version ] ; then
728 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/grml-version
729 sed -i "s/%DATE%/$DATE/" "$BUILD_OUTPUT"/GRML/grml-version
732 # make sure the squashfs filename is set accordingly:
733 SQUASHFS_NAME="$GRML_NAME.squashfs"
735 if [ -n "$NO_BOOTID" ] ; then
736 log 'Skipping bootid feature as requested via $NO_BOOTID.'
737 einfo 'Skipping bootid feature as requested via $NO_BOOTID.'
739 [ -n "$BOOTID" ] || BOOTID="$(echo ${GRML_NAME}${VERSION} | tr -d ',./;\- ')"
740 [ -d "$BUILD_OUTPUT"/conf ] || mkdir "$BUILD_OUTPUT"/conf
741 einfo "Generating /conf/bootid.txt with entry ${BOOTID}."
742 log "Generating /conf/bootid.txt with entry ${BOOTID}."
743 echo "$BOOTID" > "$BUILD_OUTPUT"/conf/bootid.txt
747 # adjust all variables in the templates with the according distribution information
748 for file in "${BUILD_OUTPUT}"/boot/isolinux/*.cfg "${BUILD_OUTPUT}"/boot/isolinux/*.msg \
749 "${BUILD_OUTPUT}"/boot/grub/* ; do
750 if [ -r "${file}" ] ; then
751 sed -i "s/%ARCH%/$ARCH/g" "${file}"
752 sed -i "s/%DATE%/$DATE/g" "${file}"
753 sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/g" "${file}"
754 sed -i "s/%DISTRI_NAME%/$DISTRI_NAME/g" "${file}"
755 sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/g" "${file}"
756 sed -i "s/%GRML_NAME%/$GRML_NAME/g" "${file}"
757 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/g" "${file}"
758 sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/g" "${file}"
759 sed -i "s/%SHORT_NAME%/$SHORT_NAME/g" "${file}"
760 sed -i "s/%VERSION%/$VERSION/g" "${file}"
762 [ -n "$DEFAULT_BOOTOPTIONS" ] && sed -i "s/ boot=live/ boot=live $DEFAULT_BOOTOPTIONS/" "${file}"
764 if [ -n "$NO_BOOTID" ] ; then
765 sed -i "s/ bootid=%BOOTID%//g" "${file}" # drop bootid bootoption
767 sed -i "s/%BOOTID%/$BOOTID/g" "${file}" # adjust bootid=... argument
772 # adjust bootsplash accordingly but make sure the string has the according lenght
773 SQUASHFS_NAME="$(cut_string 20 "$SQUASHFS_NAME")"
774 SQUASHFS_NAME="$(extend_string_end 20 "$SQUASHFS_NAME")"
775 for file in f4 f5 ; do
776 if [ -r "${BUILD_OUTPUT}/boot/isolinux/${file}" ] ; then
777 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
778 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
782 # generate addon list
783 rm "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
784 for name in "${BUILD_OUTPUT}"/boot/isolinux/addon_*.cfg ; do
785 include_name=$(basename "$name")
786 echo "include $include_name" >> "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
789 if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
790 log "including grmlmain.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
791 echo "include grmlmain.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
792 echo "include default.cfg" > "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
793 echo "include menuoptions.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
794 echo "include grml.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
796 for f in "${BUILD_OUTPUT}"/boot/isolinux/submenu*.cfg ; do
797 echo "include $(basename $f)" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
800 echo "include options.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
801 if [ ! -n "$NO_ADDONS" ] ; then
802 echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
804 echo "include isoprompt.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
805 echo "include hd.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
806 echo "include hidden.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
807 else # assume we are building a custom distribution:
808 log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
809 einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
810 if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
811 log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
813 einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
817 log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
818 echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
819 [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
823 # use old style console based isolinux method only if requested:
824 if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
825 log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
826 einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
827 if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
828 einfo "include for console.cfg already foud, nothing to do."
831 log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
832 einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
833 echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
837 log 'Using graphical boot menu.'
838 if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
839 log "include for vesamenu.cfg already foud, nothing to do."
841 log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
842 echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
846 # jump back to grub from bsd4grml (/boot/grub/stage2):
849 if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
850 if [ -e "$BUILD_OUTPUT"/boot/grub/core.img ]; then
856 for file in "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 \
857 "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.cfg \
858 "$BUILD_OUTPUT"/boot/isolinux/*.cfg \
859 "$BUILD_OUTPUT"/boot/grub/grub.cfg \
860 "$BUILD_OUTPUT"/boot/grub/menu.lst ; do
861 if [ -e "$file" ] ; then
862 sed -i -e "s!%GRUB_VERSION%!$GRUB_VERSION!g" \
863 -e "s!%GRUB_LEGACY%!$GRUB_LEGACY!g" "$file"
867 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
870 if [ -e "$BUILD_OUTPUT"/boot/grub/$GRUB_LEGACY ]; then
871 sed -i "s/%GRUB_LEGACY%/$GRUB_LEGACY/g" "$BUILD_OUTPUT"/boot/grub/menu.lst
872 sed -i "s/%GRUB_LEGACY%/$GRUB_LEGACY/g" "$BUILD_OUTPUT"/boot/grub/grub.cfg
873 elif [ -e "$BUILD_OUTPUT"/boot/grub/menu.lst -a -e "$BUILD_OUTPUT"/boot/grub/grub.cfg ] ; then
874 sed -i "/%GRUB_LEGACY%/d" "$BUILD_OUTPUT"/boot/grub/menu.lst
875 sed -i "/%GRUB_LEGACY%/d" "$BUILD_OUTPUT"/boot/grub/grub.cfg
878 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot
879 if ! [ -r "$DPKG_LIST" ] ; then
880 ewarn "$DPKG_LIST could not be read, ignoring to store package information on ISO therefore."
882 einfo "Storing package list information as /GRML/${GRML_NAME}-packages.txt on ISO."
883 cp "$DPKG_LIST" "${BUILD_OUTPUT}/GRML/${GRML_NAME}-packages.txt"
887 # autostart for Windows:
888 if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
889 cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
893 if [ -n "$NO_WINDOWS_BINARIES" ] ; then
894 log "Skipping download of windows binaries as requested via \$NO_WINDOWS_BINARIES."
895 einfo "Skipping download of windows binaries as requested via \$NO_WINDOWS_BINARIES."
898 if [ -f "$BUILD_OUTPUT"/windows/putty.exe ] ; then
899 log "Skipping stage 'WINDOWS_BINARIES' as $BUILD_OUTPUT/windows exists already."
900 ewarn "Skipping stage 'WINDOWS_BINARIES' as $BUILD_OUTPUT/windows exists already." ; eend 0
902 if ! [ -d "$BUILD_OUTPUT"/windows ] ; then
903 mkdir "$BUILD_OUTPUT"/windows
904 ( cd "$BUILD_OUTPUT"/windows
905 for file in pageant plink pscp psftp putty puttygen ; do
906 wget -O ${file}.exe ${WINDOWS_BINARIES}/${file}.exe
907 md5sum ${file}.exe > ${file}.exe.md5
911 log "Finished execution of stage 'WINDOWS_BINARIES' [$(date)]"
912 einfo "Finished execution of stage 'WINDOWS_BINARIES'" ; eend 0
916 FORCE_ISO_REBUILD=true
917 einfo "Finished execution of stage 'boot'" ; eend 0
920 log 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
921 eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
925 # support installation of local files into the chroot/ISO
926 if [ -n "$CHROOT_INSTALL" ] ; then
927 if ! [ -d "$CHROOT_INSTALL" ] ; then
928 log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
929 ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
931 log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
932 einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
933 rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
935 einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
936 FORCE_ISO_REBUILD=true
940 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
941 log "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
942 ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
943 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
944 log "Skipping stage 'squashfs' as requested via option -q"
945 ewarn "Skipping stage 'squashfs' as requested via option -q" ; eend 0
947 [ -d "$BUILD_OUTPUT"/live ] || mkdir "$BUILD_OUTPUT"/live
948 # make sure we don't leave (even an empty) base.tgz:
949 [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
951 # if unconfigured default to squashfs-tools' mksquashfs binary
952 if [ -z "$SQUASHFS_BINARY" ] ; then
953 SQUASHFS_BINARY='mksquashfs'
956 if which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
957 log "Using mksquashfs binary ${SQUASHFS_BINARY}"
958 einfo "Using mksquashfs binary ${SQUASHFS_BINARY}" ; eend 0
960 log "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
961 eerror "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
965 # use sane defaults if $SQUASHFS_OPTIONS isn't set
966 if [ -z "$SQUASHFS_OPTIONS" ] ; then
967 # use blocksize 256k as this gives best result with regards to time + compression
968 SQUASHFS_OPTIONS="-b 256k"
970 # set lzma compression by default, unless -z option has been specified on command line
971 if [ -z "$SQUASHFS_ZLIB" ] ; then
972 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp lzma"
976 # support exclusion of files via exclude-file:
977 if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
978 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE"
981 # get rid of unnecessary files when building grml-small for final release:
982 if echo "$CLASSES" | grep -q GRML_SMALL ; then
983 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
987 SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
989 # informational stuff
990 [ -n "$SQUASHFS_OPTIONS" ] && SQUASHFS_INFO_MSG="$SQUASHFS_OPTIONS"
991 [ -n "$SQUASHFS_ZLIB" ] && SQUASHFS_INFO_MSG="$SQUASHFS_INFO_MSG $SQUASHFS_ZLIB"
992 [ -n "$SQUASHFS_INFO_MSG" ] && SQUASHFS_INFO_MSG="using options: $SQUASHFS_INFO_MSG"
993 einfo "Squashfs build information: running binary $SQUASHFS_BINARY $SQUASHFS_INFO_MSG"
995 log "$SQUASHFS_BINARY $CHROOT_OUTPUT/* $BUILD_OUTPUT/live/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS $SQUASHFS_ZLIB"
997 if $SQUASHFS_BINARY $CHROOT_OUTPUT/* $BUILD_OUTPUT/live/"${GRML_NAME}".squashfs \
998 -noappend $SQUASHFS_OPTIONS $SQUASHFS_ZLIB 2>"${SQUASHFS_STDERR}" ; then
999 echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/filesystem.module
1000 log "Finished execution of stage 'squashfs' [$(date)]"
1001 einfo "Finished execution of stage 'squashfs'" ; eend 0
1003 log "Error: there was a critical error executing stage 'squashfs' [$(date)]:"
1004 log "$(cat $SQUASHFS_STDERR)"
1005 eerror "Error: there was a critical error executing stage 'squashfs':"
1006 cat "${SQUASHFS_STDERR}"
1011 FORCE_ISO_REBUILD=true
1014 # create md5sum file:
1015 ( cd $BUILD_OUTPUT/GRML &&
1016 find .. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
1019 # ISO_OUTPUT - mkisofs {{{
1020 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
1021 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
1023 if [ "$BOOT_METHOD" = "isolinux" ] ; then
1024 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
1025 elif [ "$BOOT_METHOD" = "grub" ] ; then
1026 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/grub/stage2"
1027 elif [ "$BOOT_METHOD" = "grub2" ] ; then
1028 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -b boot/grub/toriboot.bin"
1031 # Just until http://bts.grml.org/grml/issue945 has been resolved.
1032 # HYBRID_METHOD defaults to manifold, so make sure the default works OOTB.
1033 if [[ $BOOT_METHOD != isolinux && ($HYBRID_METHOD = isohybrid || $HYBRID_METHOD = manifold) ]]; then
1034 log "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1035 ewarn "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1036 HYBRID_METHOD='grub2'
1040 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ] ; then
1041 log "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already."
1042 ewarn "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already." ; eend 0
1043 elif [ -n "$SKIP_MKISOFS" ] ; then
1044 log "Skipping stage 'iso build' as requested via option -n"
1045 ewarn "Skipping stage 'iso build' as requested via option -n" ; eend 0
1047 mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
1049 if $FORCE_ISO_REBUILD && ! [ -f "${ISO_OUTPUT}/${ISO_NAME}" ] ; then
1050 log "Forcing rebuild of ISO because files on ISO have been modified."
1051 einfo "Forcing rebuild of ISO because files on ISO have been modified."
1054 # support mkisofs as well as genisoimage
1055 if which mkisofs >/dev/null 2>&1; then
1057 elif which genisoimage >/dev/null 2>&1; then
1058 MKISOFS='genisoimage'
1060 log "Error: neither mkisofs nor genisoimage available - can not create ISO."
1061 eerror "Error: neither mkisofs nor genisoimage available - can not create ISO." ; eend 1
1066 if cd "$BUILD_OUTPUT" ; then
1067 if [ "$BOOT_METHOD" = "grub2" ]; then
1068 # make a 2048-byte bootsector for El Torito
1069 dd if=/dev/zero of=boot/grub/toriboot.bin bs=512 count=4 2>/dev/null
1070 # those are in 2048-byte sectors, so 1 16 matches 4 63 below
1071 echo 1 16 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -B 11 | \
1072 dd of=boot/grub/toriboot.bin conv=notrunc 2>/dev/null
1074 log "$MKISOFS -V '${GRML_NAME} ${VERSION}' -publisher 'grml-live | grml.org' -l -r -J $BOOT_ARGS -o ${ISO_OUTPUT}/${ISO_NAME} ."
1075 "$MKISOFS" -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
1076 -l -r -J $BOOT_ARGS -no-pad \
1077 -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
1078 # both of these need core.img there, so it’s easier to write it here
1079 if [ "$BOOT_METHOD" = "grub2" ] || [ "$HYBRID_METHOD" = "grub2" ]; then
1080 # must be <= 30720 bytes
1081 dd if=boot/grub/core.img of="${ISO_OUTPUT}/${ISO_NAME}" \
1082 conv=notrunc bs=512 seek=4 2>/dev/null
1085 # pad the output ISO to multiples of 256 KiB for partition table support
1086 siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
1087 cyls=$((siz / 512 / 32 / 16 + 1)) # C=$cyls H=16 S=32
1088 siz=$((cyls * 16 * 32 * 512)) # size after padding
1089 dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
1090 of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
1092 # support disabling hybrid ISO image
1093 if [ "$HYBRID_METHOD" = "disable" ] ; then\
1094 log "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1095 einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1097 # use isohybrid only on request
1098 elif [ "$HYBRID_METHOD" = "isohybrid" ] ; then
1099 if ! which isohybrid >/dev/null 2>&1 ; then
1100 bailout 12 "isohybrid binary not found - please install syslinux/syslinux-common"
1102 log "Creating hybrid ISO file with isohybrid method"
1103 einfo "Creating hybrid ISO file with isohybrid method"
1104 # Notes for consideration:
1105 # "-entry 4 -type 1c"
1106 # * using 4 as the partition number is supposed to help with BIOSes
1107 # that only support USB-Zip boot
1108 # * using 1c (i.e. hidden FAT32 LBA), instead of the default 0x17
1109 # (hidden NTFS, IIRC), as the partition type is sometimes needed
1110 # to get the BIOS even look at the partition created by isohybrid
1111 isohybrid "${ISO_OUTPUT}/${ISO_NAME}"
1114 # by default use our manifold boot method:
1116 # isoinfo is part of both mkisofs and genisoimage so we're good
1117 bootoff=$(isoinfo -l -i "${ISO_OUTPUT}/${ISO_NAME}" | \
1118 sed -n '/^.*\[ *\([0-9]*\)[] ].* ISOLINUX.BIN;1 *$/s//\1/p')
1119 if ! [ -r boot/grub/core.img ] ; then
1120 ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
1121 elif [ "${bootoff:-0}" -lt 1 ] ; then
1122 ewarn "isolinux.bin not found on the ISO file, disabling manifold boot"
1124 log "Creating hybrid ISO file with manifold method"
1125 einfo "Creating hybrid ISO file with manifold method"
1126 if [ "$HYBRID_METHOD" = "grub2" ] ; then
1127 # 512 bytes: MBR, partition table, load GRUB 2
1128 echo 4 63 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 4:0x96 -g $cyls:16:32
1130 # read only one but 2048-byte sized (scale: << 2) sector
1131 echo $bootoff $bootoff | \
1132 mksh /usr/share/grml-live/scripts/bootilnx.mksh -A -M 4:0x96 -g $cyls:16:32 -S 2
1133 fi | dd of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
1138 # generate md5sum and sha1sum of ISO if we are using class 'RELEASE':
1139 case $CLASSES in *RELEASE*)
1142 if cd $ISO_OUTPUT ; then
1143 md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
1144 touch -r ${ISO_NAME} ${ISO_NAME}.md5
1145 sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
1146 touch -r ${ISO_NAME} ${ISO_NAME}.sha1
1155 if [ "$RC" = 0 ] ; then
1156 log "Finished execution of stage 'iso build' [$(date)]"
1157 einfo "Finished execution of stage 'iso build'" ; eend 0
1159 log "Error: there was a critical error ($RC) executing stage 'iso build' [$(date)]"
1160 eerror "Error: there was a critical error executing stage 'iso build'" ; eend 1
1166 # log build information to database if grml-live-db is installed and enabled {{{
1168 if [ -d /usr/share/grml-live-db ] ; then
1171 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot:
1172 [ -n "$DPKG_DATABASE" ] || DPKG_DATABASE=/var/log/grml-live.db
1173 [ -n "$DPKG_DBSCRIPT" ] || DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
1174 [ -n "$DPKG_DBOPTIONS" ] || DPKG_DBOPTIONS="--database $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME --dpkg $DPKG_LIST"
1176 if ! [ -x "$DPKG_DBSCRIPT" ] ; then
1177 log "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information."
1178 eerror "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information." ; eend 1
1182 # disable by default for now, not sure whether really everyone is using a local db file
1183 #if ! touch "$DPKG_DATABASE" ; then
1184 # eerror "Error: can not write to ${DPKG_DATABASE}, can not log dpkg information." ; eend 1
1188 if ! [ -r "$DPKG_LIST" ] ; then
1189 log "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)"
1190 ewarn "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)" ; eend 0
1192 einfo "Logging $DPKG_LIST to database $DPKG_DATABASE"
1193 log "Logging $DPKG_LIST to database $DPKG_DATABASE"
1194 log "Executing $DPKG_DBSCRIPT $DPKG_DBOPTIONS"
1197 if DB_INFO=$("$DPKG_DBSCRIPT" $DPKG_DBOPTIONS 2>&1) ; then
1213 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
1214 log "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]"
1216 dpkg_to_db # make sure we catch the last log line as well, therefore execute between log + einfo
1218 einfo "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]" ; eend 0
1222 ## END OF FILE #################################################################
1223 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=3