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 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)
218 # Copy addonfile $1 from either
219 # * the chroot (via $2, the system path),
220 # * or from TEMPLATE_DIRECTORY/compat (if exists),
221 # * or from the host system (again, using $2),
222 # or warn about the missing file.
225 # * We assume that the chroot always has a "good" version of
226 # the file. Also it makes sources handling easier.
227 # * On unstable, we Recommend the Debian packages containing
228 # these files. The user can override them by putting his
229 # "better" version into the chroot.
230 # * On stable, the Debian packages are probably not available,
231 # or outdated, so we look in TEMPLATE_DIRECTORY/compat first, where
232 # our grml-live-compat package installs current file versions.
234 DEST="${BUILD_OUTPUT}/boot/$3"
235 if [ ! -d "${DEST}/" ]; then
238 if [ -e "$CHROOT_OUTPUT/$2/$1" ]; then
239 log "Copying $1 from chroot"
240 cp "$CHROOT_OUTPUT/$2/$1" "${DEST}/"
243 if [ -e "${TEMPLATE_DIRECTORY}/compat/$3/$1" ]; then
244 log "Copying $1 from grml-live-compat"
245 cp "${TEMPLATE_DIRECTORY}/compat/$3/$1" "${DEST}/"
248 if [ -e "$2/$1" ]; then
249 log "Copying $1 from system"
250 cp "$2/$1" "${DEST}/"
254 msg="Missing addon file: \"$1\""
255 ewarn "$msg" ; eend 1
256 log "copy_addon_file: $msg"
260 # read local (non-packaged) configuration {{{
261 LOCAL_CONFIG=/etc/grml/grml-live.local
262 if [ -r "$LOCAL_CONFIG" ] ; then
263 log "Sourcing $LOCAL_CONFIG"
266 log "No $LOCAL_CONFIG found, not sourcing it"
271 # command line parsing {{{
272 while getopts "a:C:c:d:D:g:i:I:o:r:s:t:v:bBFnNquVz" opt; do
277 c) CLASSES="$OPTARG" ;;
278 C) CONFIG="$OPTARG" ;;
280 D) GRML_FAI_CONFIG="$OPTARG" ;;
281 g) GRML_NAME="$OPTARG" ;;
282 i) ISO_NAME="$OPTARG" ;;
283 I) CHROOT_INSTALL="$OPTARG" ;;
285 N) BOOTSTRAP_ONLY=1; SKIP_MKISOFS=1; SKIP_MKSQUASHFS=1 ;;
286 o) OUTPUT="$OPTARG" ;;
287 q) SKIP_MKSQUASHFS=1 ;;
288 r) RELEASENAME="$OPTARG" ;;
289 s) SUITE="$OPTARG" ;;
290 t) TEMPLATE_DIRECTORY="$OPTARG";;
291 v) VERSION="$OPTARG" ;;
295 z) SQUASHFS_ZLIB=1 ;;
296 ?) echo "invalid option -$OPTARG" >&2; bailout 1 ;;
299 shift $(($OPTIND - 1)) # set ARGV to the first not parsed commandline parameter
302 # assume sane defaults (if not set already) {{{
303 [ -n "$ARCH" ] || ARCH="$(dpkg --print-architecture)"
304 [ -n "$BOOT_METHOD" ] || BOOT_METHOD='isolinux'
305 [ -n "$CLASSES" ] || CLASSES="GRMLBASE,GRML_MEDIUM,I386"
306 [ -n "$DATE" ] || DATE="$(date +%Y-%m-%d)"
307 [ -n "$DISTRI_INFO" ] || DISTRI_INFO='Grml - Live Linux for system administrators '
308 [ -n "$DISTRI_NAME" ] || DISTRI_NAME="grml"
309 [ -n "$DISTRI_SPLASH" ] || DISTRI_SPLASH='grml.png'
310 [ -n "$FORCE_ISO_REBUILD" ] || FORCE_ISO_REBUILD="false"
311 [ -n "$GRML_FAI_CONFIG" ] || GRML_FAI_CONFIG='/etc/grml/fai'
312 [ -n "$GRML_NAME" ] || GRML_NAME='grml'
313 [ -n "$HOSTNAME" ] || HOSTNAME='grml'
314 [ -n "$HYBRID_METHOD" ] || HYBRID_METHOD='manifold'
315 [ -n "$NFSROOT_CONF" ] || NFSROOT_CONF="${GRML_FAI_CONFIG}/make-fai-nfsroot.conf"
316 [ -n "$RELEASENAME" ] || RELEASENAME='grml-live rocks'
317 [ -n "$SOURCES_LIST_OUTPUT" ] || SOURCES_LIST_OUTPUT="${GRML_FAI_CONFIG}/config/files/etc/apt/sources.list/GRML_LIVE_SOURCES_LIST"
318 [ -n "$SQUASHFS_EXCLUDES_FILE" ] || SQUASHFS_EXCLUDES_FILE="${GRML_FAI_CONFIG}/config/grml/squashfs-excludes"
319 [ -n "$SUITE" ] || SUITE='squeeze'
320 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
321 [ -n "$USERNAME" ] || USERNAME='grml'
322 [ -n "$VERSION" ] || VERSION='0.0.1'
324 # output specific stuff, depends on $OUTPUT (iff not set):
325 [ -n "$OUTPUT" ] || OUTPUT='/grml/grml-live'
326 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
327 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
328 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
331 # some misc checks before executing FAI {{{
332 [ -n "$CLASSES" ] || bailout 1 "Error: \$CLASSES unset, please set it in $LIVE_CONF or
333 specify it on the command line using the -c option."
334 [ -n "$OUTPUT" ] || bailout 1 "Error: \$OUTPUT unset, please set it in $LIVE_CONF or
335 specify it on the command line using the -o option."
337 # trim characters that are known to cause problems inside $GRML_NAME;
338 # for example isolinux does not like '-' inside the directory name
339 [ -n "$GRML_NAME" ] && export SHORT_NAME="$(echo $GRML_NAME | tr -d ',./;\- ')"
341 # export variables to have them available in fai scripts:
342 [ -n "$GRML_NAME" ] && export GRML_NAME="$GRML_NAME"
343 [ -n "$RELEASENAME" ] && export RELEASENAME="$RELEASENAME"
346 # ZERO_LOGFILE - check for backwards compatibility reasons {{{
347 # this was default behaviour until grml-live 0.9.34:
348 if [ -n "$ZERO_LOGFILE" ] ; then
349 PRESERVE_LOGFILE='' # make sure it's cleaned then
350 ewarn "Please consider disabling the \$ZERO_LOGFILE option as grml-live clears..."
351 ewarn "... the logfile $LOGFILE by default (unless \$PRESERVE_LOGFILE is set) nowadays."
356 # ask user whether the setup is ok {{{
357 if [ -z "$FORCE" ] ; then
359 echo "${PN} [${GRML_LIVE_VERSION}]: check your configuration (or use -F to force execution):"
361 echo " FAI classes: $CLASSES"
362 [ -r "$LOCAL_CONFIG" ] && echo " Local config: /etc/grml/grml-live.local"
363 [ -n "$CONFIG" ] && echo " Configuration: $CONFIG"
364 [ -n "$GRML_FAI_CONFIG" ] && echo " Config directory: $GRML_FAI_CONFIG"
365 echo " main directory: $OUTPUT"
366 [ -n "$CHROOT_OUTPUT" ] && echo " Chroot target: $CHROOT_OUTPUT"
367 [ -n "$BUILD_OUTPUT" ] && echo " Build target: $BUILD_OUTPUT"
368 [ -n "$ISO_OUTPUT" ] && echo " ISO target: $ISO_OUTPUT"
369 [ -n "$GRML_NAME" ] && echo " Grml name: $GRML_NAME"
370 [ -n "$RELEASENAME" ] && echo " Release name: $RELEASENAME"
371 [ -n "$DATE" ] && echo " Build date: $DATE"
372 [ -n "$VERSION" ] && echo " Grml version: $VERSION"
373 [ -n "$SUITE" ] && echo " Debian suite: $SUITE"
374 [ -n "$ARCH" ] && echo " Architecture: $ARCH"
375 [ -n "$BOOT_METHOD" ] && echo " Boot method: $BOOT_METHOD"
376 [ -n "$HYBRID_METHOD" ] && echo " Hybrid method: $HYBRID_METHOD"
377 [ -n "$TEMPLATE_DIRECTORY" ] && echo " Template files: $TEMPLATE_DIRECTORY"
378 [ -n "$CHROOT_INSTALL" ] && echo " Install files from directory to chroot: $CHROOT_INSTALL"
379 [ -n "$BOOTID" ] && echo " Boot identifier: $BOOTID"
380 [ -n "$NO_BOOTID" ] && echo " Skipping bootid feature."
381 [ -n "$DEFAULT_BOOTOPTIONS" ] && echo " Adding default bootoptions: \"$DEFAULT_BOOTOPTIONS\""
382 [ -n "$FAI_ARGS" ] && echo " Additional arguments for FAI: $FAI_ARGS"
383 [ -n "$LOGFILE" ] && echo " Logging to file: $LOGFILE"
384 [ -n "$SQUASHFS_ZLIB" ] && echo " Using ZLIB (instead of LZMA/XZ) compression."
385 [ -n "$SQUASHFS_OPTIONS" ] && echo " Using SQUASHFS_OPTIONS ${SQUASHFS_OPTIONS}"
386 [ -n "$VERBOSE" ] && echo " Using VERBOSE mode."
387 [ -n "$UPDATE" ] && echo " Executing UPDATE instead of fresh installation."
388 if [ -n "$BOOTSTRAP_ONLY" ] ; then
389 echo " Bootstrapping only and not building (files for) ISO."
391 [ -n "$SKIP_MKSQUASHFS" ] && echo " Skipping creation of SQUASHFS file."
392 [ -n "$SKIP_MKISOFS" ] && echo " Skipping creation of ISO file."
393 [ -n "$BUILD_ONLY" ] && echo " Executing BUILD_ONLY instead of fresh installation or UPDATE."
394 [ -n "$BUILD_DIRTY" ] && echo " Executing BUILD_DIRTY to leave chroot untouched."
397 echo -n "Is this ok for you? [y/N] "
399 if ! [ "$a" = 'y' -o "$a" = 'Y' ] ; then
400 bailout 1 "Exiting as requested."
406 # clean/zero/remove logfiles {{{
408 if [ -n "$PRESERVE_LOGFILE" ] ; then
409 echo "Preserving logfile $LOGFILE as requested via \$PRESERVE_LOGFILE"
411 # make sure it is empty (as it is e.g. appended to grml-live-db)
415 if [ -n "$ZERO_FAI_LOGFILE" ] ; then
416 if [ -d /var/log/fai/"$HOSTNAME" ] ; then
417 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last)"
418 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-dirinstall)"
419 rm -rf /var/log/fai/"$HOSTNAME"/"$(readlink /var/log/fai/"$HOSTNAME"/last-softupdate)"
420 rm -f /var/log/fai/"$HOSTNAME"/last \
421 /var/log/fai/"$HOSTNAME"/last-dirinstall \
422 /var/log/fai/"$HOSTNAME"/last-softupdate
427 # source config and startup {{{
428 if [ -n "$CONFIG" ] ; then
429 if ! [ -f "$CONFIG" ] ; then
430 log "Error: $CONFIG could not be read. Exiting. [$(date)]"
431 eerror "Error: $CONFIG could not be read. Exiting." ; eend 1
434 log "Sourcing $CONFIG"
439 start_seconds=$(cut -d . -f 1 /proc/uptime)
440 log "------------------------------------------------------------------------------"
441 log "Starting grml-live [${GRML_LIVE_VERSION}] run on $(date)"
442 log "Executed grml-live command line:"
445 einfo "Logging actions to logfile $LOGFILE"
448 # on-the-fly configuration {{{
449 mkdir -p "$(dirname $SOURCES_LIST_OUTPUT)" # might not be present in -D config space
451 cat > "$SOURCES_LIST_OUTPUT" << EOF
452 # NOTE: This file is *NOT* meant for manual customisation! This file is
453 # installed temporarily only by grml-live and will be overriden in the
454 # installation and configuration process then.
457 if [ -n "$MIRROR_DIRECTORY" ] ; then
458 if ! [ -d "$MIRROR_DIRECTORY/debian" ] ; then
459 log "Error: $MIRROR_DIRECTORY/debian does not seem to exist. Exiting. [$(date)]"
460 eerror "Error: $MIRROR_DIRECTORY/debian does not seem to exist. Exiting." ; eend 1
463 echo "$MIRROR_SOURCES" >> "$SOURCES_LIST_OUTPUT"
466 if [ -n "$FAI_DEBOOTSTRAP" ] ; then
467 sed "s#^FAI_DEBOOTSTRAP=.*#FAI_DEBOOTSTRAP=\"$FAI_DEBOOTSTRAP\"#" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
470 # does this suck? YES!
471 # /usr/share/debootstrap/scripts/unstable does not exist, instead use 'sid':
473 unstable) SUITE='sid' ;;
474 # make sure that we *NEVER* write any broken suite name to sources.list,
475 # otherwise we won't be able to adjust it one next (correct) execution
483 *) echo "Sorry, $SUITE is not a valid Debian suite, exiting.">&2; bailout 1 ;;
485 export SUITE # make sure it's available in FAI scripts
487 if [ -n "${GRML_LIVE_SOURCES:-}" ] ; then
488 DIST=" etch\| stable\| lenny\| squeeze\| wheezy\| testing\| sid\| unstable"
489 echo "# generated based on \$GRML_LIVE_SOURCES by grml-live
490 $GRML_LIVE_SOURCES" | \
491 sed -e "s/\(^deb .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/;
492 s/\(^deb-src .\+\)\([ \t]*\)\($DIST\)\([ \t]*\)\(main \)/\1 \2$SUITE\4\5/" >> "$SOURCES_LIST_OUTPUT"
494 cat >> "$SOURCES_LIST_OUTPUT" << EOF
495 # generated by grml-live
496 deb http://deb.grml.org/ grml-stable main
497 deb http://deb.grml.org/ grml-testing main
498 deb http://cdn.debian.net/debian $SUITE main contrib non-free
502 # notice: activate grml-live pool when building against unstable or testing:
503 if grep -qwe unstable -qwe sid -qwe testing -qwe wheezy "$SOURCES_LIST_OUTPUT" ; then
504 grep -q 'grml-live.*main' "$SOURCES_LIST_OUTPUT" || \
505 grep grml-stable "$SOURCES_LIST_OUTPUT" | \
506 sed 's/grml-stable/grml-live/' >> "$SOURCES_LIST_OUTPUT"
508 grep -q 'grml-live.*main' "$SOURCES_LIST_OUTPUT" && \
509 sed -i 's/.*grml-live.*main/# removed grml-live repository/' "$SOURCES_LIST_OUTPUT"
512 for file in "$LIVE_CONF" "$CONFIG" "$LOCAL_CONFIG" "$NFSROOT_CONF" ; do
513 if [ -n "$file" ] ; then
514 sed "s|^FAI_DEBOOTSTRAP=\"[a-z]* |FAI_DEBOOTSTRAP=\"$SUITE |" "$file" | sponge "$file"
518 # validate whether the specified architecture class matches the
519 # architecture (option), otherwise installation of kernel will fail
520 if echo $CLASSES | grep -qi i386 ; then
521 if ! [[ "$ARCH" == "i386" ]] ; then
522 log "Error: You specified the I386 class but are trying to build something else (AMD64?)."
523 eerror "Error: You specified the I386 class but are trying to build something else (AMD64?)."
524 eerror "Tip: Either invoke grml-live with '-a i386' or adjust the architecture class. Exiting."
528 elif echo $CLASSES | grep -qi amd64 ; then
529 if ! [[ "$ARCH" == "amd64" ]] ; then
530 log "Error: You specified the AMD64 class but are trying to build something else (I386?)."
531 eerror "Error: You specified the AMD64 class but are trying to build something else (I386?)."
532 eerror "Tip: Either invoke grml-live with '-a amd64' or adjust the architecture class. Exiting."
538 if grep -q -- 'FAI_DEBOOTSTRAP_OPTS.*--arch' "$NFSROOT_CONF" ; then
539 sed "s/--arch [a-z0-9]* /--arch $ARCH /" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
541 sed "s|^FAI_DEBOOTSTRAP_OPTS=\"\(.*\)|FAI_DEBOOTSTRAP_OPTS=\"--arch $ARCH \1|" "$NFSROOT_CONF" | sponge "$NFSROOT_CONF"
545 # CHROOT_OUTPUT - execute FAI {{{
546 if [ -n "$BUILD_DIRTY" ]; then
547 log "Skipping stage 'fai' as requested via option -B"
548 ewarn "Skipping stage 'fai' as requested via option -B" ; eend 0
550 [ -n "$CHROOT_OUTPUT" ] || CHROOT_OUTPUT="$OUTPUT/grml_chroot"
552 # provide inform fai about the ISO we build
553 [ -d "$CHROOT_OUTPUT/etc/" ] || mkdir -p "$CHROOT_OUTPUT/etc/"
554 echo '# This file has been generated by grml-live.' > "$CHROOT_OUTPUT/etc/grml_live_version"
555 [ -n "$GRML_LIVE_VERSION" ] && echo "GRML_LIVE_VERSION=$GRML_LIVE_VERSION" >> "$CHROOT_OUTPUT/etc/grml_live_version"
556 [ -n "$SUITE" ] && echo "SUITE=$SUITE" >> "$CHROOT_OUTPUT/etc/grml_live_version"
558 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
559 FAI_ACTION=softupdate
561 FAI_ACTION=dirinstall
564 if [ -n "$UPDATE" -o -n "$BUILD_ONLY" ] ; then
565 if ! [ -r "$CHROOT_OUTPUT/etc/debian_version" ] ; then
566 log "Error: does not look like you have a working chroot. Updating/building not possible."
567 eerror "Error: does not look like you have a working chroot. Updating/building not possible. (Drop -u/-b option?)"
573 if [ -d "$CHROOT_OUTPUT/bin" -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
574 log "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already."
575 ewarn "Skipping stage 'fai dirinstall' as $CHROOT_OUTPUT exists already." ; eend 0
577 mkdir -p "$CHROOT_OUTPUT" || bailout 5 "Problem with creating $CHROOT_OUTPUT for FAI"
579 if [ -n "${MIRROR_DIRECTORY}" ] ; then
580 mkdir -p "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
581 mount --bind "${MIRROR_DIRECTORY}" "${CHROOT_OUTPUT}/${MIRROR_DIRECTORY}"
584 # tell dpkg to use "unsafe io" during the build
585 [ -d "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d" ] || mkdir -p "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d"
586 echo force-unsafe-io > "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
588 log "Executed FAI command line:"
589 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"
590 BUILD_ONLY="$BUILD_ONLY" BOOTSTRAP_ONLY="$BOOTSTRAP_ONLY" fai $VERBOSE \
591 -C "$GRML_FAI_CONFIG" -s "file:///$GRML_FAI_CONFIG/config" -c"$CLASSES" \
592 -u "$HOSTNAME" "$FAI_ACTION" "$CHROOT_OUTPUT" $FAI_ARGS | tee -a $LOGFILE
593 RC="$PIPESTATUS" # notice: bash-only
595 rm -f "$CHROOT_OUTPUT/etc/dpkg/dpkg.cfg.d/unsafe-io"
597 FORCE_ISO_REBUILD=true
599 if [ "$RC" != 0 ] ; then
600 log "Error: critical error while executing fai [exit code ${RC}]. Exiting."
601 eerror "Error: critical error while executing fai [exit code ${RC}]. Exiting." ; eend 1
604 einfo "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
605 log "Setting /etc/grml_version to $GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]"
606 echo "$GRML_NAME $VERSION Release Codename $RELEASENAME [$DATE]" > $CHROOT_OUTPUT/etc/grml_version
607 chmod 644 $CHROOT_OUTPUT/etc/grml_version
608 einfo "Rebuilding initramfs"
609 # make sure new /etc/grml_version reaches initramfs, iterate over all
610 # present kernel versions (note: we can't really handle more than one
611 # kernel version anyway right now)
612 # chroot $CHROOT_OUTPUT update-initramfs -u -t => might break when using kernel-package :(
613 for initrd in "$(basename $CHROOT_OUTPUT/boot/vmlinuz-*)" ; do
614 if ! chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -c ; then
615 einfo "Creating fresh initrd did not work, trying update instead:"
616 log "Creating fresh initrd did not work, trying update instead:"
617 chroot $CHROOT_OUTPUT update-initramfs -k "${initrd##vmlinuz-}" -u
623 # Remove all FAI logs from chroot if class RELEASE is used:
624 if [ -f "$CHROOT_OUTPUT"/etc/grml_fai_release ] ; then
625 rm -rf "$CHROOT_OUTPUT"/var/log/fai/*
626 rm -f "$CHROOT_OUTPUT"/var/log/install_packages.list
631 # notice: 'fai dirinstall' does not seem to exit appropriate, so:
633 CHECKLOG=/var/log/fai/$HOSTNAME/last
634 if [ -r "$CHECKLOG/software.log" ] ; then
635 # 1 errors during executing of commands
636 grep 'dpkg: error processing' $CHECKLOG/software.log >> $LOGFILE && ERROR=1
637 grep 'E: Method http has died unexpectedly!' $CHECKLOG/software.log >> $LOGFILE && ERROR=2
638 grep 'ERROR: chroot' $CHECKLOG/software.log >> $LOGFILE && ERROR=3
639 grep 'E: Failed to fetch' $CHECKLOG/software.log >> $LOGFILE && ERROR=4
640 grep 'Unable to write mmap - msync (28 No space left on device)' $CHECKLOG/software.log >> $LOGFILE && ERROR=5
643 if [ -r "$CHECKLOG/shell.log" ] ; then
644 grep 'FAILED with exit code' $CHECKLOG/shell.log >> $LOGFILE && ERROR=6
647 if [ -n "$ERROR" ] ; then
648 log "Error: there was a critical error [${ERROR}] during execution of stage 'fai dirinstall' [$(date)]"
649 eerror "Error: there was a critical error during execution of stage 'fai dirinstall'"
650 eerror "Note: check out ${CHECKLOG}/ for details. [exit ${ERROR}]"
654 log "Finished execution of stage 'fai dirinstall' [$(date)]"
655 einfo "Finished execution of stage 'fai dirinstall'"
658 einfo "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
659 log "Find FAI build logs at $(readlink -f /var/log/fai/$HOSTNAME/last)"
665 # package validator {{{
666 CHECKLOG=/var/log/fai/$HOSTNAME/last
668 if [ -r "$CHECKLOG/package_errors.log" ] && grep -q '[a-z]' "$CHECKLOG/package_errors.log" ; then
670 if [ -n "$EXIT_ON_MISSING_PACKAGES" -a -z "$BUILD_DIRTY" ] ; then
671 eerror "The following packages were requested for installation but could not be processed:"
672 cat $CHECKLOG/package_errors.log
673 eerror "... exiting as requested via \$EXIT_ON_MISSING_PACKAGES."
677 ewarn "The following packages were requested for installation but could not be processed:"
678 cat $CHECKLOG/package_errors.log
684 # BUILD_OUTPUT - execute arch specific stuff and squashfs {{{
685 [ -n "$BUILD_OUTPUT" ] || BUILD_OUTPUT="$OUTPUT/grml_cd"
686 mkdir -p "$BUILD_OUTPUT" || bailout 6 "Problem with creating $BUILD_OUTPUT for stage ARCH"
689 if [ "$ARCH" = i386 ] || [ "$ARCH" = amd64 ] ; then
690 if [ -n "$BOOTSTRAP_ONLY" ] ; then
691 log "Skipping stage 'boot' as building with bootstrap only."
692 ewarn "Skipping stage 'boot' as building with bootstrap only." ; eend 0
694 if [ -d "$BUILD_OUTPUT"/boot/isolinux -a -z "$UPDATE" -a -z "$BUILD_ONLY" ] ; then
695 log "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already."
696 ewarn "Skipping stage 'boot' as $BUILD_OUTPUT/boot/isolinux exists already." ; eend 0
699 [ -d "$BUILD_OUTPUT"/boot/isolinux ] || mkdir -p "$BUILD_OUTPUT"/boot/isolinux
700 [ -d "$BUILD_OUTPUT"/boot/"${SHORT_NAME}" ] || mkdir -p "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"
702 # if we don't have an initrd we a) can't boot and b) there was an error
703 # during build, so check for the file:
704 INITRD="$(ls $CHROOT_OUTPUT/boot/initrd* 2>/dev/null| grep -v '.bak$' | sort -r | head -1)"
705 if [ -n "$INITRD" ] ; then
706 cp $INITRD "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/initrd.gz
707 find $CHROOT_OUTPUT/boot/ -name initrd\*.bak -exec rm {} \;
709 log "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting"
710 eerror "Error: No initrd found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
714 KERNEL_IMAGE="$(ls $CHROOT_OUTPUT/boot/vmlinuz* 2>/dev/null | sort -r | head -1)"
715 if [ -n "$KERNEL_IMAGE" ] ; then
716 cp "$KERNEL_IMAGE" "$BUILD_OUTPUT"/boot/"${SHORT_NAME}"/linux26
718 log "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting"
719 eerror "Error: No kernel found inside $CHROOT_OUTPUT/boot/ - Exiting" ; eend 1
723 [ -n "$TEMPLATE_DIRECTORY" ] || TEMPLATE_DIRECTORY='/usr/share/grml-live/templates'
724 if ! [ -d "${TEMPLATE_DIRECTORY}"/boot ] ; then
725 log "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting."
726 eerror "Error: ${TEMPLATE_DIRECTORY}/boot does not exist. Exiting." ; eend 1
730 # copy _required_ isolinux files
731 for file in ifcpu64.c32 isolinux.bin vesamenu.c32; do
732 copy_addon_file "${file}" /usr/lib/syslinux isolinux
735 # *always* copy files to output directory so the variables
736 # get adjusted according to the build.
737 cp ${TEMPLATE_DIRECTORY}/boot/isolinux/* "$BUILD_OUTPUT"/boot/isolinux/
739 if [ -n "$NO_ADDONS" ] ; then
740 log "Skipping installation of boot addons as requested via \$NO_ADDONS."
741 einfo "Skipping installation of boot addons as requested via \$NO_ADDONS."; eend 0
743 if ! [ -d "$TEMPLATE_DIRECTORY"/boot/addons ] ; then
744 log "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)"
745 ewarn "Boot addons not found, skipping therefore. (Consider installing package grml-live-addons)" ; eend 0
747 # copy addons from system packages or grml-live-compat
748 copy_addon_file ipxe.lkrn /usr/lib/ipxe addons
749 copy_addon_file pci.ids /usr/share/misc addons
750 copy_addon_file memtest86+.bin /boot addons
751 for file in memdisk chain.c32 hdt.c32 menu.c32; do
752 copy_addon_file "${file}" /usr/lib/syslinux addons
755 # make memtest filename FAT16/8.3 compatible
756 mv "${BUILD_OUTPUT}/boot/addons/memtest86+.bin" \
757 "${BUILD_OUTPUT}/boot/addons/memtest"
759 # copy only files so we can handle bsd4grml on its own
760 for file in ${TEMPLATE_DIRECTORY}/boot/addons/* ; do
761 test -f $file && cp $file "$BUILD_OUTPUT"/boot/addons/
764 if [ -n "$NO_ADDONS_BSD4GRML" ] ; then
765 log "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."
766 einfo "Skipping installation of bsd4grml as requested via \$NO_ADDONS_BSD4GRML."; eend 0
768 if [ -d "$TEMPLATE_DIRECTORY"/boot/addons/bsd4grml ] ; then
769 cp -a ${TEMPLATE_DIRECTORY}/boot/addons/bsd4grml "$BUILD_OUTPUT"/boot/addons/
771 log "Missing addon file: bsd4grml"
772 ewarn "Missing addon file: bsd4grml" ; eend 0
776 fi # no "$TEMPLATE_DIRECTORY"/boot/addons
779 if ! [ -d "${BUILD_OUTPUT}/boot/grub" ] ; then
780 mkdir -p "${BUILD_OUTPUT}/boot/grub"
782 cp ${TEMPLATE_DIRECTORY}/boot/grub/* "$BUILD_OUTPUT"/boot/grub/
784 if [ -e ${TEMPLATE_DIRECTORY}/compat/grub/linux.mod ]; then
785 cp "${TEMPLATE_DIRECTORY}"/compat/grub/* "${BUILD_OUTPUT}"/boot/grub/
787 if ! which "grub-mkimage" >/dev/null 2>&1 ; then
788 log "grub-mkimage not found, skipping Grub step therefore." ; eend 0
789 ewarn "grub-mkimage not found, skipping Grub step therefore."
790 ewarn "Please install grub-pc-bin or grub-common >= 1.98+20100804-14." ; eend 0
791 elif ! grub-mkimage --help | grep -q -- --format ; then
792 log "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore." ; eend 0
793 ewarn "grub-mkimage does not support --format=i386-pc, skipping Grub step therefore."
794 ewarn "Please install grub-common >= 1.98+20100804-14 or grub-pc-bin." ; eend 0
796 # copy system grub files if grml-live-compat is not installed
797 cp -a /usr/lib/grub/*-pc/*.mod "${BUILD_OUTPUT}"/boot/grub/
798 cp -a /usr/lib/grub/*-pc/*.o "${BUILD_OUTPUT}"/boot/grub/
799 cp -a /usr/lib/grub/*-pc/*.lst "${BUILD_OUTPUT}"/boot/grub/
800 cp -a /usr/share/grub/ascii.pf2 "${BUILD_OUTPUT}"/boot/grub/
801 grub-mkimage -d /usr/lib/grub/*-pc -o \
802 "${BUILD_OUTPUT}/boot/grub/core.img" biosdisk iso9660 --format=i386-pc
806 if ! [ -d "${TEMPLATE_DIRECTORY}"/GRML ] ; then
807 log "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting."
808 eerror "Error: ${TEMPLATE_DIRECTORY}/GRML does not exist. Exiting." ; eend 1
812 [ -d "$BUILD_OUTPUT"/GRML ] || mkdir "$BUILD_OUTPUT"/GRML
813 cp -a ${TEMPLATE_DIRECTORY}/GRML/* "$BUILD_OUTPUT"/GRML/
815 # adjust boot splash information:
816 RELEASE_INFO="$GRML_NAME $VERSION - Release Codename $RELEASENAME"
817 RELEASE_INFO="$(cut_string 68 "$RELEASE_INFO")"
818 RELEASE_INFO="$(extend_string_end 68 "$RELEASE_INFO")"
820 if [ -r "$BUILD_OUTPUT"/GRML/grml-version ] ; then
821 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/GRML/grml-version
822 sed -i "s/%DATE%/$DATE/" "$BUILD_OUTPUT"/GRML/grml-version
825 # make sure the squashfs filename is set accordingly:
826 SQUASHFS_NAME="$GRML_NAME.squashfs"
828 if [ -n "$NO_BOOTID" ] ; then
829 log 'Skipping bootid feature as requested via $NO_BOOTID.'
830 einfo 'Skipping bootid feature as requested via $NO_BOOTID.'
832 [ -n "$BOOTID" ] || BOOTID="$(echo ${GRML_NAME}${VERSION} | tr -d ',./;\- ')"
833 [ -d "$BUILD_OUTPUT"/conf ] || mkdir "$BUILD_OUTPUT"/conf
834 einfo "Generating /conf/bootid.txt with entry ${BOOTID}."
835 log "Generating /conf/bootid.txt with entry ${BOOTID}."
836 echo "$BOOTID" > "$BUILD_OUTPUT"/conf/bootid.txt
840 # adjust all variables in the templates with the according distribution information
841 for file in "${BUILD_OUTPUT}"/boot/isolinux/*.cfg "${BUILD_OUTPUT}"/boot/isolinux/*.msg \
842 "${BUILD_OUTPUT}"/boot/grub/* ; do
843 if [ -r "${file}" ] ; then
844 sed -i "s/%ARCH%/$ARCH/g" "${file}"
845 sed -i "s/%DATE%/$DATE/g" "${file}"
846 sed -i "s/%DISTRI_INFO%/$DISTRI_INFO/g" "${file}"
847 sed -i "s/%DISTRI_NAME%/$DISTRI_NAME/g" "${file}"
848 sed -i "s/%DISTRI_SPLASH%/$DISTRI_SPLASH/g" "${file}"
849 sed -i "s/%GRML_NAME%/$GRML_NAME/g" "${file}"
850 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/g" "${file}"
851 sed -i "s/%RELEASE_INFO%/$RELEASE_INFO/g" "${file}"
852 sed -i "s/%SHORT_NAME%/$SHORT_NAME/g" "${file}"
853 sed -i "s/%VERSION%/$VERSION/g" "${file}"
855 [ -n "$DEFAULT_BOOTOPTIONS" ] && sed -i "s/ boot=live/ boot=live $DEFAULT_BOOTOPTIONS/" "${file}"
857 if [ -n "$NO_BOOTID" ] ; then
858 sed -i "s/ bootid=%BOOTID%//g" "${file}" # drop bootid bootoption
860 sed -i "s/%BOOTID%/$BOOTID/g" "${file}" # adjust bootid=... argument
865 # adjust bootsplash accordingly but make sure the string has the according lenght
866 SQUASHFS_NAME="$(cut_string 20 "$SQUASHFS_NAME")"
867 SQUASHFS_NAME="$(extend_string_end 20 "$SQUASHFS_NAME")"
868 for file in f4 f5 ; do
869 if [ -r "${BUILD_OUTPUT}/boot/isolinux/${file}" ] ; then
870 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
871 sed -i "s/%SQUASHFS_NAME%/$SQUASHFS_NAME/" "${BUILD_OUTPUT}/boot/isolinux/${file}"
875 # generate addon list
876 rm -f "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
877 for name in "${BUILD_OUTPUT}"/boot/isolinux/addon_*.cfg ; do
878 include_name=$(basename "$name")
879 echo "include $include_name" >> "${BUILD_OUTPUT}/${ADDONS_LIST_FILE}"
882 if ! [ -r "${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg" ] || [ "$DISTRI_NAME" = "grml" ] ; then
883 log "including grmlmain.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
884 echo "include grmlmain.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
885 echo "include default.cfg" > "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
886 echo "include menuoptions.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
887 echo "include grml.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
889 for f in "${BUILD_OUTPUT}"/boot/isolinux/submenu*.cfg ; do
890 echo "include $(basename $f)" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
893 echo "include options.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
894 if [ ! -n "$NO_ADDONS" ] ; then
895 echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
897 echo "include isoprompt.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
898 echo "include hd.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
899 echo "include hidden.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/grmlmain.cfg"
900 else # assume we are building a custom distribution:
901 log "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
902 einfo "File ${BUILD_OUTPUT}/boot/isolinux/${DISTRI_NAME}.cfg found, using it."
903 if grep -q "^include ${DISTRI_NAME}.cfg" "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
904 log "include for ${DISTRI_NAME}.cfg already present, nothing to do."
906 einfo "include for ${DISTRI_NAME}.cfg already present, nothing to do."
910 log "including ${DISTRI_NAME}.cfg in ${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
911 echo "include ${DISTRI_NAME}.cfg" > "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
912 [ -n "$NO_ADDONS" ] || echo "include addons.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/distri.cfg"
916 # use old style console based isolinux method only if requested:
917 if [[ "${ISOLINUX_METHOD}" == "console" ]] ; then
918 log 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
919 einfo 'Using console based isolinux method as requested via $ISOLINUX_METHOD.'
920 if grep -q '^include console.cfg' "${BUILD_OUTPUT}/boot/isolinux/distri.cfg" ; then
921 einfo "include for console.cfg already found, nothing to do."
924 log "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
925 einfo "including console.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
926 echo "include console.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
930 log 'Using graphical boot menu.'
931 if grep -q '^include vesamenu.cfg' "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg" ; then
932 log "include for vesamenu.cfg already found, nothing to do."
934 log "including vesamenu.cfg in ${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
935 echo "include vesamenu.cfg" >> "${BUILD_OUTPUT}/boot/isolinux/isolinux.cfg"
939 if [ -e "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6 ]; then
940 sed -i "s/%RELEASE_INFO%/$GRML_NAME $VERSION - $RELEASENAME/" "$BUILD_OUTPUT"/boot/addons/bsd4grml/boot.6
943 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot
944 if ! [ -r "$DPKG_LIST" ] ; then
945 ewarn "$DPKG_LIST could not be read, ignoring to store package information on ISO therefore."
947 einfo "Storing package list information as /GRML/${GRML_NAME}-packages.txt on ISO."
948 cp "$DPKG_LIST" "${BUILD_OUTPUT}/GRML/${GRML_NAME}-packages.txt"
952 # autostart for Windows:
953 if [ -d "${TEMPLATE_DIRECTORY}/windows/autostart/" ] ; then
954 cp ${TEMPLATE_DIRECTORY}/windows/autostart/* "$BUILD_OUTPUT"/
957 FORCE_ISO_REBUILD=true
958 einfo "Finished execution of stage 'boot'" ; eend 0
962 log 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!'
963 eerror 'Error: Unsupported ARCH, sorry. Want to support it? Contribute!' ; eend 1
967 # support installation of local files into the chroot/ISO
968 if [ -n "$CHROOT_INSTALL" ] ; then
969 if ! [ -d "$CHROOT_INSTALL" ] ; then
970 log "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
971 ewarn "Configuration variable \$CHROOT_INSTALL is set but not a directory; ignoring"
973 log "Copying local files to chroot as requested via \$CHROOT_INSTALL"
974 einfo "Copying local files to chroot as requested via \$CHROOT_INSTALL"
975 rsync -avz --inplace "$CHROOT_INSTALL"/ "$CHROOT_OUTPUT/"
977 einfo "Make sure to run squashfs stage, otherwise your local files won't be part of the ISO."
978 FORCE_ISO_REBUILD=true
982 if [ -f "$BUILD_OUTPUT"/live/${GRML_NAME}.squashfs -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" ] ; then
983 log "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already."
984 ewarn "Skipping stage 'squashfs' as $BUILD_OUTPUT/live exists already." ; eend 0
985 elif [ -n "$SKIP_MKSQUASHFS" ] ; then
986 log "Skipping stage 'squashfs' as requested via option -q or -N"
987 ewarn "Skipping stage 'squashfs' as requested via option -q or -N" ; eend 0
989 [ -d "$BUILD_OUTPUT"/live ] || mkdir "$BUILD_OUTPUT"/live
990 # make sure we don't leave (even an empty) base.tgz:
991 [ -f "$CHROOT_OUTPUT/base.tgz" ] && rm -f "$CHROOT_OUTPUT/base.tgz"
993 # if unconfigured default to squashfs-tools' mksquashfs binary
994 if [ -z "$SQUASHFS_BINARY" ] ; then
995 SQUASHFS_BINARY='mksquashfs'
998 if which "$SQUASHFS_BINARY" >/dev/null 2>&1 ; then
999 log "Using mksquashfs binary ${SQUASHFS_BINARY}"
1000 einfo "Using mksquashfs binary ${SQUASHFS_BINARY}" ; eend 0
1002 log "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting."
1003 eerror "Error: mksquashfs binary ($SQUASHFS_BINARY) not found. Exiting." ; eend 1
1007 # use sane defaults if $SQUASHFS_OPTIONS isn't set
1008 if [ -z "$SQUASHFS_OPTIONS" ] ; then
1009 # use blocksize 256k as this gives best result with regards to time + compression
1010 SQUASHFS_OPTIONS="-b 256k"
1012 # set lzma/xz compression by default, unless -z option has been specified on command line
1013 if [ -z "$SQUASHFS_ZLIB" ] ; then
1014 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp xz"
1016 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -comp gzip"
1020 # support exclusion of files via exclude-file:
1021 if [ -n "$SQUASHFS_EXCLUDES_FILE" -a "$SQUASHFS_EXCLUDES_FILE" ] ; then
1022 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -ef $SQUASHFS_EXCLUDES_FILE -wildcards"
1025 # get rid of unnecessary files when building grml-small for final release:
1026 if echo "$CLASSES" | grep -q GRML_SMALL ; then
1027 SQUASHFS_OPTIONS="$SQUASHFS_OPTIONS -e initrd.img* vmlinuz*"
1031 SQUASHFS_STDERR="$(mktemp -t grml-live.XXXXXX)"
1033 # informational stuff
1034 [ -n "$SQUASHFS_OPTIONS" ] && SQUASHFS_INFO_MSG="$SQUASHFS_OPTIONS"
1035 [ -n "$SQUASHFS_INFO_MSG" ] && SQUASHFS_INFO_MSG="using options: $SQUASHFS_INFO_MSG"
1036 einfo "Squashfs build information: running binary $SQUASHFS_BINARY $SQUASHFS_INFO_MSG"
1038 log "$SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/${GRML_NAME}.squashfs -noappend $SQUASHFS_OPTIONS"
1040 if $SQUASHFS_BINARY $CHROOT_OUTPUT/ $BUILD_OUTPUT/live/"${GRML_NAME}".squashfs \
1041 -noappend $SQUASHFS_OPTIONS 2>"${SQUASHFS_STDERR}" ; then
1042 echo "${GRML_NAME}.squashfs" > $BUILD_OUTPUT/live/filesystem.module
1043 log "Finished execution of stage 'squashfs' [$(date)]"
1044 einfo "Finished execution of stage 'squashfs'" ; eend 0
1046 log "Error: there was a critical error executing stage 'squashfs' [$(date)]:"
1047 log "$(cat $SQUASHFS_STDERR)"
1048 eerror "Error: there was a critical error executing stage 'squashfs':"
1049 cat "${SQUASHFS_STDERR}"
1054 FORCE_ISO_REBUILD=true
1057 # create md5sum file:
1058 if [ -z "$BOOTSTRAP_ONLY" ] ; then
1059 ( cd $BUILD_OUTPUT/GRML &&
1060 find .. -type f -not -name md5sums -not -name isolinux.bin -exec md5sum {} \; > md5sums )
1064 # ISO_OUTPUT - mkisofs {{{
1065 [ -n "$ISO_OUTPUT" ] || ISO_OUTPUT="$OUTPUT/grml_isos"
1066 [ -n "$ISO_NAME" ] || ISO_NAME="${GRML_NAME}_${VERSION}.iso"
1068 if [ "$BOOT_METHOD" = "isolinux" ] ; then
1069 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -boot-info-table -b boot/isolinux/isolinux.bin -c boot/isolinux/boot.cat"
1070 elif [ "$BOOT_METHOD" = "grub2" ] ; then
1071 BOOT_ARGS="-no-emul-boot -boot-load-size 4 -b boot/grub/toriboot.bin"
1074 # Just until http://bts.grml.org/grml/issue945 has been resolved.
1075 # HYBRID_METHOD defaults to manifold, so make sure the default works OOTB.
1076 if [[ $BOOT_METHOD != isolinux && ($HYBRID_METHOD = isohybrid || $HYBRID_METHOD = manifold) ]]; then
1077 log "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1078 ewarn "Setting HYBRID_METHOD to grub2 as hybrid mode does not work with isohybrid yet."
1079 HYBRID_METHOD='grub2'
1083 if [ -f "${ISO_OUTPUT}/${ISO_NAME}" -a -z "$UPDATE" -a -z "$BUILD_ONLY" -a -z "$BUILD_DIRTY" -a "$FORCE_ISO_REBUILD" = "false" ] ; then
1084 log "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already."
1085 ewarn "Skipping stage 'iso build' as $ISO_OUTPUT/${ISO_NAME} exists already." ; eend 0
1086 elif [ -n "$SKIP_MKISOFS" ] ; then
1087 log "Skipping stage 'iso build' as requested via option -n or -N"
1088 ewarn "Skipping stage 'iso build' as requested via option -n or -N" ; eend 0
1090 mkdir -p "$ISO_OUTPUT" || bailout 6 "Problem with creating $ISO_OUTPUT for stage 'iso build'"
1092 if $FORCE_ISO_REBUILD && ! [ -f "${ISO_OUTPUT}/${ISO_NAME}" ] ; then
1093 log "Forcing rebuild of ISO because files on ISO have been modified."
1094 einfo "Forcing rebuild of ISO because files on ISO have been modified."
1097 # support mkisofs as well as genisoimage
1098 if which mkisofs >/dev/null 2>&1; then
1100 elif which genisoimage >/dev/null 2>&1; then
1101 MKISOFS='genisoimage'
1103 log "Error: neither mkisofs nor genisoimage available - can not create ISO."
1104 eerror "Error: neither mkisofs nor genisoimage available - can not create ISO." ; eend 1
1109 if cd "$BUILD_OUTPUT" ; then
1110 if [ "$BOOT_METHOD" = "grub2" ]; then
1111 # make a 2048-byte bootsector for El Torito
1112 dd if=/dev/zero of=boot/grub/toriboot.bin bs=512 count=4 2>/dev/null
1113 # those are in 2048-byte sectors, so 1 16 matches 4 63 below
1114 echo 1 16 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -B 11 | \
1115 dd of=boot/grub/toriboot.bin conv=notrunc 2>/dev/null
1117 log "$MKISOFS -V '${GRML_NAME} ${VERSION}' -publisher 'grml-live | grml.org' -l -r -J $BOOT_ARGS -o ${ISO_OUTPUT}/${ISO_NAME} ."
1118 "$MKISOFS" -V "${GRML_NAME} ${VERSION}" -publisher 'grml-live | grml.org' \
1119 -l -r -J $BOOT_ARGS -no-pad \
1120 -o "${ISO_OUTPUT}/${ISO_NAME}" . ; RC=$?
1121 # both of these need core.img there, so it’s easier to write it here
1122 if [ "$BOOT_METHOD" = "grub2" ] || [ "$HYBRID_METHOD" = "grub2" ]; then
1123 # must be <= 30720 bytes
1124 dd if=boot/grub/core.img of="${ISO_OUTPUT}/${ISO_NAME}" \
1125 conv=notrunc bs=512 seek=4 2>/dev/null
1128 # pad the output ISO to multiples of 256 KiB for partition table support
1129 siz=$($getfilesize "${ISO_OUTPUT}/${ISO_NAME}")
1130 cyls=$((siz / 512 / 32 / 16 + 1)) # C=$cyls H=16 S=32
1131 siz=$((cyls * 16 * 32 * 512)) # size after padding
1132 dd if=/dev/zero bs=1 count=1 seek=$((siz - 1)) \
1133 of="${ISO_OUTPUT}/${ISO_NAME}" 2>/dev/null
1135 # support disabling hybrid ISO image
1136 if [ "$HYBRID_METHOD" = "disable" ] ; then\
1137 log "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1138 einfo "Skipping creation of hybrid ISO file as requested via HYBRID_METHOD=disable"
1140 # use isohybrid only on request
1141 elif [ "$HYBRID_METHOD" = "isohybrid" ] ; then
1142 if ! which isohybrid >/dev/null 2>&1 ; then
1143 bailout 12 "isohybrid binary not found - please install syslinux/syslinux-common"
1145 log "Creating hybrid ISO file with isohybrid method"
1146 einfo "Creating hybrid ISO file with isohybrid method"
1147 # Notes for consideration:
1148 # "-entry 4 -type 1c"
1149 # * using 4 as the partition number is supposed to help with BIOSes
1150 # that only support USB-Zip boot
1151 # * using 1c (i.e. hidden FAT32 LBA), instead of the default 0x17
1152 # (hidden NTFS, IIRC), as the partition type is sometimes needed
1153 # to get the BIOS even look at the partition created by isohybrid
1154 isohybrid "${ISO_OUTPUT}/${ISO_NAME}"
1157 # by default use our manifold boot method:
1159 # isoinfo is part of both mkisofs and genisoimage so we're good
1160 bootoff=$(isoinfo -l -i "${ISO_OUTPUT}/${ISO_NAME}" | \
1161 sed -n '/^.*\[ *\([0-9]*\)[] ].* ISOLINUX.BIN;1 *$/s//\1/p')
1162 if ! [ -r boot/grub/core.img ] ; then
1163 ewarn "boot/grub/core.img not found, not creating manifold boot ISO file"
1164 elif [ "${bootoff:-0}" -lt 1 ] ; then
1165 ewarn "isolinux.bin not found on the ISO file, disabling manifold boot"
1167 log "Creating hybrid ISO file with manifold method"
1168 einfo "Creating hybrid ISO file with manifold method"
1169 if [ "$HYBRID_METHOD" = "grub2" ] ; then
1170 # 512 bytes: MBR, partition table, load GRUB 2
1171 echo 4 63 | mksh /usr/share/grml-live/scripts/bootgrub.mksh -A -M 4:0x96 -g $cyls:16:32
1173 # read only one but 2048-byte sized (scale: << 2) sector
1174 echo $bootoff $bootoff | \
1175 mksh /usr/share/grml-live/scripts/bootilnx.mksh -A -M 4:0x96 -g $cyls:16:32 -S 2
1176 fi | dd of="${ISO_OUTPUT}/${ISO_NAME}" conv=notrunc 2>/dev/null
1181 # generate md5sum and sha1sum of ISO if we are using class 'RELEASE':
1182 case $CLASSES in *RELEASE*)
1185 if cd $ISO_OUTPUT ; then
1186 md5sum ${ISO_NAME} > ${ISO_NAME}.md5 && \
1187 touch -r ${ISO_NAME} ${ISO_NAME}.md5
1188 sha1sum ${ISO_NAME} > ${ISO_NAME}.sha1 && \
1189 touch -r ${ISO_NAME} ${ISO_NAME}.sha1
1198 if [ "$RC" = 0 ] ; then
1199 log "Finished execution of stage 'iso build' [$(date)]"
1200 einfo "Finished execution of stage 'iso build'" ; eend 0
1202 log "Error: there was a critical error ($RC) executing stage 'iso build' [$(date)]"
1203 eerror "Error: there was a critical error executing stage 'iso build'" ; eend 1
1209 # log build information to database if grml-live-db is installed and enabled {{{
1211 if [ -d /usr/share/grml-live-db ] ; then
1214 DPKG_LIST="/var/log/fai/$HOSTNAME/last/dpkg.list" # the dpkg --list output of the chroot:
1215 [ -n "$DPKG_DATABASE" ] || DPKG_DATABASE=/var/log/grml-live.db
1216 [ -n "$DPKG_DBSCRIPT" ] || DPKG_DBSCRIPT=/usr/share/grml-live-db/scripts/dpkg-to-db
1217 [ -n "$DPKG_DBOPTIONS" ] || DPKG_DBOPTIONS="--database $DPKG_DATABASE --logfile $LOGFILE --flavour $GRML_NAME --dpkg $DPKG_LIST"
1219 if ! [ -x "$DPKG_DBSCRIPT" ] ; then
1220 log "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information."
1221 eerror "Error: $DPKG_DBSCRIPT is not executable, can not log dpkg information." ; eend 1
1225 # disable by default for now, not sure whether really everyone is using a local db file
1226 #if ! touch "$DPKG_DATABASE" ; then
1227 # eerror "Error: can not write to ${DPKG_DATABASE}, can not log dpkg information." ; eend 1
1231 if ! [ -r "$DPKG_LIST" ] ; then
1232 log "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)"
1233 ewarn "Warning: can not read $DPKG_LIST - can not provide information to $DPKG_DBSCRIPT (dirty build?)" ; eend 0
1235 einfo "Logging $DPKG_LIST to database $DPKG_DATABASE"
1236 log "Logging $DPKG_LIST to database $DPKG_DATABASE"
1237 log "Executing $DPKG_DBSCRIPT $DPKG_DBOPTIONS"
1240 if DB_INFO=$("$DPKG_DBSCRIPT" $DPKG_DBOPTIONS 2>&1) ; then
1256 [ -n "$start_seconds" ] && SECONDS="$[$(cut -d . -f 1 /proc/uptime)-$start_seconds]" || SECONDS="unknown"
1257 log "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]"
1259 dpkg_to_db # make sure we catch the last log line as well, therefore execute between log + einfo
1261 einfo "Successfully finished execution of $PN [$(date) - running ${SECONDS} seconds]" ; eend 0
1265 ## END OF FILE #################################################################
1266 # vim:foldmethod=marker ts=2 ft=sh ai expandtab tw=80 sw=2