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.13.2'
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/XZ 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='squeeze'
261 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
262 [ -n "$USERNAME" ] || USERNAME='grml'
263 [ -n "$VERSION" ] || VERSION='0.0.1'
264 [ -n "$WINDOWS_BINARIES" ] || WINDOWS_BINARIES='http://the.earth.li/~sgtatham/putty/latest/x86/'
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/XZ) compression."
326 [ -n "$SQUASHFS_OPTIONS" ] && echo " Using SQUASHFS_OPTIONS ${SQUASHFS_OPTIONS}"
327 [ -n "$VERBOSE" ] && echo " Using VERBOSE mode."
328 [ -n "$UPDATE" ] && echo " Executing UPDATE instead of fresh installation."
329 [ -n "$SKIP_MKSQUASHFS" ] && echo " Skipping creation of SQUASHFS file."
330 [ -n "$SKIP_MKISOFS" ] && echo " Skipping creation of ISO file."
331 [ -n "$BUILD_ONLY" ] && echo " Executing BUILD_ONLY instead of fresh installation or UPDATE."
332 [ -n "$BUILD_DIRTY" ] && echo " Executing BUILD_DIRTY to leave chroot untouched."
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
429 *) echo "Sorry, $SUITE is not a valid Debian suite, exiting.">&2; bailout 1 ;;
432 DIST=" etch\| stable\| lenny\| squeeze\| testing\| sid\| unstable"
433 sed "s/\(^deb .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/" "$SOURCES_LIST_FILE" | sponge "$SOURCES_LIST_FILE"
434 for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" ; do
435 if [ -n "$file" ] ; then
436 sed "s/^SUITE=.*/SUITE=\"$SUITE\"/" $file | sponge $file
437 sed "s/\(^deb .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/" "$file" | sponge "$file"
441 # notice: activate grml-live pool only if we are building against unstable:
442 if grep -qe unstable -qe sid "$SOURCES_LIST_FILE" ; then
443 grep -q 'grml-live.*main' "$SOURCES_LIST_FILE" || \
444 grep grml-stable "$SOURCES_LIST_FILE" | \
445 sed 's/grml-stable/grml-live/' >> "$SOURCES_LIST_FILE"
447 grep -q 'grml-live.*main' "$SOURCES_LIST_FILE" && \
448 sed 's/.*grml-live.*/# removed grml-live repository/' "$SOURCES_LIST_FILE" | sponge "$SOURCES_LIST_FILE"
451 for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" "$NFSROOT_CONF" ; do
452 if [ -n "$file" ] ; then
453 sed "s|^FAI_DEBOOTSTRAP=\"[a-z]* |FAI_DEBOOTSTRAP=\"$SUITE |" "$file" | sponge "$file"
457 # validate whether the specified architecture class matches the
458 # architecture (option), otherwise installation of kernel will fail
459 if echo $CLASSES | grep -qi i386 ; then
460 if ! [[ "$ARCH" == "i386" ]] ; then
461 log "Error: You specified the I386 class but are trying to build something else (AMD64?)."
462 eerror "Error: You specified the I386 class but are trying to build something else (AMD64?)."
463 eerror "Tip: Either invoke grml-live with '-a i386' or adjust the architecture class. Exiting."
467 elif echo $CLASSES | grep -qi amd64 ; then
468 if ! [[ "$ARCH" == "amd64" ]] ; then
469 log "Error: You specified the AMD64 class but are trying to build something else (I386?)."
470 eerror "Error: You specified the AMD64 class but are trying to build something else (I386?)."
471 eerror "Tip: Either invoke grml-live with '-a amd64' or adjust the architecture class. Exiting."
477 if grep -q -- 'FAI_DEBOOTSTRAP_OPTS.*--arch' "$NFSROOT_CONF" ; then
478 sed "s/--arch [a-z0-9]* /--arch $ARCH /" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
480 sed "s|^FAI_DEBOOTSTRAP_OPTS=\"\(.*\)|FAI_DEBOOTSTRAP_OPTS=\"--arch $ARCH \1|" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
484 # CHROOT_OUTPUT - execute FAI {{{
485 if [ -n "$BUILD_DIRTY" ]; then
486 log "Skipping stage 'fai' as requested via option -B"
487 ewarn "Skipping stage 'fai' as requested via option -B" ; eend 0
489 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
491 # provide inform fai about the ISO we build
492 [ -d "$CHROOT_OUTPUT/etc/" ] || mkdir -p "$CHROOT_OUTPUT/etc/"
493 echo '# This file has been generated by grml-live.' > "$CHROOT_OUTPUT/etc/grml_live_version"
494 [ -n "$GRML_LIVE_VERSION" ] && echo "GRML_LIVE_VERSION=$GRML_LIVE_VERSION" >> "$CHROOT_OUTPUT/etc/grml_live_version"
495 [ -n "$SUITE" ] && echo "SUITE=$SUITE" >> "$CHROOT_OUTPUT/etc/grml_live_version"
497 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
498 FAI_ACTION=softupdate
500 FAI_ACTION=dirinstall
503 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
504 if ! [ -r "$CHROOT_OUTPUT/etc/debian_version" ] ; then
505 log "Error: does not look like you have a working chroot. Updating/building not possible."
506 eerror "Error: does not look like you have a working chroot. Updating/building not possible. (Drop -u/-b option?)"
512 if [ -d "$CHROOT_OUTPUT/bin" -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
513 log "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already."
514 ewarn "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already." ; eend 0
516 mkdir -p "$CHROOT_OUTPUT" || bailout 5 "Problem with creating $CHROOT_OUTPUT for FAI"
518 if [ -n "${MIRROR_DIRECTORY}" ] ; then
519 mkdir -p "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
520 mount --bind "${MIRROR_DIRECTORY}" "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
523 log "Executed FAI command line:"
524 log "BUILD_ONLY=$BUILD_ONLY fai $VERBOSE -C $GRML_FAI_CONFIG -c$CLASSES -u $HOSTNAME $FAI_ACTION $CHROOT_OUTPUT $FAI_ARGS"
525 BUILD_ONLY="$BUILD_ONLY" fai $VERBOSE -C "$GRML_FAI_CONFIG" -c"$CLASSES" -u \
526 "$HOSTNAME" $FAI_ACTION "$CHROOT_OUTPUT" $FAI_ARGS | tee -a $LOGFILE
527 RC="$PIPESTATUS" # notice: bash-only
529 FORCE_ISO_REBUILD=true
531 if [ "$RC" != 0 ] ; then
532 log "Error: critical error while executing fai [exit code ${RC}]. Exiting."
533 eerror "Error: critical error while executing fai [exit code ${RC}]. Exiting." ; eend 1
536 log "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
537 echo "$GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]" > $CHROOT_OUTPUT/etc/grml_version
538 chmod 644 $CHROOT_OUTPUT/etc/grml_version
539 einfo "Rebuilding initramfs"
540 # make sure new /etc/grml_version reaches the initramfs:
541 # chroot $CHROOT_OUTPUT update-initramfs -u -t => might break when using kernel-package :(
542 chroot $CHROOT_OUTPUT update-initramfs -u -k all
546 # Remove all FAI logs from chroot if class RELEASE is used:
547 if [ -f "$CHROOT_OUTPUT"/etc/grml_fai_release ] ; then
548 rm -rf "$CHROOT_OUTPUT"/var/log/fai/*
551 # make sure we don't leave any mounts - FAI doesn't remove them always
552 umount $CHROOT_OUTPUT/proc 2>/dev/null || /bin/true
553 umount $CHROOT_OUTPUT/sys 2>/dev/null || /bin/true
554 umount $CHROOT_OUTPUT/dev/pts 2>/dev/null || /bin/true
555 umount $CHROOT_OUTPUT/dev 2>/dev/null || /bin/true
557 [ -n "$MIRROR_DIRECTORY" ] && umount "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
559 # notice: 'fai dirinstall' does not seem to exit appropriate, so:
561 CHECKLOG=/var/log/fai/$HOSTNAME/last
562 if [ -r "$CHECKLOG/software.log" ] ; then
563 # 1 errors during executing of commands
564 grep 'dpkg: error processing' $CHECKLOG/software.log >> $LOGFILE && ERROR=1
565 grep 'E: Method http has died unexpectedly!' $CHECKLOG/software.log >> $LOGFILE && ERROR=2
566 grep 'ERROR: chroot' $CHECKLOG/software.log >> $LOGFILE && ERROR=3
567 grep 'E: Failed to fetch' $CHECKLOG/software.log >> $LOGFILE && ERROR=4
568 grep 'Unable to write mmap - msync (28 No space left on device)' $CHECKLOG/software.log >> $LOGFILE && ERROR=5
571 if [ -r "$CHECKLOG/shell.log" ] ; then
572 grep 'FAILED with exit code' $CHECKLOG/shell.log >> $LOGFILE && ERROR=6
575 if [ -n "$ERROR" ] ; then
576 log "Error: there was a critical error [${ERROR}] during execution of stage 'fai dirinstall' [$(date)]"
577 eerror "Error: there was a critical error during execution of stage 'fai dirinstall'"
578 eerror "Note: check out ${CHECKLOG}/ for details. [exit ${ERROR}]"
582 log "Finished execution of stage 'fai dirinstall' [$(date)]"
583 einfo "Finished execution of stage 'fai dirinstall'"
586 einfo "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
587 log "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
593 # package validator {{{
594 CHECKLOG=/var/log/fai/$HOSTNAME/last
596 if [ -r "$CHECKLOG/package_errors.log" ] && grep -q '[a-z]' "$CHECKLOG/package_errors.log" ; then
598 if [ -n "$EXIT_ON_MISSING_PACKAGES" -a -z "$BUILD_DIRTY" ] ; then
599 eerror "The following packages were requested for installation but could not be processed:"
600 cat $CHECKLOG/package_errors.log
601 eerror "... exiting as requested via \$EXIT_ON_MISSING_PACKAGES."
605 ewarn "The following packages were requested for installation but could not be processed:"
606 cat $CHECKLOG/package_errors.log
612 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
613 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
614 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
617 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
618 if [ -d "$BUILD_OUTPUT"/boot/isolinux -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
619 log "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already."
620 ewarn "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already." ; eend 0
623 [ -d "$BUILD_OUTPUT"/boot/isolinux ] || mkdir -p "$BUILD_OUTPUT"/boot/isolinux
624 [ -d "$BUILD_OUTPUT"/boot/"${SHORT_NAME}" ] || mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"
626 if [ -z "$NO_ADDONS" ] ; then
627 [ -d "$BUILD_OUTPUT"/boot/addons ] || mkdir -p "$BUILD_OUTPUT"/boot/addons
628 if [ -r "$TEMPLATE_DIRECTORY"/boot/addons/memtest ] ; then
629 log "Installing $TEMPLATE_DIRECTORY/boot/addons/memtest"
630 cp "$TEMPLATE_DIRECTORY"/boot/addons/memtest "$BUILD_OUTPUT"/boot/addons/memtest
631 elif [ -r /boot/memtest86+.bin ] ; then
632 log "Installing /boot/memtest86+.bin"
633 cp /boot/memtest86+.bin "$BUILD_OUTPUT"/boot/addons/memtest
635 ewarn "No memtest binary found (either install package grml-live-addons or memtest86+), skipping."
636 log "No memtest binary found (either install package grml-live-addons or memtest86+), skipping."
641 # if we don't have an initrd we a) can't boot and b) there was an error
642 # during build, so check for the file:
643 INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
644 if [ -n "$INITRD" ] ; then
645 cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/initrd.gz
646 find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
648 log "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
649 eerror "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
653 KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
654 if [ -n "$KERNEL_IMAGE" ] ; then
655 cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/linux26
657 log "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
658 eerror "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
662 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
663 if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
664 log "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
665 eerror "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
669 # *always* copy files to output directory so the variables
670 # get adjusted according to the build
671 cp ${TEMPLATE_DIRECTORY}/boot/isolinux/* "$BUILD_OUTPUT"/boot/isolinux/
673 if [ -n "$NO_ADDONS" ] ; then
674 log "Skipping installation of boot addons as requested via \$NO_ADDONS."
675 einfo "Skipping installation of boot addons as requested via \$NO_ADDONS."; eend 0
677 if ! [ -d "$TEMPLATE_DIRECTORY"/boot/addons ] ; then
678 log "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)"
679 ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
681 # copy only files so we can handle bsd4grml on its own
682 for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
683 test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
686 if [ -n "$NO_ADDONS_BSD4GRML" ] ; then
687 log "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."
688 einfo "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."; eend 0
690 if [ -d "$TEMPLATE_DIRECTORY"/boot/addons/bsd4grml ] ; then
691 cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
693 log "bsd4grml addon not found, skipping therefore."
694 ewarn "bsd4grml addon not found, skipping therefore." ; eend 0
698 fi # no "$TEMPLATE_DIRECTORY"/boot/addons
701 if ! [ -d ${TEMPLATE_DIRECTORY}/boot/grub ] ; then
702 log "grub templates do not exist, skipping therefore."
703 ewarn "grub templates do not exist, skipping therefore." ; eend 0
705 if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
706 cp -a ${TEMPLATE_DIRECTORY}/boot/grub "$BUILD_OUTPUT"/boot/
709 # make sure we have recent template files available, otherwise updating
710 # the strings like $GRML_NAME and $VERSION might be out of date
711 cp ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
714 if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
715 log "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
716 eerror "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
720 [ -d "$BUILD_OUTPUT"/GRML ] || mkdir "$BUILD_OUTPUT"/GRML
721 cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/
723 # adjust boot splash information:
724 RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
725 RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
726 RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
728 if [ -r "$BUILD_OUTPUT"/GRML/grml-version ] ; then
729 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/grml-version
730 sed -i "s/%DATE%/$DATE/" "$BUILD_OUTPUT"/GRML/grml-version
733 # make sure the squashfs filename is set accordingly:
734 SQUASHFS_NAME="$GRML_NAME.squashfs"
736 if [ -n "$NO_BOOTID" ] ; then
737 log 'Skipping bootid feature as requested via $NO_BOOTID.'
738 einfo 'Skipping bootid feature as requested via $NO_BOOTID.'
740 [ -n "$BOOTID" ] || BOOTID="$(echo ${GRML_NAME}${VERSION} | tr -d ',./;\- ')"
741 [ -d "$BUILD_OUTPUT"/conf ] || mkdir "$BUILD_OUTPUT"/conf
742 einfo "Generating /conf/bootid.txt with entry ${BOOTID}."
743 log "Generating /conf/bootid.txt with entry ${BOOTID}."
744 echo "$BOOTID" > "$BUILD_OUTPUT"/conf/bootid.txt
748 # adjust all variables in the templates with the according distribution information
749 for file in "${BUILD_OUTPUT}"/boot/isolinux/*.cfg "${BUILD_OUTPUT}"/boot/isolinux/*.msg \
750 "${BUILD_OUTPUT}"/boot/grub/* ; do
751 if [ -r "${file}" ] ; then
752 sed -i "s/%ARCH%/$ARCH/g" "${file}"
753 sed -i "s/%DATE%/$DATE/g" "${file}"
754 sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/g" "${file}"
755 sed -i "s/%DISTRI_NAME%/$DISTRI_NAME/g" "${file}"
756 sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/g" "${file}"
757 sed -i "s/%GRML_NAME%/$GRML_NAME/g" "${file}"
758 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/g" "${file}"
759 sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/g" "${file}"
760 sed -i "s/%SHORT_NAME%/$SHORT_NAME/g" "${file}"
761 sed -i "s/%VERSION%/$VERSION/g" "${file}"
763 [ -n "$DEFAULT_BOOTOPTIONS" ] && sed -i "s/ boot=live/ boot=live $DEFAULT_BOOTOPTIONS/" "${file}"
765 if [ -n "$NO_BOOTID" ] ; then
766 sed -i "s/ bootid=%BOOTID%//g" "${file}" # drop bootid bootoption
768 sed -i "s/%BOOTID%/$BOOTID/g" "${file}" # adjust bootid=... argument
773 # adjust bootsplash accordingly but make sure the string has the according lenght
774 SQUASHFS_NAME="$(cut_string 20 "$SQUASHFS_NAME")"
775 SQUASHFS_NAME="$(extend_string_end 20 "$SQUASHFS_NAME")"
776 for file in f4 f5 ; do
777 if [ -r "${BUILD_OUTPUT}/boot/isolinux/${file}" ] ; then
778 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
779 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
783 # generate addon list
784 rm "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
785 for name in "${BUILD_OUTPUT}"/boot/isolinux/addon_*.cfg ; do
786 include_name=$(basename "$name")
787 echo "include $include_name" >> "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
790 if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
791 log "including grmlmain.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
792 echo "include grmlmain.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
793 echo "include default.cfg" > "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
794 echo "include menuoptions.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
795 echo "include grml.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
797 for f in "${BUILD_OUTPUT}"/boot/isolinux/submenu*.cfg ; do
798 echo "include $(basename $f)" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
801 echo "include options.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
802 if [ ! -n "$NO_ADDONS" ] ; then
803 echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
805 echo "include isoprompt.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
806 echo "include hd.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
807 echo "include hidden.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
808 else # assume we are building a custom distribution:
809 log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
810 einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
811 if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
812 log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
814 einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
818 log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
819 echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
820 [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
824 # use old style console based isolinux method only if requested:
825 if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
826 log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
827 einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
828 if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
829 einfo "include for console.cfg already foud, nothing to do."
832 log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
833 einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
834 echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
838 log 'Using graphical boot menu.'
839 if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
840 log "include for vesamenu.cfg already foud, nothing to do."
842 log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
843 echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
847 # jump back to grub from bsd4grml (/boot/grub/stage2):
850 if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
851 if [ -e "$BUILD_OUTPUT"/boot/grub/core.img ]; then
857 for file in "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 \
858 "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.cfg \
859 "$BUILD_OUTPUT"/boot/isolinux/*.cfg \
860 "$BUILD_OUTPUT"/boot/grub/grub.cfg \
861 "$BUILD_OUTPUT"/boot/grub/menu.lst ; do
862 if [ -e "$file" ] ; then
863 sed -i -e "s!%GRUB_VERSION%!$GRUB_VERSION!g" \
864 -e "s!%GRUB_LEGACY%!$GRUB_LEGACY!g" "$file"
868 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
871 if [ -e "$BUILD_OUTPUT"/boot/grub/$GRUB_LEGACY ]; then
872 sed -i "s/%GRUB_LEGACY%/$GRUB_LEGACY/g" "$BUILD_OUTPUT"/boot/grub/menu.lst
873 sed -i "s/%GRUB_LEGACY%/$GRUB_LEGACY/g" "$BUILD_OUTPUT"/boot/grub/grub.cfg
874 elif [ -e "$BUILD_OUTPUT"/boot/grub/menu.lst -a -e "$BUILD_OUTPUT"/boot/grub/grub.cfg ] ; then
875 sed -i "/%GRUB_LEGACY%/d" "$BUILD_OUTPUT"/boot/grub/menu.lst
876 sed -i "/%GRUB_LEGACY%/d" "$BUILD_OUTPUT"/boot/grub/grub.cfg
879 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot
880 if ! [ -r "$DPKG_LIST" ] ; then
881 ewarn "$DPKG_LIST could not be read, ignoring to store package information on ISO therefore."
883 einfo "Storing package list information as /GRML/${GRML_NAME}-packages.txt on ISO."
884 cp "$DPKG_LIST" "${BUILD_OUTPUT}/GRML/${GRML_NAME}-packages.txt"
888 # autostart for Windows:
889 if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
890 cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
894 if [ -n "$NO_WINDOWS_BINARIES" ] ; then
895 log "Skipping download of windows binaries as requested via \$NO_WINDOWS_BINARIES."
896 einfo "Skipping download of windows binaries as requested via \$NO_WINDOWS_BINARIES."
899 if [ -f "$BUILD_OUTPUT"/windows/putty.exe ] ; then
900 log "Skipping stage 'WINDOWS_BINARIES' as $BUILD_OUTPUT/windows exists already."
901 ewarn "Skipping stage 'WINDOWS_BINARIES' as $BUILD_OUTPUT/windows exists already." ; eend 0
903 if ! [ -d "$BUILD_OUTPUT"/windows ] ; then
904 mkdir "$BUILD_OUTPUT"/windows
905 ( cd "$BUILD_OUTPUT"/windows
906 for file in pageant plink pscp psftp putty puttygen ; do
907 wget -O ${file}.exe ${WINDOWS_BINARIES}/${file}.exe
908 md5sum ${file}.exe > ${file}.exe.md5
912 log "Finished execution of stage 'WINDOWS_BINARIES' [$(date)]"
913 einfo "Finished execution of stage 'WINDOWS_BINARIES'" ; eend 0
917 FORCE_ISO_REBUILD=true
918 einfo "Finished execution of stage 'boot'" ; eend 0
921 log 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
922 eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
926 # support installation of local files into the chroot/ISO
927 if [ -n "$CHROOT_INSTALL" ] ; then
928 if ! [ -d "$CHROOT_INSTALL" ] ; then
929 log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
930 ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
932 log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
933 einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
934 rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
936 einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
937 FORCE_ISO_REBUILD=true
941 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
942 log "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
943 ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
944 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
945 log "Skipping stage 'squashfs' as requested via option -q"
946 ewarn "Skipping stage 'squashfs' as requested via option -q" ; eend 0
948 [ -d "$BUILD_OUTPUT"/live ] || mkdir "$BUILD_OUTPUT"/live
949 # make sure we don't leave (even an empty) base.tgz:
950 [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
952 # if unconfigured default to squashfs-tools' mksquashfs binary
953 if [ -z "$SQUASHFS_BINARY" ] ; then
954 SQUASHFS_BINARY='mksquashfs'
957 if which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
958 log "Using mksquashfs binary ${SQUASHFS_BINARY}"
959 einfo "Using mksquashfs binary ${SQUASHFS_BINARY}" ; eend 0
961 log "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
962 eerror "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
966 # use sane defaults if $SQUASHFS_OPTIONS isn't set
967 if [ -z "$SQUASHFS_OPTIONS" ] ; then
968 # use blocksize 256k as this gives best result with regards to time + compression
969 SQUASHFS_OPTIONS="-b 256k"
971 # set lzma/xz compression by default, unless -z option has been specified on command line
972 if [ -z "$SQUASHFS_ZLIB" ] ; then
973 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp xz"
977 # support exclusion of files via exclude-file:
978 if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
979 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE"
982 # get rid of unnecessary files when building grml-small for final release:
983 if echo "$CLASSES" | grep -q GRML_SMALL ; then
984 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
988 SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
990 # informational stuff
991 [ -n "$SQUASHFS_OPTIONS" ] && SQUASHFS_INFO_MSG="$SQUASHFS_OPTIONS"
992 [ -n "$SQUASHFS_ZLIB" ] && SQUASHFS_INFO_MSG="$SQUASHFS_INFO_MSG $SQUASHFS_ZLIB"
993 [ -n "$SQUASHFS_INFO_MSG" ] && SQUASHFS_INFO_MSG="using options: $SQUASHFS_INFO_MSG"
994 einfo "Squashfs build information: running binary $SQUASHFS_BINARY $SQUASHFS_INFO_MSG"
996 log "$SQUASHFS_BINARY $CHROOT_OUTPUT/* $BUILD_OUTPUT/live/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS $SQUASHFS_ZLIB"
998 if $SQUASHFS_BINARY $CHROOT_OUTPUT/* $BUILD_OUTPUT/live/"${GRML_NAME}".squashfs \
999 -noappend $SQUASHFS_OPTIONS $SQUASHFS_ZLIB 2>"${SQUASHFS_STDERR}" ; then
1000 echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/filesystem.module
1001 log "Finished execution of stage 'squashfs' [$(date)]"
1002 einfo "Finished execution of stage 'squashfs'" ; eend 0
1004 log "Error: there was a critical error executing stage 'squashfs' [$(date)]:"
1005 log "$(cat $SQUASHFS_STDERR)"
1006 eerror "Error: there was a critical error executing stage 'squashfs':"
1007 cat "${SQUASHFS_STDERR}"
1012 FORCE_ISO_REBUILD=true
1015 # create md5sum file:
1016 ( cd $BUILD_OUTPUT/GRML &&
1017 find .. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
1020 # ISO_OUTPUT - mkisofs {{{
1021 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
1022 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
1024 if [ "$BOOT_METHOD" = "isolinux" ] ; then
1025 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
1026 elif [ "$BOOT_METHOD" = "grub" ] ; then
1027 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/grub/stage2"
1028 elif [ "$BOOT_METHOD" = "grub2" ] ; then
1029 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -b boot/grub/toriboot.bin"
1032 # Just until http://bts.grml.org/grml/issue945 has been resolved.
1033 # HYBRID_METHOD defaults to manifold, so make sure the default works OOTB.
1034 if [[ $BOOT_METHOD != isolinux && ($HYBRID_METHOD = isohybrid || $HYBRID_METHOD = manifold) ]]; then
1035 log "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1036 ewarn "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1037 HYBRID_METHOD='grub2'
1041 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ] ; then
1042 log "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already."
1043 ewarn "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already." ; eend 0
1044 elif [ -n "$SKIP_MKISOFS" ] ; then
1045 log "Skipping stage 'iso build' as requested via option -n"
1046 ewarn "Skipping stage 'iso build' as requested via option -n" ; eend 0
1048 mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
1050 if $FORCE_ISO_REBUILD && ! [ -f "${ISO_OUTPUT}/${ISO_NAME}" ] ; then
1051 log "Forcing rebuild of ISO because files on ISO have been modified."
1052 einfo "Forcing rebuild of ISO because files on ISO have been modified."
1055 # support mkisofs as well as genisoimage
1056 if which mkisofs >/dev/null 2>&1; then
1058 elif which genisoimage >/dev/null 2>&1; then
1059 MKISOFS='genisoimage'
1061 log "Error: neither mkisofs nor genisoimage available - can not create ISO."
1062 eerror "Error: neither mkisofs nor genisoimage available - can not create ISO." ; eend 1
1067 if cd "$BUILD_OUTPUT" ; then
1068 if [ "$BOOT_METHOD" = "grub2" ]; then
1069 # make a 2048-byte bootsector for El Torito
1070 dd if=/dev/zero of=boot/grub/toriboot.bin bs=512 count=4 2>/dev/null
1071 # those are in 2048-byte sectors, so 1 16 matches 4 63 below
1072 echo 1 16 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -B 11 | \
1073 dd of=boot/grub/toriboot.bin conv=notrunc 2>/dev/null
1075 log "$MKISOFS -V '${GRML_NAME} ${VERSION}' -publisher 'grml-live | grml.org' -l -r -J $BOOT_ARGS -o ${ISO_OUTPUT}/${ISO_NAME} ."
1076 "$MKISOFS" -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
1077 -l -r -J $BOOT_ARGS -no-pad \
1078 -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
1079 # both of these need core.img there, so it’s easier to write it here
1080 if [ "$BOOT_METHOD" = "grub2" ] || [ "$HYBRID_METHOD" = "grub2" ]; then
1081 # must be <= 30720 bytes
1082 dd if=boot/grub/core.img of="${ISO_OUTPUT}/${ISO_NAME}" \
1083 conv=notrunc bs=512 seek=4 2>/dev/null
1086 # pad the output ISO to multiples of 256 KiB for partition table support
1087 siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
1088 cyls=$((siz / 512 / 32 / 16 + 1)) # C=$cyls H=16 S=32
1089 siz=$((cyls * 16 * 32 * 512)) # size after padding
1090 dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
1091 of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
1093 # support disabling hybrid ISO image
1094 if [ "$HYBRID_METHOD" = "disable" ] ; then\
1095 log "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1096 einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1098 # use isohybrid only on request
1099 elif [ "$HYBRID_METHOD" = "isohybrid" ] ; then
1100 if ! which isohybrid >/dev/null 2>&1 ; then
1101 bailout 12 "isohybrid binary not found - please install syslinux/syslinux-common"
1103 log "Creating hybrid ISO file with isohybrid method"
1104 einfo "Creating hybrid ISO file with isohybrid method"
1105 # Notes for consideration:
1106 # "-entry 4 -type 1c"
1107 # * using 4 as the partition number is supposed to help with BIOSes
1108 # that only support USB-Zip boot
1109 # * using 1c (i.e. hidden FAT32 LBA), instead of the default 0x17
1110 # (hidden NTFS, IIRC), as the partition type is sometimes needed
1111 # to get the BIOS even look at the partition created by isohybrid
1112 isohybrid "${ISO_OUTPUT}/${ISO_NAME}"
1115 # by default use our manifold boot method:
1117 # isoinfo is part of both mkisofs and genisoimage so we're good
1118 bootoff=$(isoinfo -l -i "${ISO_OUTPUT}/${ISO_NAME}" | \
1119 sed -n '/^.*\[ *\([0-9]*\)[] ].* ISOLINUX.BIN;1 *$/s//\1/p')
1120 if ! [ -r boot/grub/core.img ] ; then
1121 ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
1122 elif [ "${bootoff:-0}" -lt 1 ] ; then
1123 ewarn "isolinux.bin not found on the ISO file, disabling manifold boot"
1125 log "Creating hybrid ISO file with manifold method"
1126 einfo "Creating hybrid ISO file with manifold method"
1127 if [ "$HYBRID_METHOD" = "grub2" ] ; then
1128 # 512 bytes: MBR, partition table, load GRUB 2
1129 echo 4 63 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 4:0x96 -g $cyls:16:32
1131 # read only one but 2048-byte sized (scale: << 2) sector
1132 echo $bootoff $bootoff | \
1133 mksh /usr/share/grml-live/scripts/bootilnx.mksh -A -M 4:0x96 -g $cyls:16:32 -S 2
1134 fi | dd of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
1139 # generate md5sum and sha1sum of ISO if we are using class 'RELEASE':
1140 case $CLASSES in *RELEASE*)
1143 if cd $ISO_OUTPUT ; then
1144 md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
1145 touch -r ${ISO_NAME} ${ISO_NAME}.md5
1146 sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
1147 touch -r ${ISO_NAME} ${ISO_NAME}.sha1
1156 if [ "$RC" = 0 ] ; then
1157 log "Finished execution of stage 'iso build' [$(date)]"
1158 einfo "Finished execution of stage 'iso build'" ; eend 0
1160 log "Error: there was a critical error ($RC) executing stage 'iso build' [$(date)]"
1161 eerror "Error: there was a critical error executing stage 'iso build'" ; eend 1
1167 # log build information to database if grml-live-db is installed and enabled {{{
1169 if [ -d /usr/share/grml-live-db ] ; then
1172 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot:
1173 [ -n "$DPKG_DATABASE" ] || DPKG_DATABASE=/var/log/grml-live.db
1174 [ -n "$DPKG_DBSCRIPT" ] || DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
1175 [ -n "$DPKG_DBOPTIONS" ] || DPKG_DBOPTIONS="--database $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME --dpkg $DPKG_LIST"
1177 if ! [ -x "$DPKG_DBSCRIPT" ] ; then
1178 log "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information."
1179 eerror "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information." ; eend 1
1183 # disable by default for now, not sure whether really everyone is using a local db file
1184 #if ! touch "$DPKG_DATABASE" ; then
1185 # eerror "Error: can not write to ${DPKG_DATABASE}, can not log dpkg information." ; eend 1
1189 if ! [ -r "$DPKG_LIST" ] ; then
1190 log "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)"
1191 ewarn "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)" ; eend 0
1193 einfo "Logging $DPKG_LIST to database $DPKG_DATABASE"
1194 log "Logging $DPKG_LIST to database $DPKG_DATABASE"
1195 log "Executing $DPKG_DBSCRIPT $DPKG_DBOPTIONS"
1198 if DB_INFO=$("$DPKG_DBSCRIPT" $DPKG_DBOPTIONS 2>&1) ; then
1214 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
1215 log "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]"
1217 dpkg_to_db # make sure we catch the last log line as well, therefore execute between log + einfo
1219 einfo "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]" ; eend 0
1223 ## END OF FILE #################################################################
1224 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=3