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
23 # disable for now since it seems to cause some problems
27 GRML_LIVE_VERSION='0.14.1'
30 SOURCES_LIST_FILE='/etc/grml/fai/apt/sources.list'
31 ADDONS_LIST_FILE='/boot/isolinux/addons_list.cfg'
34 # usage information {{{
38 $PN - build process script for generating a (grml based) Linux Live-ISO
40 Usage: $PN [options, see as follows]
42 -a <architecture> architecture; available values: i386 and amd64
43 -b build the ISO without updating the chroot via FAI
44 -B build the ISO without touching the chroot (skips cleanup)
45 -c <classe[s]> classes to be used for building the ISO via FAI
46 -C <configfile> configuration file for grml-live
47 -d <date> use specified date instead of build time as date of release
48 -F force execution without prompting
49 -g <grml_name> set the grml flavour name
50 -h display short usage information and exit
51 -i <iso_name> name of ISO
52 -I <src_directory> directory which provides files that should become
53 part of the chroot/ISO
54 -n skip generation of ISO
55 -N bootstrap (build chroot) only, do not create files for ISO
56 -o <output_directory> main output directory of the build process
58 -r <release_name> release name
59 -s <suite> Debian suite; values: etch, lenny, squeeze, sid
60 -t <template_directory> place of the templates
61 -u update existing chroot instead of rebuilding it from scratch
62 -v <version_number> specify version number of the release
63 -V increase verbosity in the build process
64 -z use ZLIB instead of LZMA/XZ compression
69 $PN -c GRMLBASE,GRML_MEDIUM,I386 -o /dev/shm/grml
70 $PN -c GRMLBASE,GRML_SMALL,REMOVE_DOCS,I386 -g grml-small -v 1.0
71 $PN -c GRMLBASE,GRML_FULL,I386 -i grml_0.0-1.iso -v 0.0-1
72 $PN -c GRMLBASE,GRML_FULL,I386 -s sid -V -r 'grml-live rocks'
74 More details: man grml-live + /usr/share/doc/grml-live/grml-live.html
75 http://grml.org/grml-live/
77 Please send your bug reports and feedback to the grml-team: http://grml.org/bugs/
81 # make sure it's possible to get usage information without being
82 # root or actually executing the script
83 if [ "$1" = '-h' -o "$1" = '--help' ] ; then
85 [ "$(id -u 2>/dev/null)" != 0 ] && echo "Please notice that this script requires root permissions."
90 # some runtime checks {{{
91 # we need root permissions for the build-process:
92 if [ "$(id -u 2>/dev/null)" != 0 ] ; then
93 echo "Error: please run this script with uid 0 (root)." >&2
97 if [ -r /var/run/fai/FAI_INSTALLATION_IN_PROGRESS ] ; then
98 echo "/usr/sbin/fai already running or was aborted before.">&2
99 echo "You may remove /var/run/fai/FAI_INSTALLATION_IN_PROGRESS and try again.">&2
104 if [ -r /var/run/fai/fai_softupdate_is_running ] ; then
105 echo "/usr/sbin/fai softupdate already running or was aborted before.">&2
106 echo "You may remove /var/run/fai/fai_softupdate_is_running and try again.">&2
111 # lsb-functions and configuration stuff {{{
112 # make sure they are not set by default
121 if [ -r /etc/grml/lsb-functions ] ; then
122 . /etc/grml/lsb-functions
124 einfo() { echo " [*] $*" ;}
125 eerror() { echo " [!] $*">&2 ;}
126 ewarn() { echo " [x] $*" ;}
128 eindent() { return 0 ;}
129 eoutdent() { return 0 ;}
132 # source main configuration file:
133 LIVE_CONF=/etc/grml/grml-live.conf
137 # umount all directories {{{
139 # make sure we don't leave any mounts - FAI doesn't remove them always
140 umount $CHROOT_OUTPUT/proc 2>/dev/null || /bin/true
141 umount $CHROOT_OUTPUT/sys 2>/dev/null || /bin/true
142 umount $CHROOT_OUTPUT/dev/pts 2>/dev/null || /bin/true
143 umount $CHROOT_OUTPUT/dev 2>/dev/null || /bin/true
144 [ -n "$MIRROR_DIRECTORY" ] && umount "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
150 rm -f /var/run/fai/fai_softupdate_is_running \
151 /var/run/fai/FAI_INSTALLATION_IN_PROGRESS
152 [ -n "$SQUASHFS_STDERR" ] && rm -rf "$SQUASHFS_STDERR"
154 [ -n "$1" ] && EXIT="$1" || EXIT="1"
155 [ -n "$2" ] && eerror "$2">&2
156 log "------------------------------------------------------------------------------"
159 trap bailout 1 2 3 3 6 9 14 15
164 [ -n "$LOGFILE" ] || LOGFILE=/var/log/grml-live.log
166 chown root:adm $LOGFILE
170 # some important functions {{{
173 # usage: log "string to log"
174 log() { echo "$*" >> $LOGFILE ; }
176 # cut string at character number int = $1
177 # usage: cut_string 5 "1234567890" will output "12345"
179 [ -n "$2" ] || return 1
180 echo "$2" | head -c "$1"; echo -ne "\n"
183 # prepend int = $1 spaces before string = $2
184 # usage: extend_string_begin 5 "123" will output " 123"
185 extend_string_begin() {
186 [ -n "$2" ] || return 1
187 local COUNT="$(echo $2 | wc -c)"
188 local FILL="$(expr $COUNT - $1)"
189 while [ "$FILL" -gt 1 ] ; do
191 local FILL=$(expr $FILL - 1)
193 while [ "$FILL" -lt 1 ] ; do
195 local FILL=$(expr $FILL + 1)
197 echo "$2" | head -c "$1"; echo -ne "\n"
200 # append int = $1 spaces to string = $2
201 # usage: extend_string_begin 5 "123" will output "123 "
202 extend_string_end() {
203 [ -n "$2" ] || return 1
204 echo -n "$2" | head -c "$1"
205 local COUNT="$(echo $2 | wc -c)"
206 local FILL="$(expr $COUNT - $1)"
207 while [ "$FILL" -gt 1 ] ; do
209 local FILL=$(expr $FILL - 1)
211 while [ "$FILL" -lt 1 ] ; do
213 local FILL=$(expr $FILL + 1)
219 # read local (non-packaged) configuration {{{
220 LOCAL_CONFIG=/etc/grml/grml-live.local
221 if [ -r "$LOCAL_CONFIG" ] ; then
222 log "Sourcing $LOCAL_CONFIG"
225 log "No $LOCAL_CONFIG found, not sourcing it"
230 # command line parsing {{{
231 while getopts "a:C:c:d:g:i:I:o:r:s:t:v:bBFnNquVz" opt; do
236 c) CLASSES="$OPTARG" ;;
237 C) CONFIG="$OPTARG" ;;
239 g) GRML_NAME="$OPTARG" ;;
240 i) ISO_NAME="$OPTARG" ;;
241 I) CHROOT_INSTALL="$OPTARG" ;;
243 N) BOOTSTRAP_ONLY=1; SKIP_MKISOFS=1; SKIP_MKSQUASHFS=1 ;;
244 o) OUTPUT="$OPTARG" ;;
245 q) SKIP_MKSQUASHFS=1 ;;
246 r) RELEASENAME="$OPTARG" ;;
247 s) SUITE="$OPTARG" ;;
248 t) TEMPLATE_DIRECTORY="$OPTARG";;
249 v) VERSION="$OPTARG" ;;
253 z) SQUASHFS_ZLIB=1 ;;
254 ?) echo "invalid option -$OPTARG" >&2; bailout 1 ;;
257 shift $(($OPTIND - 1)) # set ARGV to the first not parsed commandline parameter
260 # assume sane defaults (if not set already) {{{
261 [ -n "$ARCH" ] || ARCH="$(dpkg --print-architecture)"
262 [ -n "$BOOT_METHOD" ] || BOOT_METHOD='isolinux'
263 [ -n "$CLASSES" ] || CLASSES="GRMLBASE,GRML_MEDIUM,I386"
264 [ -n "$DATE" ] || DATE="$(date +%Y-%m-%d)"
265 [ -n "$DISTRI_INFO" ] || DISTRI_INFO='Grml - Live Linux for system administrators '
266 [ -n "$DISTRI_NAME" ] || DISTRI_NAME="grml"
267 [ -n "$DISTRI_SPLASH" ] || DISTRI_SPLASH='grml.png'
268 [ -n "$FORCE_ISO_REBUILD" ] || FORCE_ISO_REBUILD="false"
269 [ -n "$GRML_FAI_CONFIG" ] || GRML_FAI_CONFIG='/etc/grml/fai'
270 [ -n "$GRML_NAME" ] || GRML_NAME='grml'
271 [ -n "$HOSTNAME" ] || HOSTNAME='grml'
272 [ -n "$HYBRID_METHOD" ] || HYBRID_METHOD='manifold'
273 [ -n "$NFSROOT_CONF" ] || NFSROOT_CONF='/etc/grml/fai/make-fai-nfsroot.conf'
274 [ -n "$RELEASENAME" ] || RELEASENAME='grml-live rocks'
275 [ -n "$SQUASHFS_EXCLUDES_FILE " ] || SQUASHFS_EXCLUDES_FILE='/etc/grml/fai/squashfs-excludes'
276 [ -n "$SUITE" ] || SUITE='squeeze'
277 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
278 [ -n "$USERNAME" ] || USERNAME='grml'
279 [ -n "$VERSION" ] || VERSION='0.0.1'
280 [ -n "$WINDOWS_BINARIES" ] || WINDOWS_BINARIES='http://the.earth.li/~sgtatham/putty/latest/x86/'
282 # output specific stuff, depends on $OUTPUT (iff not set):
283 [ -n "$OUTPUT" ] || OUTPUT='/grml/grml-live'
284 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
285 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
286 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
289 # some misc checks before executing FAI {{{
290 [ -n "$CLASSES" ] || bailout 1 "Error: \$CLASSES unset, please set it in $LIVE_CONF or
291 specify it on the command line using the -c option."
292 [ -n "$OUTPUT" ] || bailout 1 "Error: \$OUTPUT unset, please set it in $LIVE_CONF or
293 specify it on the command line using the -o option."
295 # trim characters that are known to cause problems inside $GRML_NAME;
296 # for example isolinux does not like '-' inside the directory name
297 [ -n "$GRML_NAME" ] && export SHORT_NAME="$(echo $GRML_NAME | tr -d ',./;\- ')"
299 # export variables to have them available in fai scripts:
300 [ -n "$GRML_NAME" ] && export GRML_NAME="$GRML_NAME"
301 [ -n "$RELEASENAME" ] && export RELEASENAME="$RELEASENAME"
304 # ZERO_LOGFILE - check for backwards compatibility reasons {{{
305 # this was default behaviour until grml-live 0.9.34:
306 if [ -n "$ZERO_LOGFILE" ] ; then
307 PRESERVE_LOGFILE='' # make sure it's cleaned then
308 ewarn "Please consider disabling the \$ZERO_LOGFILE option as grml-live clears..."
309 ewarn "... the logfile $LOGFILE by default (unless \$PRESERVE_LOGFILE is set) nowadays."
314 # ask user whether the setup is ok {{{
315 if [ -z "$FORCE" ] ; then
317 echo "${PN} [${GRML_LIVE_VERSION}]: check your configuration (or use -F to force execution):"
319 echo " FAI classes: $CLASSES"
320 [ -r "$LOCAL_CONFIG" ] && echo " Local config: /etc/grml/grml-live.local"
321 [ -n "$CONFIG" ] && echo " Configuration: $CONFIG"
322 echo " main directory: $OUTPUT"
323 [ -n "$CHROOT_OUTPUT" ] && echo " Chroot target: $CHROOT_OUTPUT"
324 [ -n "$BUILD_OUTPUT" ] && echo " Build target: $BUILD_OUTPUT"
325 [ -n "$ISO_OUTPUT" ] && echo " ISO target: $ISO_OUTPUT"
326 [ -n "$GRML_NAME" ] && echo " Grml name: $GRML_NAME"
327 [ -n "$RELEASENAME" ] && echo " Release name: $RELEASENAME"
328 [ -n "$DATE" ] && echo " Build date: $DATE"
329 [ -n "$VERSION" ] && echo " Grml version: $VERSION"
330 [ -n "$SUITE" ] && echo " Debian suite: $SUITE"
331 [ -n "$ARCH" ] && echo " Architecture: $ARCH"
332 [ -n "$BOOT_METHOD" ] && echo " Boot method: $BOOT_METHOD"
333 [ -n "$HYBRID_METHOD" ] && echo " Hybrid method: $HYBRID_METHOD"
334 [ -n "$TEMPLATE_DIRECTORY" ] && echo " Template files: $TEMPLATE_DIRECTORY"
335 [ -n "$CHROOT_INSTALL" ] && echo " Install files from directory to chroot: $CHROOT_INSTALL"
336 [ -n "$BOOTID" ] && echo " Boot identifier: $BOOTID"
337 [ -n "$NO_BOOTID" ] && echo " Skipping bootid feature."
338 [ -n "$DEFAULT_BOOTOPTIONS" ] && echo " Adding default bootoptions: \"$DEFAULT_BOOTOPTIONS\""
339 [ -n "$FAI_ARGS" ] && echo " Additional arguments for FAI: $FAI_ARGS"
340 [ -n "$LOGFILE" ] && echo " Logging to file: $LOGFILE"
341 [ -n "$SQUASHFS_ZLIB" ] && echo " Using ZLIB (instead of LZMA/XZ) compression."
342 [ -n "$SQUASHFS_OPTIONS" ] && echo " Using SQUASHFS_OPTIONS ${SQUASHFS_OPTIONS}"
343 [ -n "$VERBOSE" ] && echo " Using VERBOSE mode."
344 [ -n "$UPDATE" ] && echo " Executing UPDATE instead of fresh installation."
345 if [ -n "$BOOTSTRAP_ONLY" ] ; then
346 echo " Bootstrapping only and not building (files for) ISO."
348 [ -n "$SKIP_MKSQUASHFS" ] && echo " Skipping creation of SQUASHFS file."
349 [ -n "$SKIP_MKISOFS" ] && echo " Skipping creation of ISO file."
350 [ -n "$BUILD_ONLY" ] && echo " Executing BUILD_ONLY instead of fresh installation or UPDATE."
351 [ -n "$BUILD_DIRTY" ] && echo " Executing BUILD_DIRTY to leave chroot untouched."
354 echo -n "Is this ok for you? [y/N] "
356 if ! [ "$a" = 'y' -o "$a" = 'Y' ] ; then
357 bailout 1 "Exiting as requested."
363 # clean/zero/remove logfiles {{{
365 if [ -n "$PRESERVE_LOGFILE" ] ; then
366 echo "Preserving logfile $LOGFILE as requested via \$PRESERVE_LOGFILE"
368 # make sure it is empty (as it is e.g. appended to grml-live-db)
372 if [ -n "$ZERO_FAI_LOGFILE" ] ; then
373 if [ -d /var/log/fai/"$HOSTNAME" ] ; then
374 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last)"
375 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-dirinstall)"
376 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-softupdate)"
377 rm -f /var/log/fai/"$HOSTNAME"/last \
378 /var/log/fai/"$HOSTNAME"/last-dirinstall \
379 /var/log/fai/"$HOSTNAME"/last-softupdate
384 # source config and startup {{{
385 if [ -n "$CONFIG" ] ; then
386 if ! [ -f "$CONFIG" ] ; then
387 log "Error: $CONFIG could not be read. Exiting. [$(date)]"
388 eerror "Error: $CONFIG could not be read. Exiting." ; eend 1
391 log "Sourcing $CONFIG"
396 start_seconds=$(cut -d . -f 1 /proc/uptime)
397 log "------------------------------------------------------------------------------"
398 log "Starting grml-live [${GRML_LIVE_VERSION}] run on $(date)"
399 log "Executed grml-live command line:"
402 einfo "Logging actions to logfile $LOGFILE"
405 # on-the-fly configuration {{{
406 if [ -n "$MIRROR_DIRECTORY" ] ; then
407 if ! [ -d "$MIRROR_DIRECTORY/debian" ] ; then
408 log "Error: $MIRROR_DIRECTORY/debian does not seem to exist. Exiting. [$(date)]"
409 eerror "Error: $MIRROR_DIRECTORY/debian does not seem to exist. Exiting." ; eend 1
412 cat > "$SOURCES_LIST_FILE" << EOF
413 # NOTE: This file is *NOT* meant for manual customisation! This file is
414 # modified by grml-live and any changes might be overridden.
415 # You might consider using GRML_LIVE_SOURCES in /etc/grml/grml-live.conf*
416 # or FAI's fcopy command with /etc/grml/fai/config/files instead!
418 echo "$MIRROR_SOURCES" >> "$SOURCES_LIST_FILE"
419 if [ -n "$GRML_LIVE_SOURCES" ] ; then
420 echo "$GRML_LIVE_SOURCES" >> "$SOURCES_LIST_FILE"
422 elif [ -n "$GRML_LIVE_SOURCES" ] ; then
423 cat > "$SOURCES_LIST_FILE" << EOF
424 # NOTE: This file is *NOT* meant for manual customisation! This file is
425 # modified by grml-live and any changes might be overridden.
426 # You might consider using GRML_LIVE_SOURCES in /etc/grml/grml-live.conf*
427 # or FAI's fcopy command with /etc/grml/fai/config/files instead!
429 echo "$GRML_LIVE_SOURCES" >> "$SOURCES_LIST_FILE"
432 if [ -n "$FAI_DEBOOTSTRAP" ] ; then
433 sed "s#^FAI_DEBOOTSTRAP=.*#FAI_DEBOOTSTRAP=\"$FAI_DEBOOTSTRAP\"#" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
436 # does this suck? YES!
437 # /usr/share/debootstrap/scripts/unstable does not exist, instead use 'sid':
439 unstable) SUITE='sid' ;;
440 # make sure that we *NEVER* write any broken suite name to sources.list,
441 # otherwise we won't be able to adjust it one next (correct) execution
449 *) echo "Sorry, $SUITE is not a valid Debian suite, exiting.">&2; bailout 1 ;;
452 DIST=" etch\| stable\| lenny\| squeeze\| wheezy\| testing\| sid\| unstable"
453 sed "s/\(^deb .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/" "$SOURCES_LIST_FILE" | sponge "$SOURCES_LIST_FILE"
454 for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" ; do
455 if [ -n "$file" ] ; then
456 sed "s/^SUITE=.*/SUITE=\"$SUITE\"/" $file | sponge $file
457 sed "s/\(^deb .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/" "$file" | sponge "$file"
461 # notice: activate grml-live pool only if we are building against unstable:
462 if grep -qwe unstable -qwe sid "$SOURCES_LIST_FILE" ; then
463 grep -q 'grml-live.*main' "$SOURCES_LIST_FILE" || \
464 grep grml-stable "$SOURCES_LIST_FILE" | \
465 sed 's/grml-stable/grml-live/' >> "$SOURCES_LIST_FILE"
467 grep -q 'grml-live.*main' "$SOURCES_LIST_FILE" && \
468 sed 's/.*grml-live.*/# removed grml-live repository/' "$SOURCES_LIST_FILE" | sponge "$SOURCES_LIST_FILE"
471 for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" "$NFSROOT_CONF" ; do
472 if [ -n "$file" ] ; then
473 sed "s|^FAI_DEBOOTSTRAP=\"[a-z]* |FAI_DEBOOTSTRAP=\"$SUITE |" "$file" | sponge "$file"
477 # validate whether the specified architecture class matches the
478 # architecture (option), otherwise installation of kernel will fail
479 if echo $CLASSES | grep -qi i386 ; then
480 if ! [[ "$ARCH" == "i386" ]] ; then
481 log "Error: You specified the I386 class but are trying to build something else (AMD64?)."
482 eerror "Error: You specified the I386 class but are trying to build something else (AMD64?)."
483 eerror "Tip: Either invoke grml-live with '-a i386' or adjust the architecture class. Exiting."
487 elif echo $CLASSES | grep -qi amd64 ; then
488 if ! [[ "$ARCH" == "amd64" ]] ; then
489 log "Error: You specified the AMD64 class but are trying to build something else (I386?)."
490 eerror "Error: You specified the AMD64 class but are trying to build something else (I386?)."
491 eerror "Tip: Either invoke grml-live with '-a amd64' or adjust the architecture class. Exiting."
497 if grep -q -- 'FAI_DEBOOTSTRAP_OPTS.*--arch' "$NFSROOT_CONF" ; then
498 sed "s/--arch [a-z0-9]* /--arch $ARCH /" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
500 sed "s|^FAI_DEBOOTSTRAP_OPTS=\"\(.*\)|FAI_DEBOOTSTRAP_OPTS=\"--arch $ARCH \1|" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
504 # CHROOT_OUTPUT - execute FAI {{{
505 if [ -n "$BUILD_DIRTY" ]; then
506 log "Skipping stage 'fai' as requested via option -B"
507 ewarn "Skipping stage 'fai' as requested via option -B" ; eend 0
509 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
511 # provide inform fai about the ISO we build
512 [ -d "$CHROOT_OUTPUT/etc/" ] || mkdir -p "$CHROOT_OUTPUT/etc/"
513 echo '# This file has been generated by grml-live.' > "$CHROOT_OUTPUT/etc/grml_live_version"
514 [ -n "$GRML_LIVE_VERSION" ] && echo "GRML_LIVE_VERSION=$GRML_LIVE_VERSION" >> "$CHROOT_OUTPUT/etc/grml_live_version"
515 [ -n "$SUITE" ] && echo "SUITE=$SUITE" >> "$CHROOT_OUTPUT/etc/grml_live_version"
517 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
518 FAI_ACTION=softupdate
520 FAI_ACTION=dirinstall
523 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
524 if ! [ -r "$CHROOT_OUTPUT/etc/debian_version" ] ; then
525 log "Error: does not look like you have a working chroot. Updating/building not possible."
526 eerror "Error: does not look like you have a working chroot. Updating/building not possible. (Drop -u/-b option?)"
532 if [ -d "$CHROOT_OUTPUT/bin" -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
533 log "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already."
534 ewarn "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already." ; eend 0
536 mkdir -p "$CHROOT_OUTPUT" || bailout 5 "Problem with creating $CHROOT_OUTPUT for FAI"
538 if [ -n "${MIRROR_DIRECTORY}" ] ; then
539 mkdir -p "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
540 mount --bind "${MIRROR_DIRECTORY}" "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
543 log "Executed FAI command line:"
544 log "BUILD_ONLY=$BUILD_ONLY BOOTSTRAP_ONLY=$BOOTSTRAP_ONLY fai $VERBOSE -C $GRML_FAI_CONFIG -c$CLASSES -u $HOSTNAME $FAI_ACTION $CHROOT_OUTPUT $FAI_ARGS"
545 BUILD_ONLY="$BUILD_ONLY" BOOTSTRAP_ONLY="$BOOTSTRAP_ONLY" fai $VERBOSE -C "$GRML_FAI_CONFIG" -c"$CLASSES" -u \
546 "$HOSTNAME" $FAI_ACTION "$CHROOT_OUTPUT" $FAI_ARGS | tee -a $LOGFILE
547 RC="$PIPESTATUS" # notice: bash-only
549 FORCE_ISO_REBUILD=true
551 if [ "$RC" != 0 ] ; then
552 log "Error: critical error while executing fai [exit code ${RC}]. Exiting."
553 eerror "Error: critical error while executing fai [exit code ${RC}]. Exiting." ; eend 1
556 log "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
557 echo "$GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]" > $CHROOT_OUTPUT/etc/grml_version
558 chmod 644 $CHROOT_OUTPUT/etc/grml_version
559 einfo "Rebuilding initramfs"
560 # make sure new /etc/grml_version reaches initramfs, iterate over all
561 # present kernel versions (note: we can't really handle more than one
562 # kernel version anyway right now)
563 # chroot $CHROOT_OUTPUT update-initramfs -u -t => might break when using kernel-package :(
564 for initrd in "$(basename $CHROOT_OUTPUT/boot/vmlinuz-*)" ; do
565 chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -c
570 # Remove all FAI logs from chroot if class RELEASE is used:
571 if [ -f "$CHROOT_OUTPUT"/etc/grml_fai_release ] ; then
572 rm -rf "$CHROOT_OUTPUT"/var/log/fai/*
573 rm -f "$CHROOT_OUTPUT"/var/log/install_packages.list
578 # notice: 'fai dirinstall' does not seem to exit appropriate, so:
580 CHECKLOG=/var/log/fai/$HOSTNAME/last
581 if [ -r "$CHECKLOG/software.log" ] ; then
582 # 1 errors during executing of commands
583 grep 'dpkg: error processing' $CHECKLOG/software.log >> $LOGFILE && ERROR=1
584 grep 'E: Method http has died unexpectedly!' $CHECKLOG/software.log >> $LOGFILE && ERROR=2
585 grep 'ERROR: chroot' $CHECKLOG/software.log >> $LOGFILE && ERROR=3
586 grep 'E: Failed to fetch' $CHECKLOG/software.log >> $LOGFILE && ERROR=4
587 grep 'Unable to write mmap - msync (28 No space left on device)' $CHECKLOG/software.log >> $LOGFILE && ERROR=5
590 if [ -r "$CHECKLOG/shell.log" ] ; then
591 grep 'FAILED with exit code' $CHECKLOG/shell.log >> $LOGFILE && ERROR=6
594 if [ -n "$ERROR" ] ; then
595 log "Error: there was a critical error [${ERROR}] during execution of stage 'fai dirinstall' [$(date)]"
596 eerror "Error: there was a critical error during execution of stage 'fai dirinstall'"
597 eerror "Note: check out ${CHECKLOG}/ for details. [exit ${ERROR}]"
601 log "Finished execution of stage 'fai dirinstall' [$(date)]"
602 einfo "Finished execution of stage 'fai dirinstall'"
605 einfo "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
606 log "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
612 # package validator {{{
613 CHECKLOG=/var/log/fai/$HOSTNAME/last
615 if [ -r "$CHECKLOG/package_errors.log" ] && grep -q '[a-z]' "$CHECKLOG/package_errors.log" ; then
617 if [ -n "$EXIT_ON_MISSING_PACKAGES" -a -z "$BUILD_DIRTY" ] ; then
618 eerror "The following packages were requested for installation but could not be processed:"
619 cat $CHECKLOG/package_errors.log
620 eerror "... exiting as requested via \$EXIT_ON_MISSING_PACKAGES."
624 ewarn "The following packages were requested for installation but could not be processed:"
625 cat $CHECKLOG/package_errors.log
631 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
632 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
633 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
636 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
637 if [ -n "$BOOTSTRAP_ONLY" ] ; then
638 log "Skipping stage 'boot' as building with bootstrap only."
639 ewarn "Skipping stage 'boot' as building with bootstrap only." ; eend 0
641 if [ -d "$BUILD_OUTPUT"/boot/isolinux -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
642 log "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already."
643 ewarn "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already." ; eend 0
646 [ -d "$BUILD_OUTPUT"/boot/isolinux ] || mkdir -p "$BUILD_OUTPUT"/boot/isolinux
647 [ -d "$BUILD_OUTPUT"/boot/"${SHORT_NAME}" ] || mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"
649 if [ -z "$NO_ADDONS" ] ; then
650 [ -d "$BUILD_OUTPUT"/boot/addons ] || mkdir -p "$BUILD_OUTPUT"/boot/addons
651 if [ -r "$TEMPLATE_DIRECTORY"/boot/addons/memtest ] ; then
652 log "Installing $TEMPLATE_DIRECTORY/boot/addons/memtest"
653 cp "$TEMPLATE_DIRECTORY"/boot/addons/memtest "$BUILD_OUTPUT"/boot/addons/memtest
654 elif [ -r /boot/memtest86+.bin ] ; then
655 log "Installing /boot/memtest86+.bin"
656 cp /boot/memtest86+.bin "$BUILD_OUTPUT"/boot/addons/memtest
658 ewarn "No memtest binary found (either install package grml-live-addons or memtest86+), skipping."
659 log "No memtest binary found (either install package grml-live-addons or memtest86+), skipping."
664 # if we don't have an initrd we a) can't boot and b) there was an error
665 # during build, so check for the file:
666 INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
667 if [ -n "$INITRD" ] ; then
668 cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/initrd.gz
669 find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
671 log "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
672 eerror "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
676 KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
677 if [ -n "$KERNEL_IMAGE" ] ; then
678 cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/linux26
680 log "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
681 eerror "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
685 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
686 if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
687 log "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
688 eerror "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
692 # *always* copy files to output directory so the variables
693 # get adjusted according to the build
694 cp ${TEMPLATE_DIRECTORY}/boot/isolinux/* "$BUILD_OUTPUT"/boot/isolinux/
696 if [ -n "$NO_ADDONS" ] ; then
697 log "Skipping installation of boot addons as requested via \$NO_ADDONS."
698 einfo "Skipping installation of boot addons as requested via \$NO_ADDONS."; eend 0
700 if ! [ -d "$TEMPLATE_DIRECTORY"/boot/addons ] ; then
701 log "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)"
702 ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
704 # copy only files so we can handle bsd4grml on its own
705 for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
706 test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
709 if [ -n "$NO_ADDONS_BSD4GRML" ] ; then
710 log "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."
711 einfo "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."; eend 0
713 if [ -d "$TEMPLATE_DIRECTORY"/boot/addons/bsd4grml ] ; then
714 cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
716 log "bsd4grml addon not found, skipping therefore."
717 ewarn "bsd4grml addon not found, skipping therefore." ; eend 0
721 fi # no "$TEMPLATE_DIRECTORY"/boot/addons
724 if ! [ -d ${TEMPLATE_DIRECTORY}/boot/grub ] ; then
725 log "grub templates do not exist, skipping therefore."
726 ewarn "grub templates do not exist, skipping therefore." ; eend 0
728 if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
729 cp -a ${TEMPLATE_DIRECTORY}/boot/grub "$BUILD_OUTPUT"/boot/
732 # make sure we have recent template files available, otherwise updating
733 # the strings like $GRML_NAME and $VERSION might be out of date
734 cp ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
737 if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
738 log "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
739 eerror "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
743 [ -d "$BUILD_OUTPUT"/GRML ] || mkdir "$BUILD_OUTPUT"/GRML
744 cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/
746 # adjust boot splash information:
747 RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
748 RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
749 RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
751 if [ -r "$BUILD_OUTPUT"/GRML/grml-version ] ; then
752 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/grml-version
753 sed -i "s/%DATE%/$DATE/" "$BUILD_OUTPUT"/GRML/grml-version
756 # make sure the squashfs filename is set accordingly:
757 SQUASHFS_NAME="$GRML_NAME.squashfs"
759 if [ -n "$NO_BOOTID" ] ; then
760 log 'Skipping bootid feature as requested via $NO_BOOTID.'
761 einfo 'Skipping bootid feature as requested via $NO_BOOTID.'
763 [ -n "$BOOTID" ] || BOOTID="$(echo ${GRML_NAME}${VERSION} | tr -d ',./;\- ')"
764 [ -d "$BUILD_OUTPUT"/conf ] || mkdir "$BUILD_OUTPUT"/conf
765 einfo "Generating /conf/bootid.txt with entry ${BOOTID}."
766 log "Generating /conf/bootid.txt with entry ${BOOTID}."
767 echo "$BOOTID" > "$BUILD_OUTPUT"/conf/bootid.txt
771 # adjust all variables in the templates with the according distribution information
772 for file in "${BUILD_OUTPUT}"/boot/isolinux/*.cfg "${BUILD_OUTPUT}"/boot/isolinux/*.msg \
773 "${BUILD_OUTPUT}"/boot/grub/* ; do
774 if [ -r "${file}" ] ; then
775 sed -i "s/%ARCH%/$ARCH/g" "${file}"
776 sed -i "s/%DATE%/$DATE/g" "${file}"
777 sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/g" "${file}"
778 sed -i "s/%DISTRI_NAME%/$DISTRI_NAME/g" "${file}"
779 sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/g" "${file}"
780 sed -i "s/%GRML_NAME%/$GRML_NAME/g" "${file}"
781 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/g" "${file}"
782 sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/g" "${file}"
783 sed -i "s/%SHORT_NAME%/$SHORT_NAME/g" "${file}"
784 sed -i "s/%VERSION%/$VERSION/g" "${file}"
786 [ -n "$DEFAULT_BOOTOPTIONS" ] && sed -i "s/ boot=live/ boot=live $DEFAULT_BOOTOPTIONS/" "${file}"
788 if [ -n "$NO_BOOTID" ] ; then
789 sed -i "s/ bootid=%BOOTID%//g" "${file}" # drop bootid bootoption
791 sed -i "s/%BOOTID%/$BOOTID/g" "${file}" # adjust bootid=... argument
796 # adjust bootsplash accordingly but make sure the string has the according lenght
797 SQUASHFS_NAME="$(cut_string 20 "$SQUASHFS_NAME")"
798 SQUASHFS_NAME="$(extend_string_end 20 "$SQUASHFS_NAME")"
799 for file in f4 f5 ; do
800 if [ -r "${BUILD_OUTPUT}/boot/isolinux/${file}" ] ; then
801 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
802 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
806 # generate addon list
807 rm "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
808 for name in "${BUILD_OUTPUT}"/boot/isolinux/addon_*.cfg ; do
809 include_name=$(basename "$name")
810 echo "include $include_name" >> "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
813 if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
814 log "including grmlmain.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
815 echo "include grmlmain.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
816 echo "include default.cfg" > "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
817 echo "include menuoptions.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
818 echo "include grml.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
820 for f in "${BUILD_OUTPUT}"/boot/isolinux/submenu*.cfg ; do
821 echo "include $(basename $f)" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
824 echo "include options.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
825 if [ ! -n "$NO_ADDONS" ] ; then
826 echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
828 echo "include isoprompt.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
829 echo "include hd.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
830 echo "include hidden.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
831 else # assume we are building a custom distribution:
832 log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
833 einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
834 if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
835 log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
837 einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
841 log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
842 echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
843 [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
847 # use old style console based isolinux method only if requested:
848 if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
849 log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
850 einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
851 if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
852 einfo "include for console.cfg already foud, nothing to do."
855 log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
856 einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
857 echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
861 log 'Using graphical boot menu.'
862 if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
863 log "include for vesamenu.cfg already foud, nothing to do."
865 log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
866 echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
870 # jump back to grub from bsd4grml (/boot/grub/stage2):
873 if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
874 if [ -e "$BUILD_OUTPUT"/boot/grub/core.img ]; then
880 for file in "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 \
881 "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.cfg \
882 "$BUILD_OUTPUT"/boot/isolinux/*.cfg \
883 "$BUILD_OUTPUT"/boot/grub/grub.cfg \
884 "$BUILD_OUTPUT"/boot/grub/menu.lst ; do
885 if [ -e "$file" ] ; then
886 sed -i -e "s!%GRUB_VERSION%!$GRUB_VERSION!g" \
887 -e "s!%GRUB_LEGACY%!$GRUB_LEGACY!g" "$file"
891 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
894 if [ -e "$BUILD_OUTPUT"/boot/grub/$GRUB_LEGACY ]; then
895 sed -i "s/%GRUB_LEGACY%/$GRUB_LEGACY/g" "$BUILD_OUTPUT"/boot/grub/menu.lst
896 sed -i "s/%GRUB_LEGACY%/$GRUB_LEGACY/g" "$BUILD_OUTPUT"/boot/grub/grub.cfg
897 elif [ -e "$BUILD_OUTPUT"/boot/grub/menu.lst -a -e "$BUILD_OUTPUT"/boot/grub/grub.cfg ] ; then
898 sed -i "/%GRUB_LEGACY%/d" "$BUILD_OUTPUT"/boot/grub/menu.lst
899 sed -i "/%GRUB_LEGACY%/d" "$BUILD_OUTPUT"/boot/grub/grub.cfg
902 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot
903 if ! [ -r "$DPKG_LIST" ] ; then
904 ewarn "$DPKG_LIST could not be read, ignoring to store package information on ISO therefore."
906 einfo "Storing package list information as /GRML/${GRML_NAME}-packages.txt on ISO."
907 cp "$DPKG_LIST" "${BUILD_OUTPUT}/GRML/${GRML_NAME}-packages.txt"
911 # autostart for Windows:
912 if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
913 cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
917 if [ -n "$NO_WINDOWS_BINARIES" ] ; then
918 log "Skipping download of windows binaries as requested via \$NO_WINDOWS_BINARIES."
919 einfo "Skipping download of windows binaries as requested via \$NO_WINDOWS_BINARIES."
922 if [ -f "$BUILD_OUTPUT"/windows/putty.exe ] ; then
923 log "Skipping stage 'WINDOWS_BINARIES' as $BUILD_OUTPUT/windows exists already."
924 ewarn "Skipping stage 'WINDOWS_BINARIES' as $BUILD_OUTPUT/windows exists already." ; eend 0
926 if ! [ -d "$BUILD_OUTPUT"/windows ] ; then
927 mkdir "$BUILD_OUTPUT"/windows
928 ( cd "$BUILD_OUTPUT"/windows
929 for file in pageant plink pscp psftp putty puttygen ; do
930 wget -O ${file}.exe ${WINDOWS_BINARIES}/${file}.exe
931 md5sum ${file}.exe > ${file}.exe.md5
935 log "Finished execution of stage 'WINDOWS_BINARIES' [$(date)]"
936 einfo "Finished execution of stage 'WINDOWS_BINARIES'" ; eend 0
940 FORCE_ISO_REBUILD=true
941 einfo "Finished execution of stage 'boot'" ; eend 0
945 log 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
946 eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
950 # support installation of local files into the chroot/ISO
951 if [ -n "$CHROOT_INSTALL" ] ; then
952 if ! [ -d "$CHROOT_INSTALL" ] ; then
953 log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
954 ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
956 log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
957 einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
958 rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
960 einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
961 FORCE_ISO_REBUILD=true
965 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
966 log "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
967 ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
968 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
969 log "Skipping stage 'squashfs' as requested via option -q or -N"
970 ewarn "Skipping stage 'squashfs' as requested via option -q or -N" ; eend 0
972 [ -d "$BUILD_OUTPUT"/live ] || mkdir "$BUILD_OUTPUT"/live
973 # make sure we don't leave (even an empty) base.tgz:
974 [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
976 # if unconfigured default to squashfs-tools' mksquashfs binary
977 if [ -z "$SQUASHFS_BINARY" ] ; then
978 SQUASHFS_BINARY='mksquashfs'
981 if which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
982 log "Using mksquashfs binary ${SQUASHFS_BINARY}"
983 einfo "Using mksquashfs binary ${SQUASHFS_BINARY}" ; eend 0
985 log "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
986 eerror "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
990 # use sane defaults if $SQUASHFS_OPTIONS isn't set
991 if [ -z "$SQUASHFS_OPTIONS" ] ; then
992 # use blocksize 256k as this gives best result with regards to time + compression
993 SQUASHFS_OPTIONS="-b 256k"
995 # set lzma/xz compression by default, unless -z option has been specified on command line
996 if [ -z "$SQUASHFS_ZLIB" ] ; then
997 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp xz"
999 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp gzip"
1003 # support exclusion of files via exclude-file:
1004 if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
1005 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE"
1008 # get rid of unnecessary files when building grml-small for final release:
1009 if echo "$CLASSES" | grep -q GRML_SMALL ; then
1010 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
1014 SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
1016 # informational stuff
1017 [ -n "$SQUASHFS_OPTIONS" ] && SQUASHFS_INFO_MSG="$SQUASHFS_OPTIONS"
1018 [ -n "$SQUASHFS_INFO_MSG" ] && SQUASHFS_INFO_MSG="using options: $SQUASHFS_INFO_MSG"
1019 einfo "Squashfs build information: running binary $SQUASHFS_BINARY $SQUASHFS_INFO_MSG"
1021 log "$SQUASHFS_BINARY $CHROOT_OUTPUT/* $BUILD_OUTPUT/live/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS"
1023 if $SQUASHFS_BINARY $CHROOT_OUTPUT/* $BUILD_OUTPUT/live/"${GRML_NAME}".squashfs \
1024 -noappend $SQUASHFS_OPTIONS 2>"${SQUASHFS_STDERR}" ; then
1025 echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/filesystem.module
1026 log "Finished execution of stage 'squashfs' [$(date)]"
1027 einfo "Finished execution of stage 'squashfs'" ; eend 0
1029 log "Error: there was a critical error executing stage 'squashfs' [$(date)]:"
1030 log "$(cat $SQUASHFS_STDERR)"
1031 eerror "Error: there was a critical error executing stage 'squashfs':"
1032 cat "${SQUASHFS_STDERR}"
1037 FORCE_ISO_REBUILD=true
1040 # create md5sum file:
1041 if [ -z "$BOOTSTRAP_ONLY" ] ; then
1042 ( cd $BUILD_OUTPUT/GRML &&
1043 find .. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
1047 # ISO_OUTPUT - mkisofs {{{
1048 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
1049 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
1051 if [ "$BOOT_METHOD" = "isolinux" ] ; then
1052 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
1053 elif [ "$BOOT_METHOD" = "grub" ] ; then
1054 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/grub/stage2"
1055 elif [ "$BOOT_METHOD" = "grub2" ] ; then
1056 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -b boot/grub/toriboot.bin"
1059 # Just until http://bts.grml.org/grml/issue945 has been resolved.
1060 # HYBRID_METHOD defaults to manifold, so make sure the default works OOTB.
1061 if [[ $BOOT_METHOD != isolinux && ($HYBRID_METHOD = isohybrid || $HYBRID_METHOD = manifold) ]]; then
1062 log "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1063 ewarn "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1064 HYBRID_METHOD='grub2'
1068 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ] ; then
1069 log "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already."
1070 ewarn "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already." ; eend 0
1071 elif [ -n "$SKIP_MKISOFS" ] ; then
1072 log "Skipping stage 'iso build' as requested via option -n or -N"
1073 ewarn "Skipping stage 'iso build' as requested via option -n or -N" ; eend 0
1075 mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
1077 if $FORCE_ISO_REBUILD && ! [ -f "${ISO_OUTPUT}/${ISO_NAME}" ] ; then
1078 log "Forcing rebuild of ISO because files on ISO have been modified."
1079 einfo "Forcing rebuild of ISO because files on ISO have been modified."
1082 # support mkisofs as well as genisoimage
1083 if which mkisofs >/dev/null 2>&1; then
1085 elif which genisoimage >/dev/null 2>&1; then
1086 MKISOFS='genisoimage'
1088 log "Error: neither mkisofs nor genisoimage available - can not create ISO."
1089 eerror "Error: neither mkisofs nor genisoimage available - can not create ISO." ; eend 1
1094 if cd "$BUILD_OUTPUT" ; then
1095 if [ "$BOOT_METHOD" = "grub2" ]; then
1096 # make a 2048-byte bootsector for El Torito
1097 dd if=/dev/zero of=boot/grub/toriboot.bin bs=512 count=4 2>/dev/null
1098 # those are in 2048-byte sectors, so 1 16 matches 4 63 below
1099 echo 1 16 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -B 11 | \
1100 dd of=boot/grub/toriboot.bin conv=notrunc 2>/dev/null
1102 log "$MKISOFS -V '${GRML_NAME} ${VERSION}' -publisher 'grml-live | grml.org' -l -r -J $BOOT_ARGS -o ${ISO_OUTPUT}/${ISO_NAME} ."
1103 "$MKISOFS" -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
1104 -l -r -J $BOOT_ARGS -no-pad \
1105 -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
1106 # both of these need core.img there, so it’s easier to write it here
1107 if [ "$BOOT_METHOD" = "grub2" ] || [ "$HYBRID_METHOD" = "grub2" ]; then
1108 # must be <= 30720 bytes
1109 dd if=boot/grub/core.img of="${ISO_OUTPUT}/${ISO_NAME}" \
1110 conv=notrunc bs=512 seek=4 2>/dev/null
1113 # pad the output ISO to multiples of 256 KiB for partition table support
1114 siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
1115 cyls=$((siz / 512 / 32 / 16 + 1)) # C=$cyls H=16 S=32
1116 siz=$((cyls * 16 * 32 * 512)) # size after padding
1117 dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
1118 of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
1120 # support disabling hybrid ISO image
1121 if [ "$HYBRID_METHOD" = "disable" ] ; then\
1122 log "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1123 einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1125 # use isohybrid only on request
1126 elif [ "$HYBRID_METHOD" = "isohybrid" ] ; then
1127 if ! which isohybrid >/dev/null 2>&1 ; then
1128 bailout 12 "isohybrid binary not found - please install syslinux/syslinux-common"
1130 log "Creating hybrid ISO file with isohybrid method"
1131 einfo "Creating hybrid ISO file with isohybrid method"
1132 # Notes for consideration:
1133 # "-entry 4 -type 1c"
1134 # * using 4 as the partition number is supposed to help with BIOSes
1135 # that only support USB-Zip boot
1136 # * using 1c (i.e. hidden FAT32 LBA), instead of the default 0x17
1137 # (hidden NTFS, IIRC), as the partition type is sometimes needed
1138 # to get the BIOS even look at the partition created by isohybrid
1139 isohybrid "${ISO_OUTPUT}/${ISO_NAME}"
1142 # by default use our manifold boot method:
1144 # isoinfo is part of both mkisofs and genisoimage so we're good
1145 bootoff=$(isoinfo -l -i "${ISO_OUTPUT}/${ISO_NAME}" | \
1146 sed -n '/^.*\[ *\([0-9]*\)[] ].* ISOLINUX.BIN;1 *$/s//\1/p')
1147 if ! [ -r boot/grub/core.img ] ; then
1148 ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
1149 elif [ "${bootoff:-0}" -lt 1 ] ; then
1150 ewarn "isolinux.bin not found on the ISO file, disabling manifold boot"
1152 log "Creating hybrid ISO file with manifold method"
1153 einfo "Creating hybrid ISO file with manifold method"
1154 if [ "$HYBRID_METHOD" = "grub2" ] ; then
1155 # 512 bytes: MBR, partition table, load GRUB 2
1156 echo 4 63 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 4:0x96 -g $cyls:16:32
1158 # read only one but 2048-byte sized (scale: << 2) sector
1159 echo $bootoff $bootoff | \
1160 mksh /usr/share/grml-live/scripts/bootilnx.mksh -A -M 4:0x96 -g $cyls:16:32 -S 2
1161 fi | dd of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
1166 # generate md5sum and sha1sum of ISO if we are using class 'RELEASE':
1167 case $CLASSES in *RELEASE*)
1170 if cd $ISO_OUTPUT ; then
1171 md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
1172 touch -r ${ISO_NAME} ${ISO_NAME}.md5
1173 sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
1174 touch -r ${ISO_NAME} ${ISO_NAME}.sha1
1183 if [ "$RC" = 0 ] ; then
1184 log "Finished execution of stage 'iso build' [$(date)]"
1185 einfo "Finished execution of stage 'iso build'" ; eend 0
1187 log "Error: there was a critical error ($RC) executing stage 'iso build' [$(date)]"
1188 eerror "Error: there was a critical error executing stage 'iso build'" ; eend 1
1194 # log build information to database if grml-live-db is installed and enabled {{{
1196 if [ -d /usr/share/grml-live-db ] ; then
1199 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot:
1200 [ -n "$DPKG_DATABASE" ] || DPKG_DATABASE=/var/log/grml-live.db
1201 [ -n "$DPKG_DBSCRIPT" ] || DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
1202 [ -n "$DPKG_DBOPTIONS" ] || DPKG_DBOPTIONS="--database $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME --dpkg $DPKG_LIST"
1204 if ! [ -x "$DPKG_DBSCRIPT" ] ; then
1205 log "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information."
1206 eerror "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information." ; eend 1
1210 # disable by default for now, not sure whether really everyone is using a local db file
1211 #if ! touch "$DPKG_DATABASE" ; then
1212 # eerror "Error: can not write to ${DPKG_DATABASE}, can not log dpkg information." ; eend 1
1216 if ! [ -r "$DPKG_LIST" ] ; then
1217 log "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)"
1218 ewarn "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)" ; eend 0
1220 einfo "Logging $DPKG_LIST to database $DPKG_DATABASE"
1221 log "Logging $DPKG_LIST to database $DPKG_DATABASE"
1222 log "Executing $DPKG_DBSCRIPT $DPKG_DBOPTIONS"
1225 if DB_INFO=$("$DPKG_DBSCRIPT" $DPKG_DBOPTIONS 2>&1) ; then
1241 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
1242 log "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]"
1244 dpkg_to_db # make sure we catch the last log line as well, therefore execute between log + einfo
1246 einfo "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]" ; eend 0
1250 ## END OF FILE #################################################################
1251 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=3