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.16.1'
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 -D <configdir> use specified configuration directory instead of /etc/grml/fai
48 -F force execution without prompting
49 -g <grml_name> set the grml flavour name
50 -h display short usage information and exit
51 -i <iso_name> name of ISO
52 -I <src_directory> directory which provides files that should become
53 part of the chroot/ISO
54 -n skip generation of ISO
55 -N bootstrap (build chroot) only, do not create files for ISO
56 -o <output_directory> main output directory of the build process
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 # don't use colors/escape sequences
122 if [ -r /lib/lsb/init-functions ] ; then
123 . /lib/lsb/init-functions
124 ! log_use_fancy_output && NOCOLORS=true
127 if [ -r /etc/grml/lsb-functions ] ; then
128 . /etc/grml/lsb-functions
130 einfo() { echo " [*] $*" ;}
131 eerror() { echo " [!] $*">&2 ;}
132 ewarn() { echo " [x] $*" ;}
134 eindent() { return 0 ;}
135 eoutdent() { return 0 ;}
138 # source main configuration file:
139 LIVE_CONF=/etc/grml/grml-live.conf
143 # umount all directories {{{
145 # make sure we don't leave any mounts - FAI doesn't remove them always
146 umount $CHROOT_OUTPUT/proc 2>/dev/null || /bin/true
147 umount $CHROOT_OUTPUT/sys 2>/dev/null || /bin/true
148 umount $CHROOT_OUTPUT/dev/pts 2>/dev/null || /bin/true
149 umount $CHROOT_OUTPUT/dev 2>/dev/null || /bin/true
150 [ -n "$MIRROR_DIRECTORY" ] && umount "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
156 rm -f /var/run/fai/fai_softupdate_is_running \
157 /var/run/fai/FAI_INSTALLATION_IN_PROGRESS
158 [ -n "$SQUASHFS_STDERR" ] && rm -rf "$SQUASHFS_STDERR"
160 [ -n "$1" ] && EXIT="$1" || EXIT="1"
161 [ -n "$2" ] && eerror "$2">&2
162 log "------------------------------------------------------------------------------"
165 trap bailout 1 2 3 3 6 9 14 15
169 # some important functions {{{
172 # usage: log "string to log"
173 log() { echo "$*" >> $LOGFILE ; }
175 # cut string at character number int = $1
176 # usage: cut_string 5 "1234567890" will output "12345"
178 [ -n "$2" ] || return 1
179 echo "$2" | head -c "$1"; echo -ne "\n"
182 # prepend int = $1 spaces before string = $2
183 # usage: extend_string_begin 5 "123" will output " 123"
184 extend_string_begin() {
185 [ -n "$2" ] || return 1
186 local COUNT="$(echo $2 | wc -c)"
187 local FILL="$(expr $COUNT - $1)"
188 while [ "$FILL" -gt 1 ] ; do
190 local FILL=$(expr $FILL - 1)
192 while [ "$FILL" -lt 1 ] ; do
194 local FILL=$(expr $FILL + 1)
196 echo "$2" | head -c "$1"; echo -ne "\n"
199 # append int = $1 spaces to string = $2
200 # usage: extend_string_begin 5 "123" will output "123 "
201 extend_string_end() {
202 [ -n "$2" ] || return 1
203 echo -n "$2" | head -c "$1"
204 local COUNT="$(echo $2 | wc -c)"
205 local FILL="$(expr $COUNT - $1)"
206 while [ "$FILL" -gt 1 ] ; do
208 local FILL=$(expr $FILL - 1)
210 while [ "$FILL" -lt 1 ] ; do
212 local FILL=$(expr $FILL + 1)
217 # Copy addonfile $1 from either
218 # * the chroot (via $2, the system path),
219 # * or from TEMPLATE_DIRECTORY/compat (if exists),
220 # * or from the host system (again, using $2),
221 # or warn about the missing file.
224 # * We assume that the chroot always has a "good" version of
225 # the file. Also it makes sources handling easier.
226 # * On unstable, we Recommend the Debian packages containing
227 # these files. The user can override them by putting his
228 # "better" version into the chroot.
229 # * On stable, the Debian packages are probably not available,
230 # or outdated, so we look in TEMPLATE_DIRECTORY/compat first, where
231 # our grml-live-compat package installs current file versions.
233 DEST="${BUILD_OUTPUT}/boot/$3"
234 if [ ! -d "${DEST}/" ]; then
237 if [ -e "$CHROOT_OUTPUT/$2/$1" ]; then
238 log "Copying $1 from chroot"
239 cp "$CHROOT_OUTPUT/$2/$1" "${DEST}/"
242 if [ -e "${TEMPLATE_DIRECTORY}/compat/$3/$1" ]; then
243 log "Copying $1 from grml-live-compat"
244 cp "${TEMPLATE_DIRECTORY}/compat/$3/$1" "${DEST}/"
247 if [ -e "$2/$1" ]; then
248 log "Copying $1 from system"
249 cp "$2/$1" "${DEST}/"
253 msg="Missing addon file: \"$1\""
254 ewarn "$msg" ; eend 1
255 log "copy_addon_file: $msg"
259 # read local (non-packaged) configuration {{{
260 LOCAL_CONFIG=/etc/grml/grml-live.local
261 if [ -r "$LOCAL_CONFIG" ] ; then
268 # command line parsing {{{
269 while getopts "a:C:c:d:D:g:i:I:o:r:s:t:v:bBFnNquVz" opt; do
274 c) CLASSES="$OPTARG" ;;
275 C) CONFIG="$OPTARG" ;;
277 D) GRML_FAI_CONFIG="$OPTARG" ;;
278 g) GRML_NAME="$OPTARG" ;;
279 i) ISO_NAME="$OPTARG" ;;
280 I) CHROOT_INSTALL="$OPTARG" ;;
282 N) BOOTSTRAP_ONLY=1; SKIP_MKISOFS=1; SKIP_MKSQUASHFS=1 ;;
283 o) OUTPUT="$OPTARG" ;;
284 q) SKIP_MKSQUASHFS=1 ;;
285 r) RELEASENAME="$OPTARG" ;;
286 s) SUITE="$OPTARG" ;;
287 t) TEMPLATE_DIRECTORY="$OPTARG";;
288 v) VERSION="$OPTARG" ;;
292 z) SQUASHFS_ZLIB=1 ;;
293 ?) echo "invalid option -$OPTARG" >&2; bailout 1 ;;
296 shift $(($OPTIND - 1)) # set ARGV to the first not parsed commandline parameter
299 # assume sane defaults (if not set already) {{{
300 [ -n "$ARCH" ] || ARCH="$(dpkg --print-architecture)"
301 [ -n "$BOOT_METHOD" ] || BOOT_METHOD='isolinux'
302 [ -n "$CLASSES" ] || CLASSES="GRMLBASE,GRML_MEDIUM,I386"
303 [ -n "$DATE" ] || DATE="$(date +%Y-%m-%d)"
304 [ -n "$DISTRI_INFO" ] || DISTRI_INFO='Grml - Live Linux for system administrators '
305 [ -n "$DISTRI_NAME" ] || DISTRI_NAME="grml"
306 [ -n "$DISTRI_SPLASH" ] || DISTRI_SPLASH='grml.png'
307 [ -n "$FORCE_ISO_REBUILD" ] || FORCE_ISO_REBUILD="false"
308 [ -n "$GRML_FAI_CONFIG" ] || GRML_FAI_CONFIG='/etc/grml/fai'
309 [ -n "$GRML_NAME" ] || GRML_NAME='grml'
310 [ -n "$HOSTNAME" ] || HOSTNAME='grml'
311 [ -n "$HYBRID_METHOD" ] || HYBRID_METHOD='manifold'
312 [ -n "$NFSROOT_CONF" ] || NFSROOT_CONF="${GRML_FAI_CONFIG}/make-fai-nfsroot.conf"
313 [ -n "$RELEASENAME" ] || RELEASENAME='grml-live rocks'
314 [ -n "$SOURCES_LIST_OUTPUT" ] || SOURCES_LIST_OUTPUT="${GRML_FAI_CONFIG}/config/files/etc/apt/sources.list/GRML_LIVE_SOURCES_LIST"
315 [ -n "$SQUASHFS_EXCLUDES_FILE" ] || SQUASHFS_EXCLUDES_FILE="${GRML_FAI_CONFIG}/config/grml/squashfs-excludes"
316 [ -n "$SUITE" ] || SUITE='squeeze'
317 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
318 [ -n "$USERNAME" ] || USERNAME='grml'
319 [ -n "$VERSION" ] || VERSION='0.0.1'
321 # output specific stuff, depends on $OUTPUT (iff not set):
322 [ -n "$OUTPUT" ] || OUTPUT='/grml/grml-live'
323 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
324 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
325 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
328 # some misc checks before executing FAI {{{
329 [ -n "$CLASSES" ] || bailout 1 "Error: \$CLASSES unset, please set it in $LIVE_CONF or
330 specify it on the command line using the -c option."
331 [ -n "$OUTPUT" ] || bailout 1 "Error: \$OUTPUT unset, please set it in $LIVE_CONF or
332 specify it on the command line using the -o option."
334 # trim characters that are known to cause problems inside $GRML_NAME;
335 # for example isolinux does not like '-' inside the directory name
336 [ -n "$GRML_NAME" ] && export SHORT_NAME="$(echo $GRML_NAME | tr -d ',./;\- ')"
338 # export variables to have them available in fai scripts:
339 [ -n "$GRML_NAME" ] && export GRML_NAME="$GRML_NAME"
340 [ -n "$RELEASENAME" ] && export RELEASENAME="$RELEASENAME"
343 # ZERO_LOGFILE - check for backwards compatibility reasons {{{
344 # this was default behaviour until grml-live 0.9.34:
345 if [ -n "$ZERO_LOGFILE" ] ; then
346 PRESERVE_LOGFILE='' # make sure it's cleaned then
347 ewarn "Please consider disabling the \$ZERO_LOGFILE option as grml-live clears..."
348 ewarn "... the logfile $LOGFILE by default (unless \$PRESERVE_LOGFILE is set) nowadays."
353 # ask user whether the setup is ok {{{
354 if [ -z "$FORCE" ] ; then
356 echo "${PN} [${GRML_LIVE_VERSION}]: check your configuration (or use -F to force execution):"
358 echo " FAI classes: $CLASSES"
359 [ -r "$LOCAL_CONFIG" ] && echo " Local config: /etc/grml/grml-live.local"
360 [ -n "$CONFIG" ] && echo " Configuration: $CONFIG"
361 [ -n "$GRML_FAI_CONFIG" ] && echo " Config directory: $GRML_FAI_CONFIG"
362 echo " main directory: $OUTPUT"
363 [ -n "$CHROOT_OUTPUT" ] && echo " Chroot target: $CHROOT_OUTPUT"
364 [ -n "$BUILD_OUTPUT" ] && echo " Build target: $BUILD_OUTPUT"
365 [ -n "$ISO_OUTPUT" ] && echo " ISO target: $ISO_OUTPUT"
366 [ -n "$GRML_NAME" ] && echo " Grml name: $GRML_NAME"
367 [ -n "$RELEASENAME" ] && echo " Release name: $RELEASENAME"
368 [ -n "$DATE" ] && echo " Build date: $DATE"
369 [ -n "$VERSION" ] && echo " Grml version: $VERSION"
370 [ -n "$SUITE" ] && echo " Debian suite: $SUITE"
371 [ -n "$ARCH" ] && echo " Architecture: $ARCH"
372 [ -n "$BOOT_METHOD" ] && echo " Boot method: $BOOT_METHOD"
373 [ -n "$HYBRID_METHOD" ] && echo " Hybrid method: $HYBRID_METHOD"
374 [ -n "$TEMPLATE_DIRECTORY" ] && echo " Template files: $TEMPLATE_DIRECTORY"
375 [ -n "$CHROOT_INSTALL" ] && echo " Install files from directory to chroot: $CHROOT_INSTALL"
376 [ -n "$BOOTID" ] && echo " Boot identifier: $BOOTID"
377 [ -n "$NO_BOOTID" ] && echo " Skipping bootid feature."
378 [ -n "$DEFAULT_BOOTOPTIONS" ] && echo " Adding default bootoptions: \"$DEFAULT_BOOTOPTIONS\""
379 [ -n "$FAI_ARGS" ] && echo " Additional arguments for FAI: $FAI_ARGS"
380 [ -n "$LOGFILE" ] && echo " Logging to file: $LOGFILE"
381 [ -n "$SQUASHFS_ZLIB" ] && echo " Using ZLIB (instead of LZMA/XZ) compression."
382 [ -n "$SQUASHFS_OPTIONS" ] && echo " Using SQUASHFS_OPTIONS ${SQUASHFS_OPTIONS}"
383 [ -n "$VERBOSE" ] && echo " Using VERBOSE mode."
384 [ -n "$UPDATE" ] && echo " Executing UPDATE instead of fresh installation."
385 if [ -n "$BOOTSTRAP_ONLY" ] ; then
386 echo " Bootstrapping only and not building (files for) ISO."
388 [ -n "$SKIP_MKSQUASHFS" ] && echo " Skipping creation of SQUASHFS file."
389 [ -n "$SKIP_MKISOFS" ] && echo " Skipping creation of ISO file."
390 [ -n "$BUILD_ONLY" ] && echo " Executing BUILD_ONLY instead of fresh installation or UPDATE."
391 [ -n "$BUILD_DIRTY" ] && echo " Executing BUILD_DIRTY to leave chroot untouched."
394 echo -n "Is this ok for you? [y/N] "
396 if ! [ "$a" = 'y' -o "$a" = 'Y' ] ; then
397 bailout 1 "Exiting as requested."
403 # create log file {{{
404 [ -n "$LOGFILE" ] || LOGFILE=${OUTPUT}/grml_logs/grml-live.log
405 mkdir -p $(dirname "${LOGFILE}")
407 chown root:adm $LOGFILE
411 # clean/zero/remove logfiles {{{
413 if [ -n "$PRESERVE_LOGFILE" ] ; then
414 echo "Preserving logfile $LOGFILE as requested via \$PRESERVE_LOGFILE"
416 # make sure it is empty (as it is e.g. appended to grml-live-db)
420 if [ -n "$ZERO_FAI_LOGFILE" ] ; then
421 if [ -d /var/log/fai/"$HOSTNAME" ] ; then
422 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last)"
423 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-dirinstall)"
424 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-softupdate)"
425 rm -f /var/log/fai/"$HOSTNAME"/last \
426 /var/log/fai/"$HOSTNAME"/last-dirinstall \
427 /var/log/fai/"$HOSTNAME"/last-softupdate
432 # source config and startup {{{
433 if [ -n "$CONFIG" ] ; then
434 if ! [ -f "$CONFIG" ] ; then
435 log "Error: $CONFIG could not be read. Exiting. [$(date)]"
436 eerror "Error: $CONFIG could not be read. Exiting." ; eend 1
439 log "Sourcing $CONFIG"
444 start_seconds=$(cut -d . -f 1 /proc/uptime)
445 log "------------------------------------------------------------------------------"
446 log "Starting grml-live [${GRML_LIVE_VERSION}] run on $(date)"
447 if [ -n "$LOCAL_CONFIG" ]; then
448 log "Using local config file: $LOCAL_CONFIG"
450 log "Executed grml-live command line:"
453 einfo "Logging actions to logfile $LOGFILE"
456 # on-the-fly configuration {{{
457 mkdir -p "$(dirname $SOURCES_LIST_OUTPUT)" # might not be present in -D config space
459 cat > "$SOURCES_LIST_OUTPUT" << EOF
460 # NOTE: This file is *NOT* meant for manual customisation! This file is
461 # installed temporarily only by grml-live and will be overriden in the
462 # installation and configuration process then.
465 if [ -n "$MIRROR_DIRECTORY" ] ; then
466 if ! [ -d "$MIRROR_DIRECTORY/debian" ] ; then
467 log "Error: $MIRROR_DIRECTORY/debian does not seem to exist. Exiting. [$(date)]"
468 eerror "Error: $MIRROR_DIRECTORY/debian does not seem to exist. Exiting." ; eend 1
471 echo "$MIRROR_SOURCES" >> "$SOURCES_LIST_OUTPUT"
474 if [ -n "$FAI_DEBOOTSTRAP" ] ; then
475 sed "s#^FAI_DEBOOTSTRAP=.*#FAI_DEBOOTSTRAP=\"$FAI_DEBOOTSTRAP\"#" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
478 # does this suck? YES!
479 # /usr/share/debootstrap/scripts/unstable does not exist, instead use 'sid':
481 unstable) SUITE='sid' ;;
482 # make sure that we *NEVER* write any broken suite name to sources.list,
483 # otherwise we won't be able to adjust it one next (correct) execution
491 *) echo "Sorry, $SUITE is not a valid Debian suite, exiting.">&2; bailout 1 ;;
493 export SUITE # make sure it's available in FAI scripts
495 if [ -n "${GRML_LIVE_SOURCES:-}" ] ; then
496 DIST=" etch\| stable\| lenny\| squeeze\| wheezy\| testing\| sid\| unstable"
497 echo "# generated based on \$GRML_LIVE_SOURCES by grml-live
498 $GRML_LIVE_SOURCES" | \
499 sed -e "s/\(^deb .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/;
500 s/\(^deb-src .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/" >> "$SOURCES_LIST_OUTPUT"
502 cat >> "$SOURCES_LIST_OUTPUT" << EOF
503 # generated by grml-live
504 deb http://deb.grml.org/ grml-stable main
505 deb http://deb.grml.org/ grml-testing main
506 deb http://cdn.debian.net/debian $SUITE main contrib non-free
510 # notice: activate grml-live pool when building against unstable or testing:
511 if grep -qwe unstable -qwe sid -qwe testing -qwe wheezy "$SOURCES_LIST_OUTPUT" ; then
512 grep -q 'grml-live.*main' "$SOURCES_LIST_OUTPUT" || \
513 grep grml-stable "$SOURCES_LIST_OUTPUT" | \
514 sed 's/grml-stable/grml-live/' >> "$SOURCES_LIST_OUTPUT"
516 grep -q 'grml-live.*main' "$SOURCES_LIST_OUTPUT" && \
517 sed -i 's/.*grml-live.*main/# removed grml-live repository/' "$SOURCES_LIST_OUTPUT"
520 for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" "$NFSROOT_CONF" ; do
521 if [ -n "$file" ] ; then
522 sed "s|^FAI_DEBOOTSTRAP=\"[a-z]* |FAI_DEBOOTSTRAP=\"$SUITE |" "$file" | sponge "$file"
526 # validate whether the specified architecture class matches the
527 # architecture (option), otherwise installation of kernel will fail
528 if echo $CLASSES | grep -qi i386 ; then
529 if ! [[ "$ARCH" == "i386" ]] ; then
530 log "Error: You specified the I386 class but are trying to build something else (AMD64?)."
531 eerror "Error: You specified the I386 class but are trying to build something else (AMD64?)."
532 eerror "Tip: Either invoke grml-live with '-a i386' or adjust the architecture class. Exiting."
536 elif echo $CLASSES | grep -qi amd64 ; then
537 if ! [[ "$ARCH" == "amd64" ]] ; then
538 log "Error: You specified the AMD64 class but are trying to build something else (I386?)."
539 eerror "Error: You specified the AMD64 class but are trying to build something else (I386?)."
540 eerror "Tip: Either invoke grml-live with '-a amd64' or adjust the architecture class. Exiting."
546 if grep -q -- 'FAI_DEBOOTSTRAP_OPTS.*--arch' "$NFSROOT_CONF" ; then
547 sed "s/--arch [a-z0-9]* /--arch $ARCH /" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
549 sed "s|^FAI_DEBOOTSTRAP_OPTS=\"\(.*\)|FAI_DEBOOTSTRAP_OPTS=\"--arch $ARCH \1|" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
553 # CHROOT_OUTPUT - execute FAI {{{
554 if [ -n "$BUILD_DIRTY" ]; then
555 log "Skipping stage 'fai' as requested via option -B"
556 ewarn "Skipping stage 'fai' as requested via option -B" ; eend 0
558 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
560 # provide inform fai about the ISO we build
561 [ -d "$CHROOT_OUTPUT/etc/" ] || mkdir -p "$CHROOT_OUTPUT/etc/"
562 echo '# This file has been generated by grml-live.' > "$CHROOT_OUTPUT/etc/grml_live_version"
563 [ -n "$GRML_LIVE_VERSION" ] && echo "GRML_LIVE_VERSION=$GRML_LIVE_VERSION" >> "$CHROOT_OUTPUT/etc/grml_live_version"
564 [ -n "$SUITE" ] && echo "SUITE=$SUITE" >> "$CHROOT_OUTPUT/etc/grml_live_version"
566 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
567 FAI_ACTION=softupdate
569 FAI_ACTION=dirinstall
572 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
573 if ! [ -r "$CHROOT_OUTPUT/etc/debian_version" ] ; then
574 log "Error: does not look like you have a working chroot. Updating/building not possible."
575 eerror "Error: does not look like you have a working chroot. Updating/building not possible. (Drop -u/-b option?)"
581 if [ -d "$CHROOT_OUTPUT/bin" -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
582 log "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already."
583 ewarn "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already." ; eend 0
585 mkdir -p "$CHROOT_OUTPUT" || bailout 5 "Problem with creating $CHROOT_OUTPUT for FAI"
587 if [ -n "${MIRROR_DIRECTORY}" ] ; then
588 mkdir -p "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
589 mount --bind "${MIRROR_DIRECTORY}" "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
592 # tell dpkg to use "unsafe io" during the build
593 [ -d "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d" ] || mkdir -p "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d"
594 echo force-unsafe-io > "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
596 log "Executed FAI command line:"
597 log "BUILD_ONLY=$BUILD_ONLY BOOTSTRAP_ONLY=$BOOTSTRAP_ONLY fai $VERBOSE -C $GRML_FAI_CONFIG -s file:///$GRML_FAI_CONFIG/config -c$CLASSES -u $HOSTNAME $FAI_ACTION $CHROOT_OUTPUT $FAI_ARGS"
598 BUILD_ONLY="$BUILD_ONLY" BOOTSTRAP_ONLY="$BOOTSTRAP_ONLY" fai $VERBOSE \
599 -C "$GRML_FAI_CONFIG" -s "file:///$GRML_FAI_CONFIG/config" -c"$CLASSES" \
600 -u "$HOSTNAME" "$FAI_ACTION" "$CHROOT_OUTPUT" $FAI_ARGS | tee -a $LOGFILE
601 RC="$PIPESTATUS" # notice: bash-only
603 rm -f "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
605 FORCE_ISO_REBUILD=true
607 if [ "$RC" != 0 ] ; then
608 log "Error: critical error while executing fai [exit code ${RC}]. Exiting."
609 eerror "Error: critical error while executing fai [exit code ${RC}]. Exiting." ; eend 1
612 einfo "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
613 log "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
614 echo "$GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]" > $CHROOT_OUTPUT/etc/grml_version
615 chmod 644 $CHROOT_OUTPUT/etc/grml_version
616 einfo "Rebuilding initramfs"
617 # make sure new /etc/grml_version reaches initramfs, iterate over all
618 # present kernel versions (note: we can't really handle more than one
619 # kernel version anyway right now)
620 # chroot $CHROOT_OUTPUT update-initramfs -u -t => might break when using kernel-package :(
621 for initrd in "$(basename $CHROOT_OUTPUT/boot/vmlinuz-*)" ; do
622 if ! chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -c ; then
623 einfo "Creating fresh initrd did not work, trying update instead:"
624 log "Creating fresh initrd did not work, trying update instead:"
625 chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -u
631 # move fai logs into grml_logs directory
632 mkdir -p "$OUTPUT"/grml_logs/fai/
633 cp -r "$CHROOT_OUTPUT"/var/log/fai/"$HOSTNAME"/last/* "$OUTPUT"/grml_logs/fai/
634 chown root:adm "$OUTPUT"/grml_logs/fai/*
635 chmod 664 "$OUTPUT"/grml_logs/fai/*
636 rm -rf "$CHROOT_OUTPUT"/var/log/fai
638 # Remove all FAI logs from chroot if class RELEASE is used:
639 rm -f "$CHROOT_OUTPUT"/var/log/install_packages.list
643 # notice: 'fai dirinstall' does not seem to exit appropriate, so:
645 CHECKLOG=/var/log/fai/$HOSTNAME/last
646 if [ -r "$CHECKLOG/software.log" ] ; then
647 # 1 errors during executing of commands
648 grep 'dpkg: error processing' $CHECKLOG/software.log >> $LOGFILE && ERROR=1
649 grep 'E: Method http has died unexpectedly!' $CHECKLOG/software.log >> $LOGFILE && ERROR=2
650 grep 'ERROR: chroot' $CHECKLOG/software.log >> $LOGFILE && ERROR=3
651 grep 'E: Failed to fetch' $CHECKLOG/software.log >> $LOGFILE && ERROR=4
652 grep 'Unable to write mmap - msync (28 No space left on device)' $CHECKLOG/software.log >> $LOGFILE && ERROR=5
655 if [ -r "$CHECKLOG/shell.log" ] ; then
656 grep 'FAILED with exit code' $CHECKLOG/shell.log >> $LOGFILE && ERROR=6
659 if [ -n "$ERROR" ] ; then
660 log "Error: there was a critical error [${ERROR}] during execution of stage 'fai dirinstall' [$(date)]"
661 eerror "Error: there was a critical error during execution of stage 'fai dirinstall'"
662 eerror "Note: check out ${CHECKLOG}/ for details. [exit ${ERROR}]"
666 log "Finished execution of stage 'fai dirinstall' [$(date)]"
667 einfo "Finished execution of stage 'fai dirinstall'"
670 einfo "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
671 log "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
677 # package validator {{{
678 CHECKLOG=/var/log/fai/$HOSTNAME/last
680 if [ -r "$CHECKLOG/package_errors.log" ] && grep -q '[a-z]' "$CHECKLOG/package_errors.log" ; then
682 if [ -n "$EXIT_ON_MISSING_PACKAGES" -a -z "$BUILD_DIRTY" ] ; then
683 eerror "The following packages were requested for installation but could not be processed:"
684 cat $CHECKLOG/package_errors.log
685 eerror "... exiting as requested via \$EXIT_ON_MISSING_PACKAGES."
689 ewarn "The following packages were requested for installation but could not be processed:"
690 cat $CHECKLOG/package_errors.log
696 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
697 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
698 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
701 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
702 if [ -n "$BOOTSTRAP_ONLY" ] ; then
703 log "Skipping stage 'boot' as building with bootstrap only."
704 ewarn "Skipping stage 'boot' as building with bootstrap only." ; eend 0
706 if [ -d "$BUILD_OUTPUT"/boot/isolinux -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
707 log "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already."
708 ewarn "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already." ; eend 0
711 [ -d "$BUILD_OUTPUT"/boot/isolinux ] || mkdir -p "$BUILD_OUTPUT"/boot/isolinux
712 [ -d "$BUILD_OUTPUT"/boot/"${SHORT_NAME}" ] || mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"
714 # if we don't have an initrd we a) can't boot and b) there was an error
715 # during build, so check for the file:
716 INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
717 if [ -n "$INITRD" ] ; then
718 cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/initrd.gz
719 find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
721 log "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
722 eerror "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
726 KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
727 if [ -n "$KERNEL_IMAGE" ] ; then
728 cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/linux26
730 log "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
731 eerror "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
735 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
736 if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
737 log "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
738 eerror "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
742 # copy _required_ isolinux files
743 for file in ifcpu64.c32 isolinux.bin vesamenu.c32; do
744 copy_addon_file "${file}" /usr/lib/syslinux isolinux
747 # *always* copy files to output directory so the variables
748 # get adjusted according to the build.
749 cp ${TEMPLATE_DIRECTORY}/boot/isolinux/* "$BUILD_OUTPUT"/boot/isolinux/
751 if [ -n "$NO_ADDONS" ] ; then
752 log "Skipping installation of boot addons as requested via \$NO_ADDONS."
753 einfo "Skipping installation of boot addons as requested via \$NO_ADDONS."; eend 0
755 if ! [ -d "$TEMPLATE_DIRECTORY"/boot/addons ] ; then
756 log "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)"
757 ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
759 # copy addons from system packages or grml-live-compat
760 copy_addon_file ipxe.lkrn /usr/lib/ipxe addons
761 copy_addon_file pci.ids /usr/share/misc addons
762 copy_addon_file memtest86+.bin /boot addons
763 for file in memdisk chain.c32 hdt.c32 menu.c32; do
764 copy_addon_file "${file}" /usr/lib/syslinux addons
767 # make memtest filename FAT16/8.3 compatible
768 mv "${BUILD_OUTPUT}/boot/addons/memtest86+.bin" \
769 "${BUILD_OUTPUT}/boot/addons/memtest"
771 # copy only files so we can handle bsd4grml on its own
772 for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
773 test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
776 if [ -n "$NO_ADDONS_BSD4GRML" ] ; then
777 log "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."
778 einfo "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."; eend 0
780 if [ -d "$TEMPLATE_DIRECTORY"/boot/addons/bsd4grml ] ; then
781 cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
783 log "Missing addon file: bsd4grml"
784 ewarn "Missing addon file: bsd4grml" ; eend 0
788 fi # no "$TEMPLATE_DIRECTORY"/boot/addons
791 if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
792 mkdir -p "${BUILD_OUTPUT}/boot/grub"
794 cp ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
796 if [ -e ${TEMPLATE_DIRECTORY}/compat/grub/linux.mod ]; then
797 cp "${TEMPLATE_DIRECTORY}"/compat/grub/* "${BUILD_OUTPUT}"/boot/grub/
799 if ! which "grub-mkimage" >/dev/null 2>&1 ; then
800 log "grub-mkimage not found, skipping Grub step therefore." ; eend 0
801 ewarn "grub-mkimage not found, skipping Grub step therefore."
802 ewarn "Please install grub-pc-bin or grub-common >= 1.98+20100804-14." ; eend 0
803 elif ! grub-mkimage --help | grep -q -- --format ; then
804 log "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore." ; eend 0
805 ewarn "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore."
806 ewarn "Please install grub-common >= 1.98+20100804-14 or grub-pc-bin." ; eend 0
808 # copy system grub files if grml-live-compat is not installed
809 cp -a /usr/lib/grub/*-pc/*.mod "${BUILD_OUTPUT}"/boot/grub/
810 cp -a /usr/lib/grub/*-pc/*.o "${BUILD_OUTPUT}"/boot/grub/
811 cp -a /usr/lib/grub/*-pc/*.lst "${BUILD_OUTPUT}"/boot/grub/
812 cp -a /usr/share/grub/ascii.pf2 "${BUILD_OUTPUT}"/boot/grub/
813 grub-mkimage -d /usr/lib/grub/*-pc -o \
814 "${BUILD_OUTPUT}/boot/grub/core.img" biosdisk iso9660 --format=i386-pc
818 if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
819 log "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
820 eerror "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
824 [ -d "$BUILD_OUTPUT"/GRML ] || mkdir "$BUILD_OUTPUT"/GRML
825 cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/
827 # adjust boot splash information:
828 RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
829 RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
830 RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
832 if [ -r "$BUILD_OUTPUT"/GRML/grml-version ] ; then
833 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/grml-version
834 sed -i "s/%DATE%/$DATE/" "$BUILD_OUTPUT"/GRML/grml-version
837 # make sure the squashfs filename is set accordingly:
838 SQUASHFS_NAME="$GRML_NAME.squashfs"
840 if [ -n "$NO_BOOTID" ] ; then
841 log 'Skipping bootid feature as requested via $NO_BOOTID.'
842 einfo 'Skipping bootid feature as requested via $NO_BOOTID.'
844 [ -n "$BOOTID" ] || BOOTID="$(echo ${GRML_NAME}${VERSION} | tr -d ',./;\- ')"
845 [ -d "$BUILD_OUTPUT"/conf ] || mkdir "$BUILD_OUTPUT"/conf
846 einfo "Generating /conf/bootid.txt with entry ${BOOTID}."
847 log "Generating /conf/bootid.txt with entry ${BOOTID}."
848 echo "$BOOTID" > "$BUILD_OUTPUT"/conf/bootid.txt
852 # adjust all variables in the templates with the according distribution information
853 for file in "${BUILD_OUTPUT}"/boot/isolinux/*.cfg "${BUILD_OUTPUT}"/boot/isolinux/*.msg \
854 "${BUILD_OUTPUT}"/boot/grub/* ; do
855 if [ -r "${file}" ] ; then
856 sed -i "s/%ARCH%/$ARCH/g" "${file}"
857 sed -i "s/%DATE%/$DATE/g" "${file}"
858 sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/g" "${file}"
859 sed -i "s/%DISTRI_NAME%/$DISTRI_NAME/g" "${file}"
860 sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/g" "${file}"
861 sed -i "s/%GRML_NAME%/$GRML_NAME/g" "${file}"
862 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/g" "${file}"
863 sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/g" "${file}"
864 sed -i "s/%SHORT_NAME%/$SHORT_NAME/g" "${file}"
865 sed -i "s/%VERSION%/$VERSION/g" "${file}"
867 [ -n "$DEFAULT_BOOTOPTIONS" ] && sed -i "s/ boot=live/ boot=live $DEFAULT_BOOTOPTIONS/" "${file}"
869 if [ -n "$NO_BOOTID" ] ; then
870 sed -i "s/ bootid=%BOOTID%//g" "${file}" # drop bootid bootoption
872 sed -i "s/%BOOTID%/$BOOTID/g" "${file}" # adjust bootid=... argument
877 # adjust bootsplash accordingly but make sure the string has the according lenght
878 SQUASHFS_NAME="$(cut_string 20 "$SQUASHFS_NAME")"
879 SQUASHFS_NAME="$(extend_string_end 20 "$SQUASHFS_NAME")"
880 for file in f4 f5 ; do
881 if [ -r "${BUILD_OUTPUT}/boot/isolinux/${file}" ] ; then
882 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
883 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
887 # generate addon list
888 rm -f "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
889 for name in "${BUILD_OUTPUT}"/boot/isolinux/addon_*.cfg ; do
890 include_name=$(basename "$name")
891 echo "include $include_name" >> "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
894 if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
895 log "including grmlmain.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
896 echo "include grmlmain.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
897 echo "include default.cfg" > "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
898 echo "include menuoptions.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
899 echo "include grml.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
901 for f in "${BUILD_OUTPUT}"/boot/isolinux/submenu*.cfg ; do
902 echo "include $(basename $f)" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
905 echo "include options.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
906 if [ ! -n "$NO_ADDONS" ] ; then
907 echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
909 echo "include isoprompt.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
910 echo "include hd.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
911 echo "include hidden.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
912 else # assume we are building a custom distribution:
913 log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
914 einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
915 if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
916 log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
918 einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
922 log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
923 echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
924 [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
928 # use old style console based isolinux method only if requested:
929 if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
930 log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
931 einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
932 if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
933 einfo "include for console.cfg already found, nothing to do."
936 log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
937 einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
938 echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
942 log 'Using graphical boot menu.'
943 if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
944 log "include for vesamenu.cfg already found, nothing to do."
946 log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
947 echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
951 if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
952 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
955 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot
956 if ! [ -r "$DPKG_LIST" ] ; then
957 ewarn "$DPKG_LIST could not be read, ignoring to store package information on ISO therefore."
959 einfo "Storing package list information as /GRML/${GRML_NAME}-packages.txt on ISO."
960 cp "$DPKG_LIST" "${BUILD_OUTPUT}/GRML/${GRML_NAME}-packages.txt"
964 # autostart for Windows:
965 if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
966 cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
969 FORCE_ISO_REBUILD=true
970 einfo "Finished execution of stage 'boot'" ; eend 0
974 log 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
975 eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
979 # support installation of local files into the chroot/ISO
980 if [ -n "$CHROOT_INSTALL" ] ; then
981 if ! [ -d "$CHROOT_INSTALL" ] ; then
982 log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
983 ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
985 log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
986 einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
987 rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
989 einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
990 FORCE_ISO_REBUILD=true
994 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
995 log "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
996 ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
997 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
998 log "Skipping stage 'squashfs' as requested via option -q or -N"
999 ewarn "Skipping stage 'squashfs' as requested via option -q or -N" ; eend 0
1001 [ -d "$BUILD_OUTPUT"/live ] || mkdir "$BUILD_OUTPUT"/live
1002 # make sure we don't leave (even an empty) base.tgz:
1003 [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
1005 # if unconfigured default to squashfs-tools' mksquashfs binary
1006 if [ -z "$SQUASHFS_BINARY" ] ; then
1007 SQUASHFS_BINARY='mksquashfs'
1010 if which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
1011 log "Using mksquashfs binary ${SQUASHFS_BINARY}"
1012 einfo "Using mksquashfs binary ${SQUASHFS_BINARY}" ; eend 0
1014 log "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
1015 eerror "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
1019 # use sane defaults if $SQUASHFS_OPTIONS isn't set
1020 if [ -z "$SQUASHFS_OPTIONS" ] ; then
1021 # use blocksize 256k as this gives best result with regards to time + compression
1022 SQUASHFS_OPTIONS="-b 256k"
1024 # set lzma/xz compression by default, unless -z option has been specified on command line
1025 if [ -z "$SQUASHFS_ZLIB" ] ; then
1026 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp xz"
1028 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp gzip"
1032 # support exclusion of files via exclude-file:
1033 if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
1034 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE -wildcards"
1037 # get rid of unnecessary files when building grml-small for final release:
1038 if echo "$CLASSES" | grep -q GRML_SMALL ; then
1039 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
1043 SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
1045 # informational stuff
1046 [ -n "$SQUASHFS_OPTIONS" ] && SQUASHFS_INFO_MSG="$SQUASHFS_OPTIONS"
1047 [ -n "$SQUASHFS_INFO_MSG" ] && SQUASHFS_INFO_MSG="using options: $SQUASHFS_INFO_MSG"
1048 einfo "Squashfs build information: running binary $SQUASHFS_BINARY $SQUASHFS_INFO_MSG"
1050 log "$SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS"
1052 if $SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/"${GRML_NAME}".squashfs \
1053 -noappend $SQUASHFS_OPTIONS 2>"${SQUASHFS_STDERR}" ; then
1054 echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/filesystem.module
1055 log "Finished execution of stage 'squashfs' [$(date)]"
1056 einfo "Finished execution of stage 'squashfs'" ; eend 0
1058 log "Error: there was a critical error executing stage 'squashfs' [$(date)]:"
1059 log "$(cat $SQUASHFS_STDERR)"
1060 eerror "Error: there was a critical error executing stage 'squashfs':"
1061 cat "${SQUASHFS_STDERR}"
1066 FORCE_ISO_REBUILD=true
1069 # create md5sum file:
1070 if [ -z "$BOOTSTRAP_ONLY" ] ; then
1071 ( cd $BUILD_OUTPUT/GRML &&
1072 find .. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
1076 # ISO_OUTPUT - mkisofs {{{
1077 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
1078 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
1080 if [ "$BOOT_METHOD" = "isolinux" ] ; then
1081 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
1082 elif [ "$BOOT_METHOD" = "grub2" ] ; then
1083 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -b boot/grub/toriboot.bin"
1086 # Just until http://bts.grml.org/grml/issue945 has been resolved.
1087 # HYBRID_METHOD defaults to manifold, so make sure the default works OOTB.
1088 if [[ $BOOT_METHOD != isolinux && ($HYBRID_METHOD = isohybrid || $HYBRID_METHOD = manifold) ]]; then
1089 log "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1090 ewarn "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1091 HYBRID_METHOD='grub2'
1095 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ] ; then
1096 log "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already."
1097 ewarn "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already." ; eend 0
1098 elif [ -n "$SKIP_MKISOFS" ] ; then
1099 log "Skipping stage 'iso build' as requested via option -n or -N"
1100 ewarn "Skipping stage 'iso build' as requested via option -n or -N" ; eend 0
1102 mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
1104 if $FORCE_ISO_REBUILD && ! [ -f "${ISO_OUTPUT}/${ISO_NAME}" ] ; then
1105 log "Forcing rebuild of ISO because files on ISO have been modified."
1106 einfo "Forcing rebuild of ISO because files on ISO have been modified."
1109 # support mkisofs as well as genisoimage
1110 if which mkisofs >/dev/null 2>&1; then
1112 elif which genisoimage >/dev/null 2>&1; then
1113 MKISOFS='genisoimage'
1115 log "Error: neither mkisofs nor genisoimage available - can not create ISO."
1116 eerror "Error: neither mkisofs nor genisoimage available - can not create ISO." ; eend 1
1121 if cd "$BUILD_OUTPUT" ; then
1122 if [ "$BOOT_METHOD" = "grub2" ]; then
1123 # make a 2048-byte bootsector for El Torito
1124 dd if=/dev/zero of=boot/grub/toriboot.bin bs=512 count=4 2>/dev/null
1125 # those are in 2048-byte sectors, so 1 16 matches 4 63 below
1126 echo 1 16 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -B 11 | \
1127 dd of=boot/grub/toriboot.bin conv=notrunc 2>/dev/null
1129 log "$MKISOFS -V '${GRML_NAME} ${VERSION}' -publisher 'grml-live | grml.org' -l -r -J $BOOT_ARGS -o ${ISO_OUTPUT}/${ISO_NAME} ."
1130 "$MKISOFS" -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
1131 -l -r -J $BOOT_ARGS -no-pad \
1132 -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
1133 # both of these need core.img there, so it’s easier to write it here
1134 if [ "$BOOT_METHOD" = "grub2" ] || [ "$HYBRID_METHOD" = "grub2" ]; then
1135 # must be <= 30720 bytes
1136 dd if=boot/grub/core.img of="${ISO_OUTPUT}/${ISO_NAME}" \
1137 conv=notrunc bs=512 seek=4 2>/dev/null
1140 # pad the output ISO to multiples of 256 KiB for partition table support
1141 siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
1142 cyls=$((siz / 512 / 32 / 16 + 1)) # C=$cyls H=16 S=32
1143 siz=$((cyls * 16 * 32 * 512)) # size after padding
1144 dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
1145 of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
1147 # support disabling hybrid ISO image
1148 if [ "$HYBRID_METHOD" = "disable" ] ; then\
1149 log "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1150 einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1152 # use isohybrid only on request
1153 elif [ "$HYBRID_METHOD" = "isohybrid" ] ; then
1154 if ! which isohybrid >/dev/null 2>&1 ; then
1155 bailout 12 "isohybrid binary not found - please install syslinux/syslinux-common"
1157 log "Creating hybrid ISO file with isohybrid method"
1158 einfo "Creating hybrid ISO file with isohybrid method"
1159 # Notes for consideration:
1160 # "-entry 4 -type 1c"
1161 # * using 4 as the partition number is supposed to help with BIOSes
1162 # that only support USB-Zip boot
1163 # * using 1c (i.e. hidden FAT32 LBA), instead of the default 0x17
1164 # (hidden NTFS, IIRC), as the partition type is sometimes needed
1165 # to get the BIOS even look at the partition created by isohybrid
1166 isohybrid "${ISO_OUTPUT}/${ISO_NAME}"
1169 # by default use our manifold boot method:
1171 # isoinfo is part of both mkisofs and genisoimage so we're good
1172 bootoff=$(isoinfo -l -i "${ISO_OUTPUT}/${ISO_NAME}" | \
1173 sed -n '/^.*\[ *\([0-9]*\)[] ].* ISOLINUX.BIN;1 *$/s//\1/p')
1174 if ! [ -r boot/grub/core.img ] ; then
1175 ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
1176 elif [ "${bootoff:-0}" -lt 1 ] ; then
1177 ewarn "isolinux.bin not found on the ISO file, disabling manifold boot"
1179 log "Creating hybrid ISO file with manifold method"
1180 einfo "Creating hybrid ISO file with manifold method"
1181 if [ "$HYBRID_METHOD" = "grub2" ] ; then
1182 # 512 bytes: MBR, partition table, load GRUB 2
1183 echo 4 63 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 4:0x96 -g $cyls:16:32
1185 # read only one but 2048-byte sized (scale: << 2) sector
1186 echo $bootoff $bootoff | \
1187 mksh /usr/share/grml-live/scripts/bootilnx.mksh -A -M 4:0x96 -g $cyls:16:32 -S 2
1188 fi | dd of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
1193 # generate md5sum and sha1sum of ISO if we are using class 'RELEASE':
1194 case $CLASSES in *RELEASE*)
1197 if cd $ISO_OUTPUT ; then
1198 md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
1199 touch -r ${ISO_NAME} ${ISO_NAME}.md5
1200 sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
1201 touch -r ${ISO_NAME} ${ISO_NAME}.sha1
1210 if [ "$RC" = 0 ] ; then
1211 log "Finished execution of stage 'iso build' [$(date)]"
1212 einfo "Finished execution of stage 'iso build'" ; eend 0
1214 log "Error: there was a critical error ($RC) executing stage 'iso build' [$(date)]"
1215 eerror "Error: there was a critical error executing stage 'iso build'" ; eend 1
1221 # log build information to database if grml-live-db is installed and enabled {{{
1223 if [ -d /usr/share/grml-live-db ] ; then
1226 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot:
1227 [ -n "$DPKG_DATABASE" ] || DPKG_DATABASE=/var/log/grml-live.db
1228 [ -n "$DPKG_DBSCRIPT" ] || DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
1229 [ -n "$DPKG_DBOPTIONS" ] || DPKG_DBOPTIONS="--database $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME --dpkg $DPKG_LIST"
1231 if ! [ -x "$DPKG_DBSCRIPT" ] ; then
1232 log "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information."
1233 eerror "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information." ; eend 1
1237 # disable by default for now, not sure whether really everyone is using a local db file
1238 #if ! touch "$DPKG_DATABASE" ; then
1239 # eerror "Error: can not write to ${DPKG_DATABASE}, can not log dpkg information." ; eend 1
1243 if ! [ -r "$DPKG_LIST" ] ; then
1244 log "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)"
1245 ewarn "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)" ; eend 0
1247 einfo "Logging $DPKG_LIST to database $DPKG_DATABASE"
1248 log "Logging $DPKG_LIST to database $DPKG_DATABASE"
1249 log "Executing $DPKG_DBSCRIPT $DPKG_DBOPTIONS"
1252 if DB_INFO=$("$DPKG_DBSCRIPT" $DPKG_DBOPTIONS 2>&1) ; then
1268 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
1269 log "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]"
1271 dpkg_to_db # make sure we catch the last log line as well, therefore execute between log + einfo
1273 einfo "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]" ; eend 0
1277 ## END OF FILE #################################################################
1278 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=2